diff --git a/DEPS b/DEPS
index 8583baf..197d794 100644
--- a/DEPS
+++ b/DEPS
@@ -79,11 +79,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '3da15bb1c813d7a3c563c372fbfb3931e5b6c27c',
+  'skia_revision': '44804c030bc2313966388f53dbf4db9166984d0a',
   # 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': 'daa444e4ac13f5ab5d371ee5d796b593c1286279',
+  'v8_revision': 'd8c2020efae83cf0737b9d08ebd062b4d0e95679',
   # 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.
@@ -91,7 +91,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '379681336ba11f33b95b337b7fa324e6336a780e',
+  'angle_revision': 'c081020c7aace0e63bd8ae2f067f2ac8e8e36fbe',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -103,7 +103,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '003e96c7c3e15afd2969d33bc91ca459bb73a3b5',
+  'pdfium_revision': '701d21682af1aa3f7f449d2da9681ee01dc8990d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -135,7 +135,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '20b4aa3deae83d8f689859aebd27601056403c82',
+  'catapult_revision': 'c3373753de40a505241481ad2e74e2746f21551f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -323,7 +323,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '5c8aa4d8a30e89added6423a242360225661c554',
+      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '55af1ecf95886bd60661dd7c62a9e32ec364afc1',
       'condition': 'checkout_linux',
   },
 
@@ -632,7 +632,7 @@
 
   # Wayland protocols that add functionality not available in the core protocol.
   'src/third_party/wayland-protocols/src': {
-      'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/wayland-protocols.git' + '@' + '26c99346ab5f2273fe5581bc4f6397bbb834f747',
+      'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/wayland-protocols.git' + '@' + '4f789286e4ab7f6fecc2ccb895d79362a9b2382a',
       'condition': 'checkout_linux',
   },
 
@@ -649,7 +649,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '5864639a46501501c9f7fe8a22ae485886a9965f', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '8ed653d1c4ea94a6f4b0d0d4114f3f0b0de251d1', # commit position 21742
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index cc0c44a2..31f71c6 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -491,6 +491,7 @@
     # Please keep sorted.
     'OS_AIX',
     'OS_ANDROID',
+    'OS_ASMJS',
     'OS_BSD',
     'OS_CAT',       # For testing.
     'OS_CHROMEOS',
@@ -521,7 +522,6 @@
 
 
 _GENERIC_PYDEPS_FILES = [
-    'chrome/test/chromedriver/test/run_py_tests.pydeps',
 ]
 
 
@@ -2082,9 +2082,9 @@
 
 def _CheckPydepsNeedsUpdating(input_api, output_api, checker_for_tests=None):
   """Checks if a .pydeps file needs to be regenerated."""
-  # This check is for Python dependency lists (.pydeps files), and involves
-  # paths not only in the PRESUBMIT.py, but also in the .pydeps files. It
-  # doesn't work on Windows and Mac, so skip it on other platforms.
+  # This check is mainly for Android, and involves paths not only in the
+  # PRESUBMIT.py, but also in the .pydeps files. It doesn't work on Windows and
+  # Mac, so skip it on other platforms.
   if input_api.platform != 'linux2':
     return []
   # TODO(agrieve): Update when there's a better way to detect
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 13c7451..54f07e4c 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -615,6 +615,8 @@
     "browser/surfaces_instance.cc",
     "browser/surfaces_instance.h",
     "browser/token_binding_manager_bridge.cc",
+    "browser/tracing/aw_trace_event_args_whitelist.cc",
+    "browser/tracing/aw_trace_event_args_whitelist.h",
     "browser/tracing/aw_tracing_controller.cc",
     "browser/tracing/aw_tracing_controller.h",
     "browser/tracing/aw_tracing_delegate.cc",
diff --git a/android_webview/browser/tracing/aw_trace_event_args_whitelist.cc b/android_webview/browser/tracing/aw_trace_event_args_whitelist.cc
new file mode 100644
index 0000000..4436ce6
--- /dev/null
+++ b/android_webview/browser/tracing/aw_trace_event_args_whitelist.cc
@@ -0,0 +1,74 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "android_webview/browser/tracing/aw_trace_event_args_whitelist.h"
+
+#include "base/bind.h"
+#include "base/strings/pattern.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
+
+namespace {
+
+struct WhitelistEntry {
+  const char* category_name;
+  const char* event_name;
+  const char* const* arg_name_filter;
+};
+
+const WhitelistEntry kEventArgsWhitelist[] = {
+    {"__metadata", "thread_name", nullptr},
+    {"__metadata", "process_name", nullptr},
+    {"__metadata", "process_uptime_seconds", nullptr},
+    {"__metadata", "stackFrames", nullptr},
+    {"__metadata", "typeNames", nullptr},
+    {nullptr, nullptr, nullptr}};
+
+}  // namespace
+
+namespace android_webview {
+
+// TODO(timvolodine): refactor this into base/ to avoid code duplication
+// with chrome/common/trace_event_args_whitelist.cc, see crbug.com/805045.
+bool IsTraceArgumentNameWhitelisted(const char* const* granular_filter,
+                                    const char* arg_name) {
+  for (int i = 0; granular_filter[i] != nullptr; ++i) {
+    if (base::MatchPattern(arg_name, granular_filter[i]))
+      return true;
+  }
+
+  return false;
+}
+
+bool IsTraceEventArgsWhitelisted(
+    const char* category_group_name,
+    const char* event_name,
+    base::trace_event::ArgumentNameFilterPredicate* arg_name_filter) {
+  DCHECK(arg_name_filter);
+  base::CStringTokenizer category_group_tokens(
+      category_group_name, category_group_name + strlen(category_group_name),
+      ",");
+  while (category_group_tokens.GetNext()) {
+    const std::string& category_group_token = category_group_tokens.token();
+    for (int i = 0; kEventArgsWhitelist[i].category_name != nullptr; ++i) {
+      const WhitelistEntry& whitelist_entry = kEventArgsWhitelist[i];
+      DCHECK(whitelist_entry.event_name);
+
+      if (base::MatchPattern(category_group_token,
+                             whitelist_entry.category_name) &&
+          base::MatchPattern(event_name, whitelist_entry.event_name)) {
+        if (whitelist_entry.arg_name_filter) {
+          *arg_name_filter = base::Bind(&IsTraceArgumentNameWhitelisted,
+                                        whitelist_entry.arg_name_filter);
+        }
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/tracing/aw_trace_event_args_whitelist.h b/android_webview/browser/tracing/aw_trace_event_args_whitelist.h
new file mode 100644
index 0000000..e5dc071e
--- /dev/null
+++ b/android_webview/browser/tracing/aw_trace_event_args_whitelist.h
@@ -0,0 +1,21 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ANDROID_WEBVIEW_BROWSER_TRACING_AW_TRACE_EVENT_ARGS_WHITELIST_H_
+#define ANDROID_WEBVIEW_BROWSER_TRACING_AW_TRACE_EVENT_ARGS_WHITELIST_H_
+
+#include "base/trace_event/trace_event_impl.h"
+
+namespace android_webview {
+
+// Used to filter trace event arguments against a whitelist of events that
+// have been manually vetted to not include any PII.
+bool IsTraceEventArgsWhitelisted(
+    const char* category_group_name,
+    const char* event_name,
+    base::trace_event::ArgumentNameFilterPredicate* arg_name_filter);
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_TRACING_AW_TRACE_EVENT_ARGS_WHITELIST_H_
diff --git a/android_webview/browser/tracing/aw_tracing_controller.cc b/android_webview/browser/tracing/aw_tracing_controller.cc
index 8184684..74aa5ff 100644
--- a/android_webview/browser/tracing/aw_tracing_controller.cc
+++ b/android_webview/browser/tracing/aw_tracing_controller.cc
@@ -91,6 +91,8 @@
       base::android::ConvertJavaStringToUTF8(env, jcategories);
   base::trace_event::TraceConfig trace_config(
       categories, static_cast<base::trace_event::TraceRecordMode>(jmode));
+  // Required for filtering out potential PII.
+  trace_config.EnableArgumentFilter();
   return content::TracingController::GetInstance()->StartTracing(
       trace_config, content::TracingController::StartTracingDoneCallback());
 }
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 820f6e39..574d297 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -12,6 +12,7 @@
 #include "android_webview/browser/browser_view_renderer.h"
 #include "android_webview/browser/command_line_helper.h"
 #include "android_webview/browser/deferred_gpu_command_service.h"
+#include "android_webview/browser/tracing/aw_trace_event_args_whitelist.h"
 #include "android_webview/common/aw_descriptors.h"
 #include "android_webview/common/aw_paths.h"
 #include "android_webview/common/aw_switches.h"
@@ -161,6 +162,11 @@
   safe_browsing::SafeBrowsingApiHandler::SetInstance(
       safe_browsing_api_handler_.get());
 
+  // Used only if the argument filter is enabled in tracing config,
+  // as is the case by default in aw_tracing_controller.cc
+  base::trace_event::TraceLog::GetInstance()->SetArgumentFilterPredicate(
+      base::Bind(&IsTraceEventArgsWhitelisted));
+
   return false;
 }
 
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc
index 55c8c327..4344e7f 100644
--- a/ash/shelf/shelf_controller.cc
+++ b/ash/shelf/shelf_controller.cc
@@ -390,10 +390,10 @@
   message_center::Notification* notification =
       message_center::MessageCenter::Get()->FindVisibleNotificationById(
           notification_id);
-  // If the notification is for an ARC app, return early.
+
   // TODO(newcomer): Support ARC app notifications.
-  if (notification->notifier_id().type !=
-      message_center::NotifierId::APPLICATION)
+  if (!notification || notification->notifier_id().type !=
+                           message_center::NotifierId::APPLICATION)
     return;
 
   model_.AddNotificationRecord(notification->notifier_id().id, notification_id);
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc
index 611d502..a2e1f956 100644
--- a/ash/system/tray/system_tray_unittest.cc
+++ b/ash/system/tray/system_tray_unittest.cc
@@ -32,6 +32,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
+#include "ui/app_list/presenter/app_list.h"
+#include "ui/app_list/presenter/test/test_app_list_presenter.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/events/test/event_generator.h"
@@ -410,6 +412,39 @@
   EXPECT_TRUE(system_tray->HasSystemBubble());
 }
 
+// Tests that press the search key can toggle the launcher when all the windows
+// are minimized after open the system tray bubble in tablet mode.
+TEST_F(SystemTrayTest, ToggleAppListAfterOpenSystemTrayBubbleInTabletMode) {
+  EXPECT_FALSE(wm::GetActiveWindow());
+  SystemTray* system_tray = GetPrimarySystemTray();
+
+  // Open the system tray bubble in tablet mode.
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  EXPECT_FALSE(system_tray->clipping_window_for_test());
+  system_tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
+  ASSERT_FALSE(system_tray->drag_controller());
+  EXPECT_FALSE(system_tray->clipping_window_for_test());
+
+  app_list::test::TestAppListPresenter test_app_list_presenter;
+  Shell::Get()->app_list()->SetAppListPresenter(
+      test_app_list_presenter.CreateInterfacePtrAndBind());
+
+  // Convert from tablet mode to clamshell.
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  EXPECT_EQ(0u, test_app_list_presenter.toggle_count());
+
+  // Press the search key should toggle the launcher.
+  ui::test::EventGenerator& generator = GetEventGenerator();
+  generator.PressKey(ui::VKEY_BROWSER_SEARCH, ui::EF_NONE);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(1u, test_app_list_presenter.toggle_count());
+
+  // Press the search key again should still toggle the launcher.
+  generator.PressKey(ui::VKEY_BROWSER_SEARCH, ui::EF_NONE);
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(2u, test_app_list_presenter.toggle_count());
+}
+
 // Verifies only the visible default views are recorded in the
 // "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
 TEST_F(SystemTrayTest, OnlyVisibleItemsRecorded) {
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index acc0811..c3f7110 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -487,10 +487,12 @@
       kShellWindowId_SettingBubbleContainer);
 
   // Place the bubble in |container|, or in a window clipped to the work area
-  // in maximize mode, to avoid tray bubble and shelf overlap.
+  // in maximize mode, to avoid tray bubble and shelf overlap when dragging the
+  // bubble from the tray.
   if (Shell::Get()
           ->tablet_mode_controller()
-          ->IsTabletModeWindowManagerEnabled()) {
+          ->IsTabletModeWindowManagerEnabled() &&
+      drag_controller()) {
     if (!clipping_window_.get()) {
       clipping_window_ = std::make_unique<aura::Window>(nullptr);
       clipping_window_->Init(ui::LAYER_NOT_DRAWN);
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index 8e61e27..e293b8d3 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -132,6 +132,12 @@
   // based on background insets returned from GetBackgroundInsets().
   gfx::Rect GetBackgroundBounds() const;
 
+  aura::Window* clipping_window_for_test() const {
+    return clipping_window_.get();
+  }
+
+  TrayDragController* drag_controller() { return drag_controller_.get(); }
+
  protected:
   // ActionableView:
   std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
@@ -141,7 +147,6 @@
                                  const ui::Event& event) override;
   views::PaintInfo::ScaleType GetPaintScaleType() const override;
 
-  TrayDragController* drag_controller() { return drag_controller_.get(); }
   void set_drag_controller(
       std::unique_ptr<TrayDragController> drag_controller) {
     drag_controller_ = std::move(drag_controller);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 36802f1..f9a7d8c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1787,10 +1787,14 @@
 buildflag_header("anchor_functions_flags") {
   header = "anchor_functions_flags.h"
   header_dir = "base/android/library_loader"
+  _supports_code_ordering = current_cpu == "arm"
 
   # buildflag entries added to this header must also must be manually added to
   # tools/gn/bootstrap/bootstrap.py
-  flags = [ "USE_LLD=$use_lld" ]
+  flags = [
+    "USE_LLD=$use_lld",
+    "SUPPORTS_CODE_ORDERING=$_supports_code_ordering",
+  ]
 }
 
 # This is the subset of files from base that should not be used with a dynamic
diff --git a/base/android/library_loader/anchor_functions.cc b/base/android/library_loader/anchor_functions.cc
index 5d052593..72630e1 100644
--- a/base/android/library_loader/anchor_functions.cc
+++ b/base/android/library_loader/anchor_functions.cc
@@ -4,13 +4,11 @@
 
 #include "base/android/library_loader/anchor_functions.h"
 
-#include "base/android/library_loader/anchor_functions_flags.h"
 #include "base/logging.h"
 #include "build/build_config.h"
 
-// asm() macros below don't compile on x86, and haven't been validated outside
-// ARM.
-#if defined(ARCH_CPU_ARMEL)
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
+
 // These functions are here to, respectively:
 // 1. Check that functions are ordered
 // 2. Delimit the start of .text
@@ -68,20 +66,18 @@
 const size_t kEndOfText =
     reinterpret_cast<size_t>(dummy_function_at_the_end_of_text);
 
-void CheckOrderingSanity() {
+bool IsOrderingSane() {
+  size_t dummy = reinterpret_cast<size_t>(&dummy_function_to_check_ordering);
+  size_t here = reinterpret_cast<size_t>(&IsOrderingSane);
   // The linker usually keeps the input file ordering for symbols.
   // dummy_function_to_anchor_text() should then be after
   // dummy_function_to_check_ordering() without ordering.
   // This check is thus intended to catch the lack of ordering.
-  CHECK_LT(kStartOfText,
-           reinterpret_cast<size_t>(&dummy_function_to_check_ordering));
-  CHECK_LT(kStartOfText, kEndOfText);
-  CHECK_LT(kStartOfText,
-           reinterpret_cast<size_t>(&dummy_function_to_check_ordering));
-  CHECK_LT(kStartOfText, reinterpret_cast<size_t>(&CheckOrderingSanity));
-  CHECK_GT(kEndOfText, reinterpret_cast<size_t>(&CheckOrderingSanity));
+  return kStartOfText < dummy && dummy < kEndOfText && kStartOfText < here &&
+         here < kEndOfText;
 }
 
 }  // namespace android
 }  // namespace base
-#endif  // defined(ARCH_CPU_ARMEL)
+
+#endif  // BUILDFLAG(SUPPORTS_CODE_ORDERING)
diff --git a/base/android/library_loader/anchor_functions.h b/base/android/library_loader/anchor_functions.h
index 45f771a04..44ae92ef 100644
--- a/base/android/library_loader/anchor_functions.h
+++ b/base/android/library_loader/anchor_functions.h
@@ -6,11 +6,12 @@
 #define BASE_ANDROID_LIBRARY_LOADER_ANCHOR_FUNCTIONS_H_
 
 #include <cstdint>
+#include "base/android/library_loader/anchor_functions_flags.h"
 
 #include "base/base_export.h"
-#include "build/build_config.h"
 
-#if defined(ARCH_CPU_ARMEL)
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
+
 namespace base {
 namespace android {
 
@@ -18,11 +19,11 @@
 BASE_EXPORT extern const size_t kStartOfText;
 BASE_EXPORT extern const size_t kEndOfText;
 
-// Basic CHECK()s ensuring that the symbols above are correctly set.
-BASE_EXPORT void CheckOrderingSanity();
+// Returns true if the ordering looks sane.
+BASE_EXPORT bool IsOrderingSane();
 
 }  // namespace android
 }  // namespace base
-#endif  // defined(ARCH_CPU_ARMEL)
+#endif  // BUILDFLAG(SUPPORTS_CODE_ORDERING)
 
 #endif  // BASE_ANDROID_LIBRARY_LOADER_ANCHOR_FUNCTIONS_H_
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
index 4e5828fa..f0bb8327e 100644
--- a/base/android/library_loader/library_loader_hooks.cc
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -5,6 +5,7 @@
 #include "base/android/library_loader/library_loader_hooks.h"
 
 #include "base/android/jni_string.h"
+#include "base/android/library_loader/anchor_functions_flags.h"
 #include "base/android/library_loader/library_load_from_apk_status_codes.h"
 #include "base/android/library_loader/library_prefetcher.h"
 #include "base/at_exit.h"
@@ -169,7 +170,12 @@
     const JavaParamRef<jobject>& jcaller) {
   if (CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kMadviseRandomExecutableCode)) {
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
     NativeLibraryPrefetcher::MadviseRandomText();
+#else
+    LOG(WARNING) << switches::kMadviseRandomExecutableCode
+                 << " is not supported on this architecture.";
+#endif
   }
 
   if (g_native_initialization_hook && !g_native_initialization_hook())
@@ -189,19 +195,31 @@
 static jboolean JNI_LibraryLoader_ForkAndPrefetchNativeLibrary(
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz) {
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
   return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
+#else
+  return false;
+#endif
 }
 
 static jint JNI_LibraryLoader_PercentageOfResidentNativeLibraryCode(
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz) {
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
   return NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode();
+#else
+  return -1;
+#endif
 }
 
 static void JNI_LibraryLoader_PeriodicallyCollectResidency(
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz) {
-  return NativeLibraryPrefetcher::PeriodicallyCollectResidency();
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
+  NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode();
+#else
+  LOG(WARNING) << "Collecting residency is not supported.";
+#endif
 }
 
 void SetVersionNumber(const char* version_number) {
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index bafc410..ac34c9c 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -18,12 +18,15 @@
 #include "base/bits.h"
 #include "base/files/file.h"
 #include "base/format_macros.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
+
 namespace base {
 namespace android {
 
@@ -32,28 +35,11 @@
 // Android defines the background priority to this value since at least 2009
 // (see Process.java).
 constexpr int kBackgroundPriority = 10;
-// Valid for all the Android architectures.
+// Valid for all Android architectures.
 constexpr size_t kPageSize = 4096;
-constexpr char kLibchromeSuffix[] = "libchrome.so";
-// "base.apk" is a suffix because the library may be loaded directly from the
-// APK.
-constexpr const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
 
-bool IsReadableAndPrivate(const base::debug::MappedMemoryRegion& region) {
-  return region.permissions & base::debug::MappedMemoryRegion::READ &&
-         region.permissions & base::debug::MappedMemoryRegion::PRIVATE;
-}
-
-bool PathMatchesSuffix(const std::string& path) {
-  for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
-    if (EndsWith(path, kSuffixesToMatch[i], CompareCase::SENSITIVE)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-// For each range, reads a byte per page to force it into the page cache.
+// Reads a byte per page between |start| and |end| to force it into the page
+// cache.
 // Heap allocations, syscalls and library functions are not allowed in this
 // function.
 // Returns true for success.
@@ -64,47 +50,37 @@
 // for the context.
 __attribute__((no_sanitize_address))
 #endif
-bool Prefetch(const std::vector<std::pair<uintptr_t, uintptr_t>>& ranges) {
-  for (const auto& range : ranges) {
-    const uintptr_t page_mask = kPageSize - 1;
-    // If start or end is not page-aligned, parsing went wrong. It is better to
-    // exit with an error.
-    if ((range.first & page_mask) || (range.second & page_mask)) {
-      return false;  // CHECK() is not allowed here.
-    }
-    unsigned char* start_ptr = reinterpret_cast<unsigned char*>(range.first);
-    unsigned char* end_ptr = reinterpret_cast<unsigned char*>(range.second);
-    unsigned char dummy = 0;
-    for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
-      // Volatile is required to prevent the compiler from eliminating this
-      // loop.
-      dummy ^= *static_cast<volatile unsigned char*>(ptr);
-    }
+bool Prefetch(size_t start, size_t end) {
+  unsigned char* start_ptr = reinterpret_cast<unsigned char*>(start);
+  unsigned char* end_ptr = reinterpret_cast<unsigned char*>(end);
+  unsigned char dummy = 0;
+  for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
+    // Volatile is required to prevent the compiler from eliminating this
+    // loop.
+    dummy ^= *static_cast<volatile unsigned char*>(ptr);
   }
   return true;
 }
 
-// Populate the per-page residency for |range| in |residency|. If successful,
-// |residency| has the size of |range| in pages.
+// Populates the per-page residency between |start| and |end| in |residency|. If
+// successful, |residency| has the size of |end| - |start| in pages.
 // Returns true for success.
-bool MincoreOnRange(const NativeLibraryPrefetcher::AddressRange& range,
-                    std::vector<unsigned char>* residency) {
-  if (range.first % kPageSize || range.second % kPageSize)
+bool Mincore(size_t start, size_t end, std::vector<unsigned char>* residency) {
+  if (start % kPageSize || end % kPageSize)
     return false;
-  size_t size = range.second - range.first;
+  size_t size = end - start;
   size_t size_in_pages = size / kPageSize;
   if (residency->size() != size_in_pages)
     residency->resize(size_in_pages);
   int err = HANDLE_EINTR(
-      mincore(reinterpret_cast<void*>(range.first), size, &(*residency)[0]));
+      mincore(reinterpret_cast<void*>(start), size, &(*residency)[0]));
   PLOG_IF(ERROR, err) << "mincore() failed";
   return !err;
 }
 
-#if defined(ARCH_CPU_ARMEL)
 // Returns the start and end of .text, aligned to the lower and upper page
 // boundaries, respectively.
-NativeLibraryPrefetcher::AddressRange GetTextRange() {
+std::pair<size_t, size_t> GetTextRange() {
   // |kStartOftext| may not be at the beginning of a page, since .plt can be
   // before it, yet in the same mapping for instance.
   size_t start_page = kStartOfText - kStartOfText % kPageSize;
@@ -126,7 +102,8 @@
 };
 
 // Returns true for success.
-bool CollectResidency(const NativeLibraryPrefetcher::AddressRange& range,
+bool CollectResidency(size_t start,
+                      size_t end,
                       std::vector<TimestampAndResidency>* data) {
   // Not using base::TimeTicks() to not call too many base:: symbol that would
   // pollute the reached symbols dumps.
@@ -138,14 +115,15 @@
   uint64_t now =
       static_cast<uint64_t>(ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec;
   std::vector<unsigned char> residency;
-  if (!MincoreOnRange(range, &residency))
+  if (!Mincore(start, end, &residency))
     return false;
 
   data->emplace_back(now, std::move(residency));
   return true;
 }
 
-void DumpResidency(const NativeLibraryPrefetcher::AddressRange& range,
+void DumpResidency(size_t start,
+                   size_t end,
                    std::unique_ptr<std::vector<TimestampAndResidency>> data) {
   auto path = base::FilePath(
       base::StringPrintf("/data/local/tmp/chrome/residency-%d.txt", getpid()));
@@ -158,12 +136,11 @@
   }
 
   // First line: start-end of text range.
-  CheckOrderingSanity();
-  CHECK_LT(range.first, kStartOfText);
-  CHECK_LT(kEndOfText, range.second);
-  auto start_end =
-      base::StringPrintf("%" PRIuS " %" PRIuS "\n", kStartOfText - range.first,
-                         kEndOfText - range.first);
+  CHECK(IsOrderingSane());
+  CHECK_LT(start, kStartOfText);
+  CHECK_LT(kEndOfText, end);
+  auto start_end = base::StringPrintf("%" PRIuS " %" PRIuS "\n",
+                                      kStartOfText - start, kEndOfText - start);
   file.WriteAtCurrentPos(start_end.c_str(), start_end.size());
 
   for (const auto& data_point : *data) {
@@ -179,61 +156,9 @@
     file.WriteAtCurrentPos(&dump[0], dump.size());
   }
 }
-#endif  // defined(ARCH_CPU_ARMEL)
 }  // namespace
 
 // static
-bool NativeLibraryPrefetcher::IsGoodToPrefetch(
-    const base::debug::MappedMemoryRegion& region) {
-  return PathMatchesSuffix(region.path) &&
-         IsReadableAndPrivate(region);  // .text and .data mappings are private.
-}
-
-// static
-void NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(
-    const std::vector<base::debug::MappedMemoryRegion>& regions,
-    std::vector<AddressRange>* ranges) {
-  bool has_libchrome_region = false;
-  for (const base::debug::MappedMemoryRegion& region : regions) {
-    if (EndsWith(region.path, kLibchromeSuffix, CompareCase::SENSITIVE)) {
-      has_libchrome_region = true;
-      break;
-    }
-  }
-  for (const base::debug::MappedMemoryRegion& region : regions) {
-    if (has_libchrome_region &&
-        !EndsWith(region.path, kLibchromeSuffix, CompareCase::SENSITIVE)) {
-      continue;
-    }
-    ranges->push_back(std::make_pair(region.start, region.end));
-  }
-}
-
-// static
-bool NativeLibraryPrefetcher::FindRanges(std::vector<AddressRange>* ranges) {
-  // All code (including in the forked process) relies on this assumption.
-  if (sysconf(_SC_PAGESIZE) != static_cast<long>(kPageSize))
-    return false;
-
-  std::string proc_maps;
-  if (!base::debug::ReadProcMaps(&proc_maps))
-    return false;
-  std::vector<base::debug::MappedMemoryRegion> regions;
-  if (!base::debug::ParseProcMaps(proc_maps, &regions))
-    return false;
-
-  std::vector<base::debug::MappedMemoryRegion> regions_to_prefetch;
-  for (const auto& region : regions) {
-    if (IsGoodToPrefetch(region)) {
-      regions_to_prefetch.push_back(region);
-    }
-  }
-
-  FilterLibchromeRangesOnlyIfPossible(regions_to_prefetch, ranges);
-  return true;
-}
-
-// static
 bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
   // Avoid forking with cygprofile instrumentation because the latter performs
   // memory allocations.
@@ -241,20 +166,23 @@
   return false;
 #endif
 
+  if (!IsOrderingSane()) {
+    LOG(WARNING) << "Incorrect code ordering";
+    return false;
+  }
+
   // Looking for ranges is done before the fork, to avoid syscalls and/or memory
   // allocations in the forked process. The child process inherits the lock
   // state of its parent thread. It cannot rely on being able to acquire any
   // lock (unless special care is taken in a pre-fork handler), including being
   // able to call malloc().
-  std::vector<AddressRange> ranges;
-  if (!FindRanges(&ranges))
-    return false;
+  const auto& range = GetTextRange();
 
   pid_t pid = fork();
   if (pid == 0) {
     setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
     // _exit() doesn't call the atexit() handlers.
-    _exit(Prefetch(ranges) ? 0 : 1);
+    _exit(Prefetch(range.first, range.second) ? 0 : 1);
   } else {
     if (pid < 0) {
       return false;
@@ -271,20 +199,18 @@
 }
 
 // static
-int NativeLibraryPrefetcher::PercentageOfResidentCode(
-    const std::vector<AddressRange>& ranges) {
+int NativeLibraryPrefetcher::PercentageOfResidentCode(size_t start,
+                                                      size_t end) {
   size_t total_pages = 0;
   size_t resident_pages = 0;
 
-  for (const auto& range : ranges) {
-    std::vector<unsigned char> residency;
-    bool ok = MincoreOnRange(range, &residency);
-    if (!ok)
-      return -1;
-    total_pages += residency.size();
-    resident_pages += std::count_if(residency.begin(), residency.end(),
-                                    [](unsigned char x) { return x & 1; });
-  }
+  std::vector<unsigned char> residency;
+  bool ok = Mincore(start, end, &residency);
+  if (!ok)
+    return -1;
+  total_pages += residency.size();
+  resident_pages += std::count_if(residency.begin(), residency.end(),
+                                  [](unsigned char x) { return x & 1; });
   if (total_pages == 0)
     return -1;
   return static_cast<int>((100 * resident_pages) / total_pages);
@@ -292,44 +218,39 @@
 
 // static
 int NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode() {
-  std::vector<AddressRange> ranges;
-  if (!FindRanges(&ranges))
+  if (!IsOrderingSane()) {
+    LOG(WARNING) << "Incorrect code ordering";
     return -1;
-  return PercentageOfResidentCode(ranges);
+  }
+  const auto& range = GetTextRange();
+  return PercentageOfResidentCode(range.first, range.second);
 }
 
 // static
 void NativeLibraryPrefetcher::PeriodicallyCollectResidency() {
-#if defined(ARCH_CPU_ARMEL)
   CHECK_EQ(static_cast<long>(kPageSize), sysconf(_SC_PAGESIZE));
 
   const auto& range = GetTextRange();
   auto data = std::make_unique<std::vector<TimestampAndResidency>>();
   for (int i = 0; i < 60; ++i) {
-    if (!CollectResidency(range, data.get()))
+    if (!CollectResidency(range.first, range.second, data.get()))
       return;
     usleep(2e5);
   }
-  DumpResidency(range, std::move(data));
-#else
-  CHECK(false) << "Only supported on ARM";
-#endif
+  DumpResidency(range.first, range.second, std::move(data));
 }
 
 // static
 void NativeLibraryPrefetcher::MadviseRandomText() {
-#if defined(ARCH_CPU_ARMEL)
-  CheckOrderingSanity();
+  CHECK(IsOrderingSane());
   const auto& range = GetTextRange();
   size_t size = range.second - range.first;
   int err = madvise(reinterpret_cast<void*>(range.first), size, MADV_RANDOM);
   if (err) {
     PLOG(ERROR) << "madvise() failed";
   }
-#else
-  CHECK(false) << "Only supported on ARM.";
-#endif  // defined(ARCH_CPU_ARMEL)
 }
 
 }  // namespace android
 }  // namespace base
+#endif  // BUILDFLAG(SUPPORTS_CODE_ORDERING)
diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h
index bff90a4..885ed604 100644
--- a/base/android/library_loader/library_prefetcher.h
+++ b/base/android/library_loader/library_prefetcher.h
@@ -8,33 +8,32 @@
 #include <jni.h>
 
 #include <stdint.h>
-#include <string>
-#include <utility>
-#include <vector>
 
-#include "base/debug/proc_maps_linux.h"
+#include "base/android/library_loader/anchor_functions_flags.h"
+#include "base/base_export.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
+
 namespace base {
 namespace android {
 
 // Forks and waits for a process prefetching the native library. This is done in
 // a forked process for the following reasons:
-// - Isolating the main process from mistakes in the parsing. If the parsing
-//   returns an incorrect address, only the forked process will crash.
+// - Isolating the main process from mistakes in getting the address range, only
+//   crashing the forked process in case of mistake.
 // - Not inflating the memory used by the main process uselessly, which could
 //   increase its likelihood to be killed.
 // The forked process has background priority and, since it is not declared to
 // the Android runtime, can be killed at any time, which is not an issue here.
 class BASE_EXPORT NativeLibraryPrefetcher {
  public:
-  using AddressRange = std::pair<uintptr_t, uintptr_t>;
-
-  // Finds the ranges matching the native library, forks a low priority
-  // process pre-fetching these ranges and wait()s for it.
+  // Finds the executable code range, forks a low priority process pre-fetching
+  // it wait()s for the process to exit or die.
   // Returns true for success.
   static bool ForkAndPrefetchNativeLibrary();
+
   // Returns the percentage of the native library code currently resident in
   // memory, or -1 in case of error.
   static int PercentageOfResidentNativeLibraryCode();
@@ -47,38 +46,12 @@
   static void MadviseRandomText();
 
  private:
-  // Returns true if the region matches native code or data.
-  static bool IsGoodToPrefetch(const base::debug::MappedMemoryRegion& region);
-  // Filters the regions to keep only libchrome ranges if possible.
-  static void FilterLibchromeRangesOnlyIfPossible(
-      const std::vector<base::debug::MappedMemoryRegion>& regions,
-      std::vector<AddressRange>* ranges);
-  // Finds the ranges matching the native library in /proc/self/maps.
-  // Returns true for success.
-  static bool FindRanges(std::vector<AddressRange>* ranges);
-
-  // Returns the percentage of the given address ranges currently resident in
+  // Returns the percentage of [start, end] currently resident in
   // memory, or -1 in case of error.
-  static int PercentageOfResidentCode(const std::vector<AddressRange>& ranges);
+  static int PercentageOfResidentCode(size_t start, size_t end);
 
   FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestIsGoodToPrefetchNoRange);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestIsGoodToPrefetchUnreadableRange);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestIsGoodToPrefetchSkipSharedRange);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestIsGoodToPrefetchLibchromeRange);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestIsGoodToPrefetchBaseApkRange);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
                            TestPercentageOfResidentCode);
-  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
-                           TestPercentageOfResidentCodeTwoRegions);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(NativeLibraryPrefetcher);
 };
@@ -86,4 +59,6 @@
 }  // namespace android
 }  // namespace base
 
+#endif  // BUILDFLAG(SUPPORTS_CODE_ORDERING)
+
 #endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
diff --git a/base/android/library_loader/library_prefetcher_unittest.cc b/base/android/library_loader/library_prefetcher_unittest.cc
index 6b35487..0c81220 100644
--- a/base/android/library_loader/library_prefetcher_unittest.cc
+++ b/base/android/library_loader/library_prefetcher_unittest.cc
@@ -7,96 +7,15 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <sys/mman.h>
-#include <string>
-#include <vector>
-#include "base/debug/proc_maps_linux.h"
+#include "base/android/library_loader/anchor_functions_flags.h"
 #include "base/memory/shared_memory.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if BUILDFLAG(SUPPORTS_CODE_ORDERING)
 namespace base {
 namespace android {
 
-namespace {
-const uint8_t kRead = base::debug::MappedMemoryRegion::READ;
-const uint8_t kReadPrivate = base::debug::MappedMemoryRegion::READ |
-                             base::debug::MappedMemoryRegion::PRIVATE;
-const uint8_t kExecutePrivate = base::debug::MappedMemoryRegion::EXECUTE |
-                                base::debug::MappedMemoryRegion::PRIVATE;
-}  // namespace
-
-TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchNoRange) {
-  const base::debug::MappedMemoryRegion regions[4] = {
-      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, 0, kReadPrivate, ""},
-      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, 0, kReadPrivate,
-                                      "foo"},
-      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, 0, kReadPrivate,
-                                      "foobar.apk"},
-      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, 0, kReadPrivate,
-                                      "libchromium.so"}};
-  for (int i = 0; i < 4; ++i) {
-    ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(regions[i]));
-  }
-}
-
-TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchUnreadableRange) {
-  const base::debug::MappedMemoryRegion region = {
-      0x4000, 0x5000, 10, 0, kExecutePrivate, "base.apk"};
-  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
-}
-
-TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchSkipSharedRange) {
-  const base::debug::MappedMemoryRegion region = {
-      0x4000, 0x5000, 10, 0, kRead, "base.apk"};
-  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
-}
-
-TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchLibchromeRange) {
-  const base::debug::MappedMemoryRegion region = {
-      0x4000, 0x5000, 10, 0, kReadPrivate, "libchrome.so"};
-  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
-}
-
-TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchBaseApkRange) {
-  const base::debug::MappedMemoryRegion region = {
-      0x4000, 0x5000, 10, 0, kReadPrivate, "base.apk"};
-  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
-}
-
-TEST(NativeLibraryPrefetcherTest,
-     TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome) {
-  std::vector<base::debug::MappedMemoryRegion> regions;
-  regions.push_back(base::debug::MappedMemoryRegion{0x1, 0x2, 0, 0,
-                                                    kReadPrivate, "base.apk"});
-  regions.push_back(base::debug::MappedMemoryRegion{0x3, 0x4, 0, 0,
-                                                    kReadPrivate, "base.apk"});
-  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
-  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
-                                                               &ranges);
-  EXPECT_EQ(ranges.size(), 2U);
-  EXPECT_EQ(ranges[0].first, 0x1U);
-  EXPECT_EQ(ranges[0].second, 0x2U);
-  EXPECT_EQ(ranges[1].first, 0x3U);
-  EXPECT_EQ(ranges[1].second, 0x4U);
-}
-
-TEST(NativeLibraryPrefetcherTest,
-     TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome) {
-  std::vector<base::debug::MappedMemoryRegion> regions;
-  regions.push_back(base::debug::MappedMemoryRegion{0x1, 0x2, 0, 0,
-                                                    kReadPrivate, "base.apk"});
-  regions.push_back(base::debug::MappedMemoryRegion{
-      0x6, 0x7, 0, 0, kReadPrivate, "libchrome.so"});
-  regions.push_back(base::debug::MappedMemoryRegion{0x3, 0x4, 0, 0,
-                                                    kReadPrivate, "base.apk"});
-  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
-  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
-                                                               &ranges);
-  EXPECT_EQ(ranges.size(), 1U);
-  EXPECT_EQ(ranges[0].first, 0x6U);
-  EXPECT_EQ(ranges[0].second, 0x7U);
-}
-
 // Fails with ASAN, crbug.com/570423.
 #if !defined(ADDRESS_SANITIZER)
 namespace {
@@ -108,55 +27,20 @@
   base::SharedMemory shared_mem;
   ASSERT_TRUE(shared_mem.CreateAndMapAnonymous(length));
   void* address = shared_mem.memory();
-
-  std::vector<NativeLibraryPrefetcher::AddressRange> ranges = {
-      {reinterpret_cast<uintptr_t>(address),
-       reinterpret_cast<uintptr_t>(address) + length}};
+  size_t start = reinterpret_cast<size_t>(address);
+  size_t end = start + length;
 
   // Remove everything.
   ASSERT_EQ(0, madvise(address, length, MADV_DONTNEED));
-  // TODO(lizeb): If flaky, mock mincore().
-  EXPECT_EQ(0, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
+  EXPECT_EQ(0, NativeLibraryPrefetcher::PercentageOfResidentCode(start, end));
 
   // Get everything back.
   ASSERT_EQ(0, mlock(address, length));
-  EXPECT_EQ(100, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
+  EXPECT_EQ(100, NativeLibraryPrefetcher::PercentageOfResidentCode(start, end));
   munlock(address, length);
 }
-
-TEST(NativeLibraryPrefetcherTest, TestPercentageOfResidentCodeTwoRegions) {
-  size_t length = 4 * kPageSize;
-  base::SharedMemory shared_mem;
-  ASSERT_TRUE(shared_mem.CreateAndMapAnonymous(length));
-  void* address = shared_mem.memory();
-
-  size_t length2 = 8 * kPageSize;
-  base::SharedMemory shared_mem2;
-  ASSERT_TRUE(shared_mem2.CreateAndMapAnonymous(length2));
-  void* address2 = shared_mem2.memory();
-
-  std::vector<NativeLibraryPrefetcher::AddressRange> ranges = {
-      {reinterpret_cast<uintptr_t>(address),
-       reinterpret_cast<uintptr_t>(address) + length},
-      {reinterpret_cast<uintptr_t>(address2),
-       reinterpret_cast<uintptr_t>(address2) + length2}};
-
-  // Remove everything.
-  ASSERT_EQ(0, madvise(address, length, MADV_DONTNEED));
-  ASSERT_EQ(0, madvise(address2, length, MADV_DONTNEED));
-  // TODO(lizeb): If flaky, mock mincore().
-  EXPECT_EQ(0, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
-
-  // Get back the first range.
-  ASSERT_EQ(0, mlock(address, length));
-  EXPECT_EQ(33, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
-  // The second one.
-  ASSERT_EQ(0, mlock(address2, length2));
-  EXPECT_EQ(100, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
-  munlock(address, length);
-  munlock(address2, length);
-}
 #endif  // !defined(ADDRESS_SANITIZER)
 
 }  // namespace android
 }  // namespace base
+#endif  // BUILDFLAG(SUPPORTS_CODE_ORDERING)
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc
index 5d7fd8b..ef27c61 100644
--- a/base/files/dir_reader_posix_unittest.cc
+++ b/base/files/dir_reader_posix_unittest.cc
@@ -32,7 +32,11 @@
   const char* dir = temp_dir.GetPath().value().c_str();
   ASSERT_TRUE(dir);
 
+  char wdbuf[PATH_MAX];
+  getcwd(wdbuf, PATH_MAX);
+  LOG(ERROR) << "Current directory: " << wdbuf;
   const int prev_wd = open(".", O_RDONLY | O_DIRECTORY);
+  PLOG_IF(ERROR, prev_wd < 0) << "opening . failed with ";
   DCHECK_GE(prev_wd, 0);
 
   PCHECK(chdir(dir) == 0);
diff --git a/build/android/gradle/root.jinja b/build/android/gradle/root.jinja
index d3a259f..0dc2c79 100644
--- a/build/android/gradle/root.jinja
+++ b/build/android/gradle/root.jinja
@@ -12,7 +12,7 @@
     }
     dependencies {
 {% if canary %}
-        classpath "com.android.tools.build:gradle:3.1.0-alpha04"
+        classpath "com.android.tools.build:gradle:3.1.0-alpha08"
 {% else %}
         classpath "com.android.tools.build:gradle:3.0.0"
 {% endif %}
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index 49d8aa08..b569f0d7 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -25,7 +25,7 @@
   <issue id="AllowBackup">
     <ignore path="AndroidManifest.xml"/>
   </issue>
-  <!-- TODO(crbug.com/799070): File bugs to fix this -->
+  <!-- TODO(crbug.com/804427): Remove this suppression or add rationale. -->
   <issue id="AppCompatResource" severity="ignore"/>
   <!-- We use asserts in Chromium. See https://chromium.googlesource.com/chromium/src/+/master/styleguide/java/java.md#Asserts -->
   <issue id="Assert" severity="ignore"/>
@@ -71,10 +71,10 @@
     <ignore regexp="content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java"/>
     <ignore regexp="content/public/android/java/src/org/chromium/content/browser/PopupZoomer.java"/>
   </issue>
-  <!-- TODO(crbug.com/799070): File bugs to fix this -->
+  <!-- TODO(crbug.com/804432): Remove this and fix the offending xml files. -->
   <issue id="EllipsizeMaxLines" severity="ignore"/>
   <issue id="ExifInterface">
-    <!-- TODO(crbug.com/799070): Update android.support.media.ExifInterface and use it instead -->
+    <!-- TODO(crbug.com/804438): Cannot update until android.media.ExifInterface supports file descriptors -->
     <ignore regexp="chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java"/>
   </issue>
   <issue id="ExportedContentProvider">
@@ -91,7 +91,7 @@
   <issue id="GoogleAppIndexingWarning" severity="Error">
     <ignore regexp="AndroidManifest.xml"/>
   </issue>
-  <!-- TODO(crbug.com/799070): Fix for remoting -->
+  <!-- TODO(crbug.com/804441): Fix for remoting -->
   <issue id="AppLinkUrlError">
     <ignore regexp="AndroidManifest.xml"/>
   </issue>
@@ -130,7 +130,7 @@
   </issue>
   <issue id="IconDipSize">
     <ignore regexp="chromecast/internal"/>
-    <!-- TODO(crbug.com/799070): File bugs to fix these icons -->
+    <!-- These only need to be 1px for all densities. See: crbug.com/804449 -->
     <ignore regexp="chrome/android/java/res/.*tab_strip_fade"/>
   </issue>
   <issue id="IconDuplicates" severity="Error">
@@ -149,10 +149,12 @@
   </issue>
   <issue id="IconLocation">
     <ignore regexp="chromecast/internal"/>
+    <!-- This is just for testing -->
+    <ignore regexp="chrome/test/chromedriver/test/webview_shell/java/res/drawable/icon.png"/>
+    <!-- Memconsumer is only for tooling -->
+    <ignore regexp="tools/android/memconsumer/java/res/drawable/"/>
     <!-- It is OK for content_shell_apk to have missing assets. -->
     <ignore regexp="content/shell/android/java/res/"/>
-    <!-- Suppression for chrome/test/chromedriver/test/webview_shell/java/res/drawable/icon.png -->
-    <ignore regexp="res/drawable/icon.png"/>
   </issue>
   <issue id="IconMissingDensityFolder">
     <!-- see crbug.com/542435 -->
@@ -185,7 +187,7 @@
   <issue id="LabelFor" severity="Error">
     <ignore regexp="android_webview/tools/system_webview_shell/apk/res/layout/activity_webview_browser.xml"/>
   </issue>
-  <!-- TODO(crbug.com/799070): File bugs to fix this. -->
+  <!-- TODO(crbug.com/804453): Remove this after fixing. -->
   <issue id="KeyboardInaccessibleWidget" severity="ignore"/>
   <issue id="LintError" severity="Error"/>
   <issue id="LogConditional" severity="ignore"/>
@@ -224,9 +226,12 @@
     <ignore regexp="Call requires API level 19.*`java.lang.Throwable#addSuppressed`"/>
     <!-- We support default methods via desugar. -->
     <ignore regexp="Default method requires API level 24"/>
+    <!-- TODO(crbug.com/805479): Remove the following suppression and fix. -->
+    <ignore regexp="Call requires API level 18.*android.view.View#setClipBounds"/>
+    <!-- TODO(crbug.com/805509): Remove the following suppression and fix. -->
+    <ignore regexp="Call requires API level 19.*new java.lang.AssertionError"/>
     <!-- TODO(crbug.com/799070): Fix these after lint upgrade. -->
     <ignore regexp="Static interface  method requires API level 24"/>
-    <ignore regexp="(current min is 1)"/>
     <!-- Suppressions below this line need rationale :( -->
     <ignore regexp="Attribute `paddingStart` referenced here can result in a crash on some specific devices older than API 17"/>
     <ignore regexp="chrome/android/java/res/values-v17/styles.xml"/>
@@ -371,7 +376,7 @@
     <ignore regexp="chrome/android/java/res/drawable-hdpi/omnibox_info.png"/>
     <ignore regexp="clank/java/clank_strings_grd.resources.zip/values/android_internal_strings.xml"/>
     <ignore regexp="tools/android/audio_focus_grabber/java/res/drawable-hdpi/notification_icon.png"/>
-    <!-- # TODO(crbug.com/799070): Fix these. -->
+    <!-- TODO(crbug.com/799070): Fix these. -->
     <ignore regexp="ui/android/java/res/values/colors.xml"/>
     <ignore regexp="ui/android/java/res/values/dimens.xml"/>
     <ignore regexp="ui/android/java/res/values-v17/styles.xml"/>
diff --git a/build/build_config.h b/build/build_config.h
index 6b30422e..7742dd7 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -63,6 +63,8 @@
 #define OS_QNX 1
 #elif defined(_AIX)
 #define OS_AIX 1
+#elif defined(__asmjs__)
+#define OS_ASMJS
 #else
 #error Please add support for your platform in build/build_config.h
 #endif
@@ -77,10 +79,10 @@
 
 // For access to standard POSIXish features, use OS_POSIX instead of a
 // more specific macro.
-#if defined(OS_AIX) || defined(OS_ANDROID) || defined(OS_FREEBSD) ||  \
-    defined(OS_FUCHSIA) || defined(OS_LINUX) || defined(OS_MACOSX) || \
-    defined(OS_NACL) || defined(OS_NETBSD) || defined(OS_OPENBSD) ||  \
-    defined(OS_QNX) || defined(OS_SOLARIS)
+#if defined(OS_AIX) || defined(OS_ANDROID) || defined(OS_ASMJS) ||     \
+    defined(OS_FREEBSD) || defined(OS_FUCHSIA) || defined(OS_LINUX) || \
+    defined(OS_MACOSX) || defined(OS_NACL) || defined(OS_NETBSD) ||    \
+    defined(OS_OPENBSD) || defined(OS_QNX) || defined(OS_SOLARIS)
 #define OS_POSIX 1
 #endif
 
@@ -143,7 +145,7 @@
 #define ARCH_CPU_ARM64 1
 #define ARCH_CPU_64_BITS 1
 #define ARCH_CPU_LITTLE_ENDIAN 1
-#elif defined(__pnacl__)
+#elif defined(__pnacl__) || defined(__asmjs__)
 #define ARCH_CPU_32_BITS 1
 #define ARCH_CPU_LITTLE_ENDIAN 1
 #elif defined(__MIPSEL__)
diff --git a/build/toolchain/goma.gni b/build/toolchain/goma.gni
index 2198f49..d6e7a792 100644
--- a/build/toolchain/goma.gni
+++ b/build/toolchain/goma.gni
@@ -15,7 +15,7 @@
   # Set the default value based on the platform.
   if (host_os == "win") {
     # Absolute directory containing the gomacc.exe binary.
-    goma_dir = "C:\goma\goma-win64"
+    goma_dir = "C:\src\goma\goma-win64"
   } else {
     # Absolute directory containing the gomacc binary.
     goma_dir = getenv("HOME") + "/goma"
diff --git a/cc/resources/layer_tree_resource_provider.cc b/cc/resources/layer_tree_resource_provider.cc
index 5bc08896..37f3c76a 100644
--- a/cc/resources/layer_tree_resource_provider.cc
+++ b/cc/resources/layer_tree_resource_provider.cc
@@ -25,44 +25,6 @@
 
 namespace cc {
 
-class TextureIdAllocator {
- public:
-  TextureIdAllocator(GLES2Interface* gl,
-                     size_t texture_id_allocation_chunk_size)
-      : gl_(gl),
-        id_allocation_chunk_size_(texture_id_allocation_chunk_size),
-        ids_(new GLuint[texture_id_allocation_chunk_size]),
-        next_id_index_(texture_id_allocation_chunk_size) {
-    DCHECK(id_allocation_chunk_size_);
-    DCHECK_LE(id_allocation_chunk_size_,
-              static_cast<size_t>(std::numeric_limits<int>::max()));
-  }
-
-  ~TextureIdAllocator() {
-    if (gl_)
-      gl_->DeleteTextures(
-          static_cast<int>(id_allocation_chunk_size_ - next_id_index_),
-          ids_.get() + next_id_index_);
-  }
-
-  GLuint NextId() {
-    if (next_id_index_ == id_allocation_chunk_size_) {
-      gl_->GenTextures(static_cast<int>(id_allocation_chunk_size_), ids_.get());
-      next_id_index_ = 0;
-    }
-
-    return ids_[next_id_index_++];
-  }
-
- private:
-  GLES2Interface* gl_;
-  const size_t id_allocation_chunk_size_;
-  std::unique_ptr<GLuint[]> ids_;
-  size_t next_id_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
-};
-
 LayerTreeResourceProvider::Settings::Settings(
     viz::ContextProvider* compositor_context_provider,
     bool delegated_sync_points_required,
@@ -73,7 +35,6 @@
       use_gpu_memory_buffer_resources(
           resource_settings.use_gpu_memory_buffer_resources),
       delegated_sync_points_required(delegated_sync_points_required) {
-  DCHECK(resource_settings.texture_id_allocation_chunk_size);
   if (!compositor_context_provider) {
     // Pick an arbitrary limit here similar to what hardware might.
     max_texture_size = 16 * 1024;
@@ -150,9 +111,6 @@
       shared_bitmap_manager_(shared_bitmap_manager),
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       next_id_(kLayerTreeInitialResourceId) {
-  GLES2Interface* gl = ContextGL();
-  texture_id_allocator_ = std::make_unique<TextureIdAllocator>(
-      gl, resource_settings.texture_id_allocation_chunk_size);
 }
 
 LayerTreeResourceProvider::~LayerTreeResourceProvider() {
@@ -163,7 +121,6 @@
     bool is_lost = imported.exported_count || imported.returned_lost;
     imported.release_callback->Run(imported.returned_sync_token, is_lost);
   }
-  texture_id_allocator_ = nullptr;
   GLES2Interface* gl = ContextGL();
   if (gl)
     gl->Finish();
@@ -569,13 +526,12 @@
   DCHECK_EQ(resource->origin, viz::internal::Resource::INTERNAL);
   DCHECK(resource->mailbox.IsZero());
 
-  resource->gl_id = texture_id_allocator_->NextId();
-  DCHECK(resource->gl_id);
-
   GLES2Interface* gl = ContextGL();
   DCHECK(gl);
 
-  // Create and set texture properties. Allocation is delayed until needed.
+  // Create and set texture properties. Allocation of the texture backing is
+  // delayed until needed.
+  gl->GenTextures(1, &resource->gl_id);
   gl->BindTexture(resource->target, resource->gl_id);
   gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
                     resource->original_filter);
diff --git a/cc/resources/layer_tree_resource_provider.h b/cc/resources/layer_tree_resource_provider.h
index e9b6a3b..c8075071 100644
--- a/cc/resources/layer_tree_resource_provider.h
+++ b/cc/resources/layer_tree_resource_provider.h
@@ -25,7 +25,6 @@
 }  // namespace gpu
 
 namespace cc {
-class TextureIdAllocator;
 
 // This class is not thread-safe and can only be called from the thread it was
 // created on (in practice, the impl thread).
@@ -346,7 +345,6 @@
   viz::SharedBitmapManager* shared_bitmap_manager_;
   struct ImportedResource;
   base::flat_map<viz::ResourceId, ImportedResource> imported_resources_;
-  std::unique_ptr<TextureIdAllocator> texture_id_allocator_;
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
   viz::ResourceId next_id_;
 
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 4541458..c6447f43 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -93,11 +93,8 @@
   return shared_bitmap;
 }
 
-static viz::ResourceSettings CreateResourceSettings(
-    size_t texture_id_allocation_chunk_size = 1) {
+static viz::ResourceSettings CreateResourceSettings() {
   viz::ResourceSettings resource_settings;
-  resource_settings.texture_id_allocation_chunk_size =
-      texture_id_allocation_chunk_size;
   resource_settings.use_gpu_memory_buffer_resources =
       kUseGpuMemoryBufferResources;
   return resource_settings;
@@ -3379,49 +3376,6 @@
   }
 };
 
-TEST(ResourceProviderTest, TextureAllocationChunkSize) {
-  auto context_owned(std::make_unique<TextureIdAllocationTrackingContext>());
-  TextureIdAllocationTrackingContext* context = context_owned.get();
-  auto context_provider = TestContextProvider::Create(std::move(context_owned));
-  context_provider->BindToCurrentThread();
-  auto shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>();
-
-  gfx::Size size(1, 1);
-  viz::ResourceFormat format = viz::RGBA_8888;
-
-  {
-    size_t kTextureAllocationChunkSize = 1;
-    auto resource_provider(std::make_unique<LayerTreeResourceProvider>(
-        context_provider.get(), shared_bitmap_manager.get(), nullptr,
-        kDelegatedSyncPointsRequired,
-        CreateResourceSettings(kTextureAllocationChunkSize)));
-
-    viz::ResourceId id = resource_provider->CreateGpuTextureResource(
-        size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
-    resource_provider->AllocateForTesting(id);
-    Mock::VerifyAndClearExpectations(context);
-
-    DCHECK_EQ(2u, context->PeekTextureId());
-    resource_provider->DeleteResource(id);
-  }
-
-  {
-    size_t kTextureAllocationChunkSize = 8;
-    auto resource_provider(std::make_unique<LayerTreeResourceProvider>(
-        context_provider.get(), shared_bitmap_manager.get(), nullptr,
-        kDelegatedSyncPointsRequired,
-        CreateResourceSettings(kTextureAllocationChunkSize)));
-
-    viz::ResourceId id = resource_provider->CreateGpuTextureResource(
-        size, viz::ResourceTextureHint::kDefault, format, gfx::ColorSpace());
-    resource_provider->AllocateForTesting(id);
-    Mock::VerifyAndClearExpectations(context);
-
-    DCHECK_EQ(10u, context->PeekTextureId());
-    resource_provider->DeleteResource(id);
-  }
-}
-
 TEST_P(ResourceProviderTest, GetSyncTokenForResources) {
   if (!use_gpu())
     return;
diff --git a/cc/test/fake_resource_provider.h b/cc/test/fake_resource_provider.h
index c1fbc494..763393d7 100644
--- a/cc/test/fake_resource_provider.h
+++ b/cc/test/fake_resource_provider.h
@@ -19,7 +19,6 @@
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = nullptr,
       bool high_bit_for_testing = false) {
     viz::ResourceSettings resource_settings;
-    resource_settings.texture_id_allocation_chunk_size = 1;
     resource_settings.high_bit_for_testing = high_bit_for_testing;
     return std::make_unique<LayerTreeResourceProvider>(
         context_provider, shared_bitmap_manager, gpu_memory_buffer_manager,
@@ -29,8 +28,6 @@
   static std::unique_ptr<DisplayResourceProvider> CreateDisplayResourceProvider(
       viz::ContextProvider* context_provider,
       viz::SharedBitmapManager* shared_bitmap_manager) {
-    viz::ResourceSettings resource_settings;
-    resource_settings.texture_id_allocation_chunk_size = 1;
     return std::make_unique<DisplayResourceProvider>(context_provider,
                                                      shared_bitmap_manager);
   }
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index 9ad595d..a2a084c3 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef CC_TEST_PIXEL_TEST_H_
+#define CC_TEST_PIXEL_TEST_H_
+
 #include "base/files/file_util.h"
 #include "cc/test/pixel_comparator.h"
 #include "cc/trees/layer_tree_settings.h"
@@ -13,9 +16,6 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_implementation.h"
 
-#ifndef CC_TEST_PIXEL_TEST_H_
-#define CC_TEST_PIXEL_TEST_H_
-
 namespace viz {
 class CopyOutputResult;
 class DirectRenderer;
diff --git a/cc/trees/latency_info_swap_promise_monitor.h b/cc/trees/latency_info_swap_promise_monitor.h
index 4d33547..c127b96 100644
--- a/cc/trees/latency_info_swap_promise_monitor.h
+++ b/cc/trees/latency_info_swap_promise_monitor.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/compiler_specific.h"
-#include "cc/trees/swap_promise_monitor.h"
-
 #ifndef CC_TREES_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
 #define CC_TREES_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
 
+#include "base/compiler_specific.h"
+#include "cc/trees/swap_promise_monitor.h"
+
 namespace ui {
 class LatencyInfo;
 }  // namespace ui
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 29bb61a..92fb83ba 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -134,7 +134,6 @@
     LayerTreeSettings settings;
     settings.enable_surface_synchronization = true;
     settings.minimum_occlusion_tracking_size = gfx::Size();
-    settings.resource_settings.texture_id_allocation_chunk_size = 1;
     return settings;
   }
 
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index f0193b2..21716630 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3729,10 +3729,6 @@
  public:
   LayerTreeHostTestUIResource() : num_ui_resources_(0) {}
 
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->resource_settings.texture_id_allocation_chunk_size = 1;
-  }
-
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void DidCommit() override {
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index e7f884a..2676ad6 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -1137,9 +1137,6 @@
 class UIResourceLostTest : public LayerTreeHostContextTest {
  public:
   UIResourceLostTest() : time_step_(0) {}
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->resource_settings.texture_id_allocation_chunk_size = 1;
-  }
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
   void AfterTest() override {}
 
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 786c0dd3..ec54b7a9 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -883,11 +883,6 @@
 class LayerTreeHostCopyRequestTestCountTextures
     : public LayerTreeHostCopyRequestTest {
  protected:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    // Always allocate only a single texture at a time through ResourceProvider.
-    settings->resource_settings.texture_id_allocation_chunk_size = 1;
-  }
-
   std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread(
       scoped_refptr<viz::ContextProvider> compositor_context_provider)
       override {
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 148f27da1..cfcf6ffd 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -436,7 +436,6 @@
         # The browser DLL may not depend on blink or v8.
         "//third_party/WebKit/public:blink",
         "//gin",
-        "//tools/v8_context_snapshot",
         "//v8",
       ]
     } else {
@@ -1430,7 +1429,6 @@
       assert_no_deps += [
         # V8/Gin should not be used in the browser DLL on Windows.
         "//gin",
-        "//tools/v8_context_snapshot",
         "//v8",
       ]
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
index 200a1bd..28ac7b6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java
@@ -25,7 +25,6 @@
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.v4.app.NotificationManagerCompat;
 
 import com.google.ipc.invalidation.util.Preconditions;
 
@@ -105,7 +104,7 @@
                         downloadUpdate.getContentId(), downloadUpdate.getIsOffTheRecord());
 
                 builder.setOngoing(true)
-                        .setPriority(NotificationManagerCompat.IMPORTANCE_HIGH)
+                        .setPriority(Notification.PRIORITY_HIGH)
                         .setAutoCancel(false)
                         .setLargeIcon(downloadUpdate.getIcon())
                         .addAction(R.drawable.ic_pause_white_24dp,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index 1a052bd..ecd7758 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -30,7 +30,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.service.notification.StatusBarNotification;
-import android.support.v4.app.NotificationManagerCompat;
 import android.text.TextUtils;
 import android.util.Pair;
 
@@ -75,7 +74,7 @@
  * The service will receive a {@link Service#stopForeground(boolean)} call when all active downloads
  * are paused.  The summary notification will be hidden when there are no other notifications in the
  * {@link NotificationConstants#GROUP_DOWNLOADS} group.  This gets checked after every notification
- * gets removed from the {@link NotificationManagerCompat}.
+ * gets removed from the {@link NotificationManager}.
  */
 public class DownloadNotificationService extends Service {
     static final String EXTRA_DOWNLOAD_CONTENTID_ID =
@@ -140,7 +139,6 @@
     private final List<ContentId> mDownloadsInProgress = new ArrayList<ContentId>();
 
     private NotificationManager mNotificationManager;
-    private NotificationManagerCompat mNotificationManagerCompat;
     private SharedPreferences mSharedPrefs;
     private Context mContext;
     private int mNextNotificationId;
@@ -170,12 +168,11 @@
         if (useForegroundService()) {
             NotificationManager manager =
                     (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-            NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
             // Attempt to update the notification summary icon without starting the service.
             if (ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON.equals(intent.getAction())) {
                 // updateSummaryIcon should be a noop if the notification isn't showing or if the
                 // icon won't change anyway.
-                updateSummaryIcon(context, manager, managerCompat, -1, null);
+                updateSummaryIcon(context, manager, -1, null);
                 return;
             }
 
@@ -194,15 +191,14 @@
      *                              place of the existing icons.
      */
     private static void updateSummaryIcon(Context context, NotificationManager manager,
-            NotificationManagerCompat managerCompat, int removedNotificationId,
-            Pair<Integer, Notification> addedNotification) {
+            int removedNotificationId, Pair<Integer, Notification> addedNotification) {
         if (!useForegroundService()) return;
 
         Pair<Boolean, Integer> icon =
                 getSummaryIcon(context, manager, removedNotificationId, addedNotification);
         if (!icon.first || !hasDownloadNotifications(manager, removedNotificationId)) return;
 
-        managerCompat.notify(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY,
+        manager.notify(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY,
                 buildSummaryNotificationWithIcon(context, icon.second));
     }
 
@@ -357,7 +353,7 @@
      * {@link #startForeground(int, Notification)}, which keeps this service in the foreground.
      * @param context The context used to build the notification and pull specific resources.
      * @return The {@link Notification} to show for the summary.  Meant to be used by
-     *         {@link NotificationManagerCompat#notify(int, Notification)}.
+     *         {@link NotificationManager#notify(int, Notification)}.
      */
     private static Notification buildSummaryNotification(
             Context context, NotificationManager manager) {
@@ -415,7 +411,6 @@
         mContext = ContextUtils.getApplicationContext();
         mNotificationManager =
                 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        mNotificationManagerCompat = NotificationManagerCompat.from(mContext);
         mSharedPrefs = ContextUtils.getAppSharedPreferences();
         mNumAutoResumptionAttemptLeft =
                 mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT, MAX_RESUMPTION_ATTEMPT_LEFT);
@@ -617,15 +612,15 @@
      */
     @VisibleForTesting
     void cancelSummaryNotification() {
-        mNotificationManagerCompat.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY);
+        mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_DOWNLOAD_SUMMARY);
     }
 
     /**
      * Check all current notifications and hide the summary notification if we have no downloads
      * notifications left.  On Android if the user swipes away the last download notification the
      * summary will be dismissed.  But if the last downloads notification is dismissed via
-     * {@link NotificationManagerCompat#cancel(int)}, the summary will remain, so we need to check
-     * and manually remove it ourselves.
+     * {@link NotificationManager#cancel(int)}, the summary will remain, so we need to check and
+     * manually remove it ourselves.
      * @param notificationIdToIgnore Canceling a notification and querying for the current list of
      *                               active notifications isn't synchronous.  Pass a notification id
      *                               here if there is a notification that should be assumed gone.
@@ -650,8 +645,8 @@
                     stopForegroundInternal(true);
                 } else {
                     // If we are not a foreground service, remove the notification via the
-                    // NotificationManagerCompat.  The notification is not bound to this service, so
-                    // any call to stopForeground() won't affect the notification.
+                    // NotificationManager.  The notification is not bound to this service, so any
+                    // call to stopForeground() won't affect the notification.
                     cancelSummaryNotification();
                 }
             } else {
@@ -782,7 +777,7 @@
                                       : android.R.drawable.stat_sys_download;
         ChromeNotificationBuilder builder = buildNotification(resId, fileName, contentText);
         builder.setOngoing(true);
-        builder.setPriority(NotificationManagerCompat.IMPORTANCE_HIGH);
+        builder.setPriority(Notification.PRIORITY_HIGH);
 
         // Avoid animations while the download isn't progressing.
         if (!isDownloadPending) {
@@ -836,7 +831,7 @@
      * @param id The {@link ContentId} of the download.
      */
     public void cancelNotification(int notificationId, ContentId id) {
-        mNotificationManagerCompat.cancel(NOTIFICATION_NAMESPACE, notificationId);
+        mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId);
         mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(id);
 
         // Since we are about to go through the process of validating whether or not we can shut
@@ -844,8 +839,7 @@
         // the summary will take care of that for us.
         stopTrackingInProgressDownload(id, hasDownloadNotificationsInternal(notificationId));
         if (!hideSummaryNotificationIfNecessary(notificationId)) {
-            updateSummaryIcon(mContext, mNotificationManager, mNotificationManagerCompat,
-                    notificationId, null);
+            updateSummaryIcon(mContext, mNotificationManager, notificationId, null);
         }
     }
 
@@ -1127,7 +1121,7 @@
         // Process updating the summary notification first.  This has no impact on a specific
         // download.
         if (ACTION_DOWNLOAD_UPDATE_SUMMARY_ICON.equals(intent.getAction())) {
-            updateSummaryIcon(mContext, mNotificationManager, mNotificationManagerCompat, -1, null);
+            updateSummaryIcon(mContext, mNotificationManager, -1, null);
             hideSummaryNotificationIfNecessary(-1);
             return;
         }
@@ -1327,7 +1321,7 @@
 
     @VisibleForTesting
     void updateNotification(int id, Notification notification) {
-        mNotificationManagerCompat.notify(NOTIFICATION_NAMESPACE, id, notification);
+        mNotificationManager.notify(NOTIFICATION_NAMESPACE, id, notification);
     }
 
     private void updateNotification(int notificationId, Notification notification, ContentId id,
@@ -1340,7 +1334,7 @@
         } else {
             mDownloadSharedPreferenceHelper.removeSharedPreferenceEntry(id);
         }
-        updateSummaryIcon(mContext, mNotificationManager, mNotificationManagerCompat, -1,
+        updateSummaryIcon(mContext, mNotificationManager, -1,
                 new Pair<Integer, Notification>(notificationId, notification));
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
index 1fa96e9..9b0e578b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -208,6 +208,8 @@
         downloadManager.getAllDownloads(false);
         if (mShowOffTheRecord) downloadManager.getAllDownloads(true);
 
+        // Fetch all Offline Items from OfflineContentProvider (Pages, Background Fetches etc).
+        getAllOfflineItems();
         getOfflineContentProvider().addObserver(this);
 
         sDeletedFileTracker.incrementInstanceCount();
@@ -736,8 +738,7 @@
         return mSpaceDisplay;
     }
 
-    @Override
-    public void onItemsAvailable() {
+    private void getAllOfflineItems() {
         getOfflineContentProvider().getAllItems(offlineItems -> {
             for (OfflineItem item : offlineItems) {
                 if (item.isTransient) continue;
@@ -750,6 +751,11 @@
         });
     }
 
+    @Override
+    public void onItemsAvailable() {
+        // TODO(dimich): This signal is not used, remove from interface.
+    }
+
     private void recordOfflineItemCountHistograms() {
         int[] itemCounts = new int[OfflineItemFilter.FILTER_BOUNDARY];
         for (DownloadHistoryItemWrapper item : mOfflineItems) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
index ff0038b0..9d6b704 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
@@ -5,13 +5,13 @@
 package org.chromium.chrome.browser.media;
 
 import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.IBinder;
-import android.support.v4.app.NotificationManagerCompat;
 import android.util.SparseIntArray;
 
 import org.chromium.base.ContextUtils;
@@ -54,7 +54,7 @@
     private static final int MEDIATYPE_AUDIO_ONLY = 3;
     private static final int MEDIATYPE_SCREEN_CAPTURE = 4;
 
-    private NotificationManagerCompat mNotificationManagerCompat;
+    private NotificationManager mNotificationManager;
     private Context mContext;
     private SharedPreferences mSharedPreferences;
     private final SparseIntArray mNotifications = new SparseIntArray();
@@ -62,7 +62,8 @@
     @Override
     public void onCreate() {
         mContext = getApplicationContext();
-        mNotificationManagerCompat = NotificationManagerCompat.from(mContext);
+        mNotificationManager = (NotificationManager) mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
         mSharedPreferences = ContextUtils.getAppSharedPreferences();
         super.onCreate();
     }
@@ -117,8 +118,7 @@
         if (notificationIds == null) return;
         Iterator<String> iterator = notificationIds.iterator();
         while (iterator.hasNext()) {
-            mNotificationManagerCompat.cancel(
-                    NOTIFICATION_NAMESPACE, Integer.parseInt(iterator.next()));
+            mNotificationManager.cancel(NOTIFICATION_NAMESPACE, Integer.parseInt(iterator.next()));
         }
         SharedPreferences.Editor sharedPreferenceEditor = mSharedPreferences.edit();
         sharedPreferenceEditor.remove(MediaCaptureNotificationService.WEBRTC_NOTIFICATION_IDS);
@@ -150,7 +150,7 @@
      */
     private void destroyNotification(int notificationId) {
         if (doesNotificationExist(notificationId)) {
-            mNotificationManagerCompat.cancel(NOTIFICATION_NAMESPACE, notificationId);
+            mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId);
             mNotifications.delete(notificationId);
             updateSharedPreferencesEntry(notificationId, true);
         }
@@ -186,7 +186,7 @@
             if (mediaType == MEDIATYPE_SCREEN_CAPTURE) {
                 // Add a "Stop" button to the screen capture notification and turn the notification
                 // into a high priority one.
-                builder.setPriority(NotificationManagerCompat.IMPORTANCE_HIGH);
+                builder.setPriority(Notification.PRIORITY_HIGH);
                 builder.setVibrate(new long[0]);
                 builder.addAction(R.drawable.ic_stop_white_36dp,
                         mContext.getResources().getString(R.string.accessibility_stop),
@@ -201,7 +201,7 @@
         builder.setContentText(contentText.toString());
 
         Notification notification = builder.buildWithBigTextStyle(contentText.toString());
-        mNotificationManagerCompat.notify(NOTIFICATION_NAMESPACE, notificationId, notification);
+        mNotificationManager.notify(NOTIFICATION_NAMESPACE, notificationId, notification);
         mNotifications.put(notificationId, mediaType);
         updateSharedPreferencesEntry(notificationId, false);
         NotificationUmaTracker.getInstance().onNotificationShown(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
index aba992c..b4facb7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -219,8 +219,9 @@
      * previous WebAPK launch. Not recorded the first time that a WebAPK is launched.
      */
     public static void recordLaunchInterval(long intervalMs) {
-        RecordHistogram.recordCustomTimesHistogram("WebApk.LaunchInterval", intervalMs,
-                TimeUnit.HOURS.toMillis(1), TimeUnit.DAYS.toMillis(30), TimeUnit.MILLISECONDS, 50);
+        RecordHistogram.recordCustomCountHistogram("WebApk.LaunchInterval2",
+                (int) TimeUnit.MILLISECONDS.toMinutes(intervalMs), 30,
+                (int) TimeUnit.DAYS.toMinutes(90), 50);
     }
 
     /** Records to UMA the count of old "WebAPK update request" files. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
index 4717ee79..92d57e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.notifications;
 
+import android.annotation.TargetApi;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -745,6 +746,7 @@
      * because earlier versions were subject to a race condition briefly after showing or closing a
      * notification, during which, this data would be incorrect.
      */
+    @TargetApi(Build.VERSION_CODES.O)
     @CalledByNative
     private String[] getActiveNotificationsIds() {
         assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
index 4c7f58c6..d1a4d3e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
@@ -46,7 +46,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
+import java.nio.charset.Charset;
 
 /**
  * The "Save passwords" screen in Settings, which allows the user to enable or disable password
@@ -302,7 +302,7 @@
         }
         tempFile.deleteOnExit();
         try (BufferedWriter tempWriter = new BufferedWriter(new OutputStreamWriter(
-                     new FileOutputStream(tempFile), StandardCharsets.UTF_8))) {
+                     new FileOutputStream(tempFile), Charset.forName("UTF-8")))) {
             tempWriter.write(serializedPasswords);
         } catch (IOException e) {
             // TODO(crbug.com/788701): Change e.getMessage to an appropriate error, following the
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationManager.java
index 29215737..59b932f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationManager.java
@@ -5,12 +5,12 @@
 package org.chromium.chrome.browser.webapps;
 
 import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.Intent;
-import android.support.v4.app.NotificationManagerCompat;
 
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.blink_public.platform.WebDisplayMode;
@@ -56,7 +56,8 @@
             return;
         }
 
-        NotificationManagerCompat nm = NotificationManagerCompat.from(this.mWebappActivity);
+        NotificationManager nm = (NotificationManager) mWebappActivity.getSystemService(
+                Context.NOTIFICATION_SERVICE);
         nm.notify(NotificationConstants.NOTIFICATION_ID_WEBAPP_ACTIONS, createNotification());
         NotificationUmaTracker.getInstance().onNotificationShown(
                 NotificationUmaTracker.WEBAPP_ACTIONS,
@@ -86,7 +87,7 @@
                 .setShowWhen(false)
                 .setAutoCancel(false)
                 .setOngoing(true)
-                .setPriority(NotificationManagerCompat.IMPORTANCE_MIN)
+                .setPriority(Notification.PRIORITY_MIN)
                 .setContentIntent(focusIntent)
                 .addAction(R.drawable.ic_share_white_24dp,
                         mWebappActivity.getResources().getString(R.string.share), shareIntent)
@@ -98,7 +99,8 @@
 
     public void cancelNotification() {
         if (!isEnabled()) return;
-        NotificationManagerCompat nm = NotificationManagerCompat.from(this.mWebappActivity);
+        NotificationManager nm = (NotificationManager) mWebappActivity.getSystemService(
+                Context.NOTIFICATION_SERVICE);
         nm.cancel(NotificationConstants.NOTIFICATION_ID_WEBAPP_ACTIONS);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
index ec8525b6..af7a6bd5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java
@@ -193,7 +193,7 @@
     public void testLaunchIntervalHistogramRecordedOnSecondLaunch() throws Exception {
         mNativeLibraryTestRule.loadNativeLibraryNoBrowserProcess();
 
-        final String histogramName = "WebApk.LaunchInterval";
+        final String histogramName = "WebApk.LaunchInterval2";
         final String packageName = "org.chromium.webapk";
 
         WebappDataStorage storage =
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index 891d822..5f43d02 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -6,7 +6,6 @@
 
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
-#include "base/process/process.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_main_delegate.h"
@@ -129,9 +128,5 @@
 
   int rv = content::ContentMain(params);
 
-  // Terminate process / all threads at once; avoiding static uninitialization
-  // problems (https://crbug.com/800808).
-  base::Process::TerminateCurrentProcessImmediately(rv);
-
   return rv;
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 3737029..dcdbaef 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9832,9 +9832,21 @@
       </if>
 
       <!-- High-contrast mode. -->
-      <message name="IDS_HIGH_CONTRAST_NOTIFICATION"
-               desc="Text that explains that the user is using Windows High-Contrast mode, so they may be interested in a high-contrast extension or a dark theme. Note to translators: this is the name of a feature in Windows, so please try to find the correct name of that feature in your region.">
-        You have High Contrast mode enabled. Would you like to install our High Contrast extension and a dark theme?
+      <if expr="not use_titlecase">
+        <message name="IDS_HIGH_CONTRAST_TITLE"
+                 desc="Text for the dialog asking if the user may be interested in a High-Contrast extension or a dark theme. Note to translators: this is the name of a feature in Windows, so please try to find the correct name of that feature in your region.">
+          Browse the web in high contrast mode
+        </message>
+      </if>
+      <if expr="use_titlecase">
+        <message name="IDS_HIGH_CONTRAST_TITLE"
+                 desc="Text for the dialog asking if the user may be interested in a High-Contrast extension or a dark theme. Note to translators: this is the name of a feature in Windows, so please try to find the correct name of that feature in your region.">
+          Browse the Web in High Contrast Mode
+        </message>
+      </if>
+      <message name="IDS_HIGH_CONTRAST_HEADER"
+               desc="Section header for list of extensions or themes to try in conjunction with the High Contrast mode">
+        Try:
       </message>
       <message name="IDS_HIGH_CONTRAST_EXT"
                desc="The title of a link that will open the Chrome Web Store with a High Contrast extension the user can install.">
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 23b287d..64428b89 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
@@ -561,7 +562,10 @@
 
 void ArcSettingsServiceImpl::SyncReportingConsent() const {
   bool consent = false;
-  CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref, &consent);
+  // Public session user never saw the consent even if the admin forced
+  // the pref by a policy.
+  if (!profiles::IsPublicSession())
+    CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref, &consent);
   base::DictionaryValue extras;
   extras.SetBoolean("reportingConsent", consent);
   SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_REPORTING_CONSENT",
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_factory.h b/chrome/browser/chromeos/file_manager/volume_manager_factory.h
index aac0a04..23269c4 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_factory.h
+++ b/chrome/browser/chromeos/file_manager/volume_manager_factory.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/macros.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
 #ifndef CHROME_BROWSER_CHROMEOS_FILE_MANAGER_VOLUME_MANAGER_FACTORY_H_
 #define CHROME_BROWSER_CHROMEOS_FILE_MANAGER_VOLUME_MANAGER_FACTORY_H_
 
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
 namespace base {
 template <typename T>
 struct DefaultSingletonTraits;
diff --git a/chrome/browser/chromeos/printing/printer_detector_test_util.h b/chrome/browser/chromeos/printing/printer_detector_test_util.h
index 19773b9..12b59db 100644
--- a/chrome/browser/chromeos/printing/printer_detector_test_util.h
+++ b/chrome/browser/chromeos/printing/printer_detector_test_util.h
@@ -1,7 +1,10 @@
-// Copyright 2017 the Chromium Authors. All rights reserved.
+// 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_PRINTING_PRINTER_DETECTOR_TEST_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_DETECTOR_TEST_UTIL_H_
+
 #include "chrome/browser/chromeos/printing/printer_detector.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
@@ -57,3 +60,5 @@
 
 }  // namespace
 }  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_DETECTOR_TEST_UTIL_H_
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.cc b/chrome/browser/chromeos/smb_client/smb_file_system.cc
index 1aa75b5b..e9779f9 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.cc
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.cc
@@ -411,9 +411,9 @@
 void SmbFileSystem::HandleRequestReadDirectoryCallback(
     const storage::AsyncFileUtil::ReadDirectoryCallback& callback,
     smbprovider::ErrorType error,
-    const smbprovider::DirectoryEntryList& entries) const {
+    const smbprovider::DirectoryEntryListProto& entries) const {
   storage::AsyncFileUtil::EntryList entry_list;
-  for (const smbprovider::DirectoryEntry& entry : entries.entries()) {
+  for (const smbprovider::DirectoryEntryProto& entry : entries.entries()) {
     entry_list.emplace_back(entry.name(), MapEntryType(entry.is_directory()));
   }
   // TODO(allenvic): Implement has_more (crbug.com/796246).
@@ -424,7 +424,7 @@
     ProvidedFileSystemInterface::MetadataFieldMask fields,
     const ProvidedFileSystemInterface::GetMetadataCallback& callback,
     smbprovider::ErrorType error,
-    const smbprovider::DirectoryEntry& entry) const {
+    const smbprovider::DirectoryEntryProto& entry) const {
   if (error != smbprovider::ERROR_OK) {
     callback.Run(std::unique_ptr<file_system_provider::EntryMetadata>(),
                  TranslateError(error));
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.h b/chrome/browser/chromeos/smb_client/smb_file_system.h
index 9e2c9ed..6ad45c0 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.h
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.h
@@ -185,13 +185,13 @@
   void HandleRequestReadDirectoryCallback(
       const storage::AsyncFileUtil::ReadDirectoryCallback& callback,
       smbprovider::ErrorType error,
-      const smbprovider::DirectoryEntryList& entries) const;
+      const smbprovider::DirectoryEntryListProto& entries) const;
 
   void HandleRequestGetMetadataEntryCallback(
       ProvidedFileSystemInterface::MetadataFieldMask fields,
       const ProvidedFileSystemInterface::GetMetadataCallback& callback,
       smbprovider::ErrorType error,
-      const smbprovider::DirectoryEntry& entry) const;
+      const smbprovider::DirectoryEntryProto& entry) const;
 
   void HandleRequestOpenFileCallback(const OpenFileCallback& callback,
                                      smbprovider::ErrorType error,
diff --git a/chrome/browser/extensions/content_capabilities_browsertest.cc b/chrome/browser/extensions/content_capabilities_browsertest.cc
index 9ec40f4..439877a5 100644
--- a/chrome/browser/extensions/content_capabilities_browsertest.cc
+++ b/chrome/browser/extensions/content_capabilities_browsertest.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
@@ -19,6 +20,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/crx_file/id_util.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/manifest_handlers/content_capabilities_handler.h"
@@ -200,9 +202,14 @@
   // script without a user gesture.
   EXPECT_TRUE(
       CanWriteClipboard(extension.get(), GetTestURLFor("bar.example.com")));
-  EXPECT_TRUE(
-      CanWriteClipboardInAboutBlankFrame(extension.get(),
-                                          GetTestURLFor("bar.example.com")));
+  if (!base::FeatureList::IsEnabled(features::kUserActivationV2)) {
+    EXPECT_TRUE(CanWriteClipboardInAboutBlankFrame(
+        extension.get(), GetTestURLFor("bar.example.com")));
+  } else {
+    // In UserActivationV2, acitvation doesn't propagate to a child frame.
+    EXPECT_FALSE(CanWriteClipboardInAboutBlankFrame(
+        extension.get(), GetTestURLFor("bar.example.com")));
+  }
 
   EXPECT_FALSE(
       CanReadClipboard(extension.get(), GetTestURLFor("foo.example.com")));
diff --git a/chrome/browser/extensions/extension_dom_clipboard_apitest.cc b/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
index 02706bd..09587df 100644
--- a/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
+++ b/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -120,7 +122,12 @@
   // the no user gesture case without a lot of code duplication.
   EXPECT_TRUE(ExecuteCopyInSelectedTab()) << message_;
   EXPECT_FALSE(ExecutePasteInSelectedTab()) << message_;
-  EXPECT_TRUE(ExecuteCommandInIframeInSelectedTab("copy")) << message_;
+
+  if (!base::FeatureList::IsEnabled(features::kUserActivationV2)) {
+    EXPECT_TRUE(ExecuteCommandInIframeInSelectedTab("copy")) << message_;
+  } else {
+    // In UserActivationV2, acitvation doesn't propagate to a child frame.
+    EXPECT_FALSE(ExecuteCommandInIframeInSelectedTab("copy")) << message_;
+  }
   EXPECT_FALSE(ExecuteCommandInIframeInSelectedTab("paste")) << message_;
 }
-
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor.h b/chrome/browser/metrics/chrome_metrics_service_accessor.h
index 076a9777..116a7fe 100644
--- a/chrome/browser/metrics/chrome_metrics_service_accessor.h
+++ b/chrome/browser/metrics/chrome_metrics_service_accessor.h
@@ -142,8 +142,11 @@
   FRIEND_TEST_ALL_PREFIXES(ChromeMetricsServiceAccessorTest,
                            MetricsReportingEnabled);
 
-  // Returns true if metrics reporting is enabled. |local_state| is the
-  // PrefService for local state. Typically this comes from
+  // Returns true if metrics reporting is enabled. This does NOT necessary mean
+  // that it is active as configuration may prevent it on some devices (i.e.
+  // the "MetricsReporting" field trial that controls sampling). To include
+  // that, call: metrics_services_manager->IsReportingEnabled()
+  // |local_state| is the PrefService for local state. Typically this comes from
   // g_browser_process->local_state(), but during startup |g_browser_process|
   // may not have been created, in which case it's the local state that will
   // eventually be assigned to |g_browser_process|.
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 7e905f89..8251789d 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -600,8 +600,7 @@
       base::MakeUnique<metrics::ScreenInfoMetricsProvider>());
 
   metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider(
-      ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(
-          local_state)));
+      metrics_state_manager_->IsMetricsReportingEnabled()));
 
   metrics_service_->RegisterMetricsProvider(
       base::MakeUnique<metrics::DriveMetricsProvider>(
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 6521e763..506155c 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -49,7 +49,6 @@
       hung_processing_complete_(false),
       unresponsive_threshold_(params.unresponsive_threshold),
       crash_on_hang_(params.crash_on_hang),
-      live_threads_threshold_(params.live_threads_threshold),
       weak_ptr_factory_(this) {
   DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
   Initialize();
@@ -301,12 +300,9 @@
   // Record how many watched threads are not responding.
   unresponsive_count_histogram_->Add(unresponding_thread_count);
 
-  // Crash the browser if the watched thread is to be crashed on hang and if the
-  // number of other threads responding is less than or equal to
-  // live_threads_threshold_ and at least one other thread is responding.
-  if (crash_on_hang_ &&
-      responding_thread_count > 0 &&
-      responding_thread_count <= live_threads_threshold_) {
+  // Crash the browser if the watched thread is to be crashed on hang and at
+  // least one other thread is responding.
+  if (crash_on_hang_ && responding_thread_count > 0) {
     static bool crashed_once = false;
     if (!crashed_once) {
       crashed_once = true;
@@ -334,23 +330,9 @@
 const int ThreadWatcherList::kUnresponsiveSeconds = 2;
 // static
 const int ThreadWatcherList::kUnresponsiveCount = 9;
-// static, configured high to catch single thread hangs
-// TODO(gab): Clean this up, https://crbug.com/804345
-const int ThreadWatcherList::kLiveThreadsThreshold = BrowserThread::ID_COUNT;
 // static, non-const for tests.
 int ThreadWatcherList::g_initialize_delay_seconds = 120;
 
-ThreadWatcherList::CrashDataThresholds::CrashDataThresholds(
-    uint32_t live_threads_threshold,
-    uint32_t unresponsive_threshold)
-    : live_threads_threshold(live_threads_threshold),
-      unresponsive_threshold(unresponsive_threshold) {}
-
-ThreadWatcherList::CrashDataThresholds::CrashDataThresholds()
-    : live_threads_threshold(kLiveThreadsThreshold),
-      unresponsive_threshold(kUnresponsiveCount) {
-}
-
 // static
 void ThreadWatcherList::StartWatchingAll(
     const base::CommandLine& command_line) {
@@ -470,12 +452,10 @@
     // Default to crashing the browser if UI or IO threads are not responsive
     // except in stable channel.
     crash_on_hang_thread_names =
-        base::StringPrintf("UI:%d:%d,IO:%d:%d", kLiveThreadsThreshold,
-                           crash_seconds, kLiveThreadsThreshold, crash_seconds);
+        base::StringPrintf("UI:%d,IO:%d", crash_seconds, crash_seconds);
   }
 
   ParseCommandLineCrashOnHangThreads(crash_on_hang_thread_names,
-                                     kLiveThreadsThreshold,
                                      crash_seconds,
                                      crash_on_hang_threads);
 }
@@ -483,32 +463,32 @@
 // static
 void ThreadWatcherList::ParseCommandLineCrashOnHangThreads(
     const std::string& crash_on_hang_thread_names,
-    uint32_t default_live_threads_threshold,
     uint32_t default_crash_seconds,
     CrashOnHangThreadMap* crash_on_hang_threads) {
   base::StringTokenizer tokens(crash_on_hang_thread_names, ",");
   while (tokens.GetNext()) {
     std::vector<base::StringPiece> values = base::SplitStringPiece(
         tokens.token_piece(), ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+    // Accepted format for each thread is "THREADNAME" or "THREADNAME:18". The
+    // optional integer is the number of seconds a thread must remain
+    // unresponsive before considering it as hung.
+    CHECK_LE(values.size(), 2U);
+
     std::string thread_name = values[0].as_string();
 
-    uint32_t live_threads_threshold = default_live_threads_threshold;
     uint32_t crash_seconds = default_crash_seconds;
     if (values.size() >= 2 &&
-        (!base::StringToUint(values[1], &live_threads_threshold))) {
+        (!base::StringToUint(values[1], &crash_seconds))) {
       continue;
     }
-    if (values.size() >= 3 &&
-        (!base::StringToUint(values[2], &crash_seconds))) {
-      continue;
-    }
-    uint32_t unresponsive_threshold = static_cast<uint32_t>(
-        ceil(static_cast<float>(crash_seconds) / kUnresponsiveSeconds));
 
-    CrashDataThresholds crash_data(live_threads_threshold,
-                                   unresponsive_threshold);
+    const UnresponsiveCountThreshold unresponsive_threshold =
+        static_cast<UnresponsiveCountThreshold>(
+            ceil(static_cast<float>(crash_seconds) / kUnresponsiveSeconds));
+
     // Use the last specifier.
-    (*crash_on_hang_threads)[thread_name] = crash_data;
+    (*crash_on_hang_threads)[thread_name] = unresponsive_threshold;
   }
 }
 
@@ -566,28 +546,21 @@
     const std::string& thread_name,
     const base::TimeDelta& sleep_time,
     const base::TimeDelta& unresponsive_time,
-    uint32_t unresponsive_threshold,
+    UnresponsiveCountThreshold unresponsive_threshold,
     const CrashOnHangThreadMap& crash_on_hang_threads) {
   DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
 
   CrashOnHangThreadMap::const_iterator it =
       crash_on_hang_threads.find(thread_name);
   bool crash_on_hang = false;
-  uint32_t live_threads_threshold = 0;
   if (it != crash_on_hang_threads.end()) {
     crash_on_hang = true;
-    live_threads_threshold = it->second.live_threads_threshold;
-    unresponsive_threshold = it->second.unresponsive_threshold;
+    unresponsive_threshold = it->second;
   }
 
-  ThreadWatcher::StartWatching(
-      ThreadWatcher::WatchingParams(thread_id,
-                                    thread_name,
-                                    sleep_time,
-                                    unresponsive_time,
-                                    unresponsive_threshold,
-                                    crash_on_hang,
-                                    live_threads_threshold));
+  ThreadWatcher::StartWatching(ThreadWatcher::WatchingParams(
+      thread_id, thread_name, sleep_time, unresponsive_time,
+      unresponsive_threshold, crash_on_hang));
 }
 
 // static
diff --git a/chrome/browser/metrics/thread_watcher.h b/chrome/browser/metrics/thread_watcher.h
index 69451fa6..4101b32 100644
--- a/chrome/browser/metrics/thread_watcher.h
+++ b/chrome/browser/metrics/thread_watcher.h
@@ -26,18 +26,15 @@
 //   after which watched (IO) thread is considered as not responsive.
 //   |crash_on_hang| specifies if we want to crash the browser when the watched
 //   (IO) thread has become sufficiently unresponsive, while other threads are
-//   sufficiently responsive. |live_threads_threshold| specifies the number of
-//   browser threads that are to be responsive when we want to crash the browser
-//   because of hung watched (IO) thread.
+//   sufficiently responsive.
 //
 //   base::TimeDelta sleep_time = base::TimeDelta::FromSeconds(5);
 //   base::TimeDelta unresponsive_time = base::TimeDelta::FromSeconds(10);
 //   uint32_t unresponsive_threshold = ThreadWatcherList::kUnresponsiveCount;
 //   bool crash_on_hang = false;
-//   uint32_t live_threads_threshold = ThreadWatcherList::kLiveThreadsThreshold;
 //   ThreadWatcher::StartWatching(
 //       BrowserThread::IO, "IO", sleep_time, unresponsive_time,
-//       unresponsive_threshold, crash_on_hang, live_threads_threshold);
+//       unresponsive_threshold, crash_on_hang);
 
 #ifndef CHROME_BROWSER_METRICS_THREAD_WATCHER_H_
 #define CHROME_BROWSER_METRICS_THREAD_WATCHER_H_
@@ -84,22 +81,19 @@
     base::TimeDelta unresponsive_time;
     uint32_t unresponsive_threshold;
     bool crash_on_hang;
-    uint32_t live_threads_threshold;
 
     WatchingParams(const content::BrowserThread::ID& thread_id_in,
                    const std::string& thread_name_in,
                    const base::TimeDelta& sleep_time_in,
                    const base::TimeDelta& unresponsive_time_in,
                    uint32_t unresponsive_threshold_in,
-                   bool crash_on_hang_in,
-                   uint32_t live_threads_threshold_in)
+                   bool crash_on_hang_in)
         : thread_id(thread_id_in),
           thread_name(thread_name_in),
           sleep_time(sleep_time_in),
           unresponsive_time(unresponsive_time_in),
           unresponsive_threshold(unresponsive_threshold_in),
-          crash_on_hang(crash_on_hang_in),
-          live_threads_threshold(live_threads_threshold_in) {}
+          crash_on_hang(crash_on_hang_in) {}
   };
 
   virtual ~ThreadWatcher();
@@ -112,11 +106,8 @@
   // is responsive or not. The watched thread is considered unresponsive if it
   // hasn't responded with a pong message for |unresponsive_threshold| number of
   // ping messages. |crash_on_hang| specifies if browser should be crashed when
-  // the watched thread is unresponsive. |live_threads_threshold| specifies the
-  // number of browser threads that are to be responsive when we want to crash
-  // the browser and watched thread has become sufficiently unresponsive. It
-  // will register that ThreadWatcher object and activate the thread watching of
-  // the given thread_id.
+  // the watched thread is unresponsive. It will register that ThreadWatcher
+  // object and activate the thread watching of the given thread_id.
   static void StartWatching(const WatchingParams& params);
 
   // Return the |thread_id_| of the thread being watched.
@@ -290,11 +281,6 @@
   // responsive.
   bool crash_on_hang_;
 
-  // This specifies the number of browser threads that are to be responsive when
-  // we want to crash the browser because watched thread has become sufficiently
-  // unresponsive.
-  uint32_t live_threads_threshold_;
-
   // We use this factory to create callback tasks for ThreadWatcher object. We
   // use this during ping-pong messaging between WatchDog thread and watched
   // thread.
@@ -312,19 +298,12 @@
   // A map from BrowserThread to the actual instances.
   typedef std::map<content::BrowserThread::ID, ThreadWatcher*> RegistrationList;
 
-  // A map from thread names (UI, IO, etc) to |CrashDataThresholds|.
-  // |live_threads_threshold| specifies the maximum number of browser threads
-  // that have to be responsive when we want to crash the browser because of
-  // hung watched thread. This threshold allows us to either look for a system
-  // deadlock, or look for a solo hung thread. A small live_threads_threshold
-  // looks for a broad deadlock (few browser threads left running), and a large
-  // threshold looks for a single hung thread (this in only appropriate for a
-  // thread that *should* never have much jank, such as the IO).
+  // A map from thread names (UI/IO) to |UnresponsiveCountThreshold|.
   //
-  // |unresponsive_threshold| specifies the number of unanswered ping messages
-  // after which watched (UI, IO, etc) thread is considered as not responsive.
-  // We translate "time" (given in seconds) into a number of pings. As a result,
-  // we only declare a thread unresponsive when a lot of "time" has passed (many
+  // UnresponsiveCountThreshold specifies the number of unanswered ping messages
+  // after which watched (UI/IO) thread is considered as not responsive. We
+  // translate "time" (given in seconds) into a number of pings. As a result, we
+  // only declare a thread unresponsive when a lot of "time" has passed (many
   // pings), and yet our pinging thread has continued to process messages (so we
   // know the entire PC is not hung). Set this number higher to crash less
   // often, and lower to crash more often.
@@ -335,52 +314,17 @@
   // watched, as they provide the system context of how hung *other* threads
   // are.
   //
-  // ThreadWatcher monitors five browser threads (i.e., UI, IO, DB, FILE,
-  // and CACHE). Out of the 5 threads, any subset may be watched, to potentially
-  // cause a crash. The following example's command line causes exactly 3
-  // threads to be watched.
+  // ThreadWatcher monitors UI and IO browser threads.
   //
-  // The example command line argument consists of "UI:3:18,IO:3:18,FILE:5:90".
-  // In that string, the first parameter specifies the thread_id: UI, IO or
-  // FILE. The second parameter specifies |live_threads_threshold|. For UI and
-  // IO threads, we would crash if the number of threads responding is less than
-  // or equal to 3. The third parameter specifies the unresponsive threshold
-  // seconds. This number is used to calculate |unresponsive_threshold|. In this
-  // example for UI and IO threads, we would crash if those threads don't
-  // respond for 18 seconds (or 9 unanswered ping messages) and for FILE thread,
-  // crash_seconds is set to 90 seconds (or 45 unanswered ping messages).
-  //
-  // The following examples explain how the data in |CrashDataThresholds|
-  // controls the crashes.
-  //
-  // Example 1: If the |live_threads_threshold| value for "IO" was 3 and
-  // unresponsive threshold seconds is 18 (or |unresponsive_threshold| is 9),
-  // then we would crash if the IO thread was hung (9 unanswered ping messages)
-  // and if at least one thread is responding and total responding threads is
-  // less than or equal to 3 (this thread, plus at least one other thread is
-  // unresponsive). We would not crash if none of the threads are responding, as
-  // we'd assume such large hang counts mean that the system is generally
-  // unresponsive.
-  // Example 2: If the |live_threads_threshold| value for "UI" was any number
-  // higher than 6 and unresponsive threshold seconds is 18 (or
-  // |unresponsive_threshold| is 9), then we would always crash if the UI thread
-  // was hung (9 unanswered ping messages), no matter what the other threads are
-  // doing.
-  // Example 3: If the |live_threads_threshold| value of "FILE" was 5 and
-  // unresponsive threshold seconds is 90 (or |unresponsive_threshold| is 45),
-  // then we would only crash if the FILE thread was the ONLY hung thread
-  // (because we watch 6 threads). If there was another unresponsive thread, we
-  // would not consider this a problem worth crashing for. FILE thread would be
-  // considered as hung if it didn't respond for 45 ping messages.
-  struct CrashDataThresholds {
-    CrashDataThresholds(uint32_t live_threads_threshold,
-                        uint32_t unresponsive_threshold);
-    CrashDataThresholds();
-
-    uint32_t live_threads_threshold;
-    uint32_t unresponsive_threshold;
-  };
-  typedef std::map<std::string, CrashDataThresholds> CrashOnHangThreadMap;
+  // The example command line argument consists of "UI:18,IO:18". In that
+  // string, the first parameter specifies the thread_id: UI or IO. The second
+  // parameter specifies the unresponsive threshold seconds. This number is used
+  // to calculate the UnresponsiveCountThreshold. In this example for UI and IO
+  // threads, we would crash if those threads don't respond for 18 seconds (i.e.
+  // 9 unanswered ping messages with a 2 seconds timeout).
+  using UnresponsiveCountThreshold = uint32_t;
+  typedef std::map<std::string, UnresponsiveCountThreshold>
+      CrashOnHangThreadMap;
 
   // This method posts a task on WatchDogThread to start watching all browser
   // threads.
@@ -414,7 +358,6 @@
                            ApplicationStatusNotification);
   FRIEND_TEST_ALL_PREFIXES(ThreadWatcherListTest, Restart);
   FRIEND_TEST_ALL_PREFIXES(ThreadWatcherTest, ThreadNamesOnlyArgs);
-  FRIEND_TEST_ALL_PREFIXES(ThreadWatcherTest, ThreadNamesAndLiveThresholdArgs);
   FRIEND_TEST_ALL_PREFIXES(ThreadWatcherTest, CrashOnHangThreadsAllArgs);
 
   // This singleton holds the global list of registered ThreadWatchers.
@@ -433,12 +376,9 @@
   // Parses the argument |crash_on_hang_thread_names| and creates
   // |crash_on_hang_threads| map of |crash_on_hang| thread's names to
   // |CrashDataThresholds|. If |crash_on_hang_thread_names| doesn't specify
-  // |live_threads_threshold|, then it uses |default_live_threads_threshold| as
-  // the value. If |crash_on_hang_thread_names| doesn't specify |crash_seconds|,
-  // then it uses |default_crash_seconds| as the value.
+  // |crash_seconds|, then it uses |default_crash_seconds| as the value.
   static void ParseCommandLineCrashOnHangThreads(
       const std::string& crash_on_hang_thread_names,
-      uint32_t default_live_threads_threshold,
       uint32_t default_crash_seconds,
       CrashOnHangThreadMap* crash_on_hang_threads);
 
@@ -489,9 +429,6 @@
   // Default values for |unresponsive_threshold|.
   static const int kUnresponsiveCount;
 
-  // Default values for |live_threads_threshold|.
-  static const int kLiveThreadsThreshold;
-
   // Default value for the delay until |InitializeAndStartWatching| is called.
   // Non-const for tests.
   static int g_initialize_delay_seconds;
diff --git a/chrome/browser/metrics/thread_watcher_unittest.cc b/chrome/browser/metrics/thread_watcher_unittest.cc
index 271b96c..0b546dd 100644
--- a/chrome/browser/metrics/thread_watcher_unittest.cc
+++ b/chrome/browser/metrics/thread_watcher_unittest.cc
@@ -80,9 +80,12 @@
                       const std::string thread_name,
                       const TimeDelta& sleep_time,
                       const TimeDelta& unresponsive_time)
-      : ThreadWatcher(WatchingParams(thread_id, thread_name, sleep_time,
-                      unresponsive_time, ThreadWatcherList::kUnresponsiveCount,
-                      true, ThreadWatcherList::kLiveThreadsThreshold)),
+      : ThreadWatcher(WatchingParams(thread_id,
+                                     thread_name,
+                                     sleep_time,
+                                     unresponsive_time,
+                                     ThreadWatcherList::kUnresponsiveCount,
+                                     true)),
         state_changed_(&custom_lock_),
         thread_watcher_state_(INITIALIZED),
         wait_state_(UNINITIALIZED),
@@ -92,8 +95,7 @@
         success_response_(0),
         failed_response_(0),
         saved_ping_time_(base::TimeTicks::Now()),
-        saved_ping_sequence_number_(0) {
-  }
+        saved_ping_sequence_number_(0) {}
 
   State UpdateState(State new_state) {
     State old_state;
@@ -243,13 +245,13 @@
 
 class ThreadWatcherTest : public ::testing::Test {
  public:
-  static const TimeDelta kSleepTime;
-  static const TimeDelta kUnresponsiveTime;
-  static const char kIOThreadName[];
-  static const char kUIThreadName[];
-  static const char kCrashOnHangThreadNames[];
-  static const char kThreadNamesAndLiveThreshold[];
-  static const char kCrashOnHangThreadData[];
+  static constexpr TimeDelta kSleepTime = TimeDelta::FromMilliseconds(50);
+  static constexpr TimeDelta kUnresponsiveTime =
+      TimeDelta::FromMilliseconds(500);
+  static constexpr char kIOThreadName[] = "IO";
+  static constexpr char kUIThreadName[] = "UI";
+  static constexpr char kCrashOnHangThreadNames[] = "UI,IO";
+  static constexpr char kCrashOnHangThreadData[] = "UI:12,IO:12";
 
   CustomThreadWatcher* io_watcher_;
   CustomThreadWatcher* ui_watcher_;
@@ -336,16 +338,13 @@
   DISALLOW_COPY_AND_ASSIGN(ThreadWatcherTest);
 };
 
-// Define static constants.
-const TimeDelta ThreadWatcherTest::kSleepTime = TimeDelta::FromMilliseconds(50);
-const TimeDelta ThreadWatcherTest::kUnresponsiveTime =
-    TimeDelta::FromMilliseconds(500);
-const char ThreadWatcherTest::kIOThreadName[] = "IO";
-const char ThreadWatcherTest::kUIThreadName[] = "UI";
-const char ThreadWatcherTest::kCrashOnHangThreadNames[] = "UI,IO";
-const char ThreadWatcherTest::kThreadNamesAndLiveThreshold[] = "UI:4,IO:4";
-const char ThreadWatcherTest::kCrashOnHangThreadData[] =
-    "UI:5:12,IO:5:12,FILE:5:12";
+// Declare storage for ThreadWatcherTest's static constants.
+constexpr TimeDelta ThreadWatcherTest::kSleepTime;
+constexpr TimeDelta ThreadWatcherTest::kUnresponsiveTime;
+constexpr char ThreadWatcherTest::kIOThreadName[];
+constexpr char ThreadWatcherTest::kUIThreadName[];
+constexpr char ThreadWatcherTest::kCrashOnHangThreadNames[];
+constexpr char ThreadWatcherTest::kCrashOnHangThreadData[];
 
 TEST_F(ThreadWatcherTest, ThreadNamesOnlyArgs) {
   // Setup command_line arguments.
@@ -373,41 +372,7 @@
         crash_on_hang_threads.find(thread_name);
     bool crash_on_hang = (it != crash_on_hang_threads.end());
     EXPECT_TRUE(crash_on_hang);
-    EXPECT_LT(0u, it->second.live_threads_threshold);
-    EXPECT_LT(0u, it->second.unresponsive_threshold);
-  }
-}
-
-TEST_F(ThreadWatcherTest, ThreadNamesAndLiveThresholdArgs) {
-  // Setup command_line arguments.
-  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
-  command_line.AppendSwitchASCII(switches::kCrashOnHangThreads,
-                                 kThreadNamesAndLiveThreshold);
-
-  // Parse command_line arguments.
-  ThreadWatcherList::CrashOnHangThreadMap crash_on_hang_threads;
-  uint32_t unresponsive_threshold;
-  ThreadWatcherList::ParseCommandLine(command_line,
-                                      &unresponsive_threshold,
-                                      &crash_on_hang_threads);
-
-  // Verify the data.
-  base::CStringTokenizer tokens(
-      kThreadNamesAndLiveThreshold,
-      kThreadNamesAndLiveThreshold +
-          (arraysize(kThreadNamesAndLiveThreshold) - 1),
-      ",");
-  while (tokens.GetNext()) {
-    std::vector<base::StringPiece> values = base::SplitStringPiece(
-        tokens.token_piece(), ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-    std::string thread_name = values[0].as_string();
-
-    ThreadWatcherList::CrashOnHangThreadMap::iterator it =
-        crash_on_hang_threads.find(thread_name);
-    bool crash_on_hang = (it != crash_on_hang_threads.end());
-    EXPECT_TRUE(crash_on_hang);
-    EXPECT_EQ(4u, it->second.live_threads_threshold);
-    EXPECT_LT(0u, it->second.unresponsive_threshold);
+    EXPECT_LT(0u, it->second);
   }
 }
 
@@ -439,10 +404,7 @@
     bool crash_on_hang = (it != crash_on_hang_threads.end());
     EXPECT_TRUE(crash_on_hang);
 
-    uint32_t crash_live_threads_threshold = it->second.live_threads_threshold;
-    EXPECT_EQ(5u, crash_live_threads_threshold);
-
-    uint32_t crash_unresponsive_threshold = it->second.unresponsive_threshold;
+    uint32_t crash_unresponsive_threshold = it->second;
     uint32_t crash_on_unresponsive_seconds =
         ThreadWatcherList::kUnresponsiveSeconds * crash_unresponsive_threshold;
     EXPECT_EQ(12u, crash_on_unresponsive_seconds);
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 3fee001..4002ea6 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/ntp_snippets/dependent_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/suggestions/image_decoder_impl.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
@@ -339,8 +338,8 @@
   }
 
   PrefService* pref_service = profile->GetPrefs();
-  identity::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForProfile(profile);
+  OAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
   UrlLanguageHistogram* language_histogram =
       UrlLanguageHistogramFactory::GetForBrowserContext(profile);
 
@@ -376,7 +375,8 @@
   }
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
   auto suggestions_fetcher = base::MakeUnique<RemoteSuggestionsFetcherImpl>(
-      identity_manager, request_context, pref_service, language_histogram,
+      signin_manager, token_service, request_context, pref_service,
+      language_histogram,
       base::Bind(
           &data_decoder::SafeJsonParser::Parse,
           content::ServiceManagerConnection::GetForProcess()->GetConnector()),
@@ -454,7 +454,6 @@
           BrowserContextDependencyManager::GetInstance()) {
   DependsOn(BookmarkModelFactory::GetInstance());
   DependsOn(HistoryServiceFactory::GetInstance());
-  DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(LargeIconServiceFactory::GetInstance());
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
   DependsOn(OfflinePageModelFactory::GetInstance());
diff --git a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
index 8cc47fcd..2854fac 100644
--- a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h"
 
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
@@ -119,10 +121,12 @@
   if (authStatus == ChildAccountService::AuthState::PENDING)
     return content::NavigationThrottle::DEFER;
 
-#if !defined(OS_ANDROID)
-  // TODO(bauerb): Show a reauthentication dialog.
-  return content::NavigationThrottle::CANCEL_AND_IGNORE;
-#else
+#if defined(OS_CHROMEOS)
+  // A credentials re-mint is already underway when we reach here (Mirror
+  // account reconciliation). Nothing to do here except block the navigation
+  // while re-minting is underway.
+  return content::NavigationThrottle::DEFER;
+#elif defined(OS_ANDROID)
   if (!has_shown_reauth_) {
     has_shown_reauth_ = true;
 
@@ -139,6 +143,12 @@
                    weak_ptr_factory_.GetWeakPtr()));
   }
   return content::NavigationThrottle::DEFER;
+#else
+  NOTREACHED();
+
+  // This should never happen but needs to be included to avoid compilation
+  // error on debug builds.
+  return content::NavigationThrottle::CANCEL_AND_IGNORE;
 #endif
 }
 
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm
index 1a319ce..e3a5cbf7 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -268,8 +268,10 @@
     [self updateTheme:[[[self view] window] themeProvider]];
 
   NSView* view = [self view];
-  [view setHidden:NSMaxX([view.superview cr_localizedRect:view.frame]) >
-                  NSMaxX(view.superview.bounds)];
+  [view setHidden:NSMaxX(base::FeatureList::IsEnabled(
+                             features::kMacMaterialDesignDownloadShelf)
+                             ? [view.superview cr_localizedRect:view.frame]
+                             : view.frame) > NSMaxX(view.superview.bounds)];
 }
 
 - (void)downloadWasOpened {
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
index d6b1f763..9d22f3e 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
@@ -397,7 +397,10 @@
     frame.size.width = [itemController preferredSize].width;
     if (!skipFirst)
       [[[itemController view] animator]
-          setFrame:[itemContainerView_ cr_localizedRect:frame]];
+          setFrame:base::FeatureList::IsEnabled(
+                       features::kMacMaterialDesignDownloadShelf)
+                       ? [itemContainerView_ cr_localizedRect:frame]
+                       : frame];
     currentX += frame.size.width + kDownloadItemPadding;
     skipFirst = NO;
   }
@@ -435,7 +438,9 @@
 
   [itemContainerView_ addSubview:[controller view]];
   [controller view].autoresizingMask =
-      [NSView cr_localizedAutoresizingMask:NSViewMaxXMargin];
+      base::FeatureList::IsEnabled(features::kMacMaterialDesignDownloadShelf)
+          ? [NSView cr_localizedAutoresizingMask:NSViewMaxXMargin]
+          : NSViewMaxXMargin;
 
   // The controller is in charge of removing itself as an observer in its
   // dealloc.
@@ -465,7 +470,10 @@
   NSSize size = [controller preferredSize];
   NSRect frame = NSMakeRect(0, 0, 0, size.height);
   NSView* view = [controller view];
-  [view setFrame:[itemContainerView_ cr_localizedRect:frame]];
+  [view setFrame:base::FeatureList::IsEnabled(
+                     features::kMacMaterialDesignDownloadShelf)
+                     ? [itemContainerView_ cr_localizedRect:frame]
+                     : frame];
 
   // ...then, in MD, animate everything together.
   if (base::FeatureList::IsEnabled(features::kMacMaterialDesignDownloadShelf)) {
diff --git a/chrome/browser/ui/views/accessibility/invert_bubble_view.cc b/chrome/browser/ui/views/accessibility/invert_bubble_view.cc
index c1938825..4fc6ef66 100644
--- a/chrome/browser/ui/views/accessibility/invert_bubble_view.cc
+++ b/chrome/browser/ui/views/accessibility/invert_bubble_view.cc
@@ -10,54 +10,71 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/harmony/chrome_typography.h"
 #include "chrome/browser/ui/views/toolbar/app_menu_button.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/page_navigator.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/controls/link_listener.h"
-#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
 
-const char kHighContrastExtensionUrl[] =
-    "https://chrome.google.com/webstore/detail/djcfdncoelnlbldjfhinnjlhdjlikmph";
-const char kDarkThemeSearchUrl[] =
+constexpr char kHighContrastExtensionUrl[] =
+    "https://chrome.google.com/webstore/detail/"
+    "djcfdncoelnlbldjfhinnjlhdjlikmph";
+constexpr char kDarkThemeSearchUrl[] =
     "https://chrome.google.com/webstore/category/collection/dark_themes";
-const char kLearnMoreUrl[] =
-    "https://groups.google.com/a/googleproductforums.com/d/topic/chrome/Xrco2HsXS-8/discussion";
+constexpr char kLearnMoreUrl[] =
+    "https://groups.google.com/a/googleproductforums.com/d/topic/chrome/"
+    "Xrco2HsXS-8/discussion";
+
+// Tag value used to uniquely identify the "learn more" (?) button.
+constexpr int kLearnMoreButton = 100;
 
 class InvertBubbleView : public views::BubbleDialogDelegateView,
-                         public views::LinkListener {
+                         public views::LinkListener,
+                         public views::ButtonListener {
  public:
   InvertBubbleView(Browser* browser, views::View* anchor_view);
   ~InvertBubbleView() override;
 
  private:
   // Overridden from views::BubbleDialogDelegateView:
+  views::View* CreateExtraView() override;
   int GetDialogButtons() const override;
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   void Init() override;
 
+  // Overridden from views::WidgetDelegate:
+  base::string16 GetWindowTitle() const override;
+  bool ShouldShowCloseButton() const override;
+
   // Overridden from views::LinkListener:
   void LinkClicked(views::Link* source, int event_flags) override;
 
+  // Overridden from views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
   void OpenLink(const std::string& url, int event_flags);
 
   Browser* browser_;
   views::Link* high_contrast_;
   views::Link* dark_theme_;
-  views::Link* learn_more_;
-  views::Link* close_;
 
   DISALLOW_COPY_AND_ASSIGN(InvertBubbleView);
 };
@@ -66,10 +83,8 @@
     : views::BubbleDialogDelegateView(anchor_view,
                                       views::BubbleBorder::TOP_RIGHT),
       browser_(browser),
-      high_contrast_(NULL),
-      dark_theme_(NULL),
-      learn_more_(NULL),
-      close_(NULL) {
+      high_contrast_(nullptr),
+      dark_theme_(nullptr) {
   set_margins(gfx::Insets());
   chrome::RecordDialogCreation(chrome::DialogIdentifier::INVERT);
 }
@@ -77,8 +92,21 @@
 InvertBubbleView::~InvertBubbleView() {
 }
 
+views::View* InvertBubbleView::CreateExtraView() {
+  views::ImageButton* learn_more = views::CreateVectorImageButton(this);
+  views::SetImageFromVectorIcon(learn_more, vector_icons::kHelpOutlineIcon);
+  learn_more->set_tag(kLearnMoreButton);
+  return learn_more;
+}
+
 int InvertBubbleView::GetDialogButtons() const {
-  return ui::DIALOG_BUTTON_NONE;
+  return ui::DIALOG_BUTTON_OK;
+}
+
+base::string16 InvertBubbleView::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  DCHECK_EQ(button, ui::DialogButton::DIALOG_BUTTON_OK);
+  return l10n_util::GetStringUTF16(IDS_DONE);
 }
 
 void InvertBubbleView::Init() {
@@ -86,57 +114,27 @@
   SetBorder(views::CreateEmptyBorder(
       provider->GetInsetsMetric(views::INSETS_DIALOG)));
 
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  const gfx::FontList& original_font_list =
-      rb.GetFontList(ui::ResourceBundle::MediumFont);
-
-  // TODO(tapted): This should be using WidgetDelegate::GetWindowTitle().
-  views::Label* title = new views::Label(
-      base::string16(), views::Label::CustomFont{original_font_list.Derive(
-                            2, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)});
-  title->SetMultiLine(true);
-
-  learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_LEARN_MORE));
-  learn_more_->SetFontList(original_font_list);
-  learn_more_->set_listener(this);
+  views::Label* header =
+      new views::Label(l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_HEADER),
+                       CONTEXT_BODY_TEXT_LARGE);
 
   high_contrast_ =
-      new views::Link(l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_EXT));
-  high_contrast_->SetFontList(original_font_list);
+      new views::Link(l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_EXT),
+                      CONTEXT_BODY_TEXT_LARGE);
   high_contrast_->set_listener(this);
 
-  dark_theme_ = new views::Link(l10n_util::GetStringUTF16(IDS_DARK_THEME));
-  dark_theme_->SetFontList(original_font_list);
+  dark_theme_ = new views::Link(l10n_util::GetStringUTF16(IDS_DARK_THEME),
+                                CONTEXT_BODY_TEXT_LARGE);
   dark_theme_->set_listener(this);
 
-  close_ = new views::Link(l10n_util::GetStringUTF16(IDS_CLOSE));
-  close_->SetFontList(original_font_list);
-  close_->set_listener(this);
+  views::BoxLayout* layout = SetLayoutManager(
+      std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
 
-  views::GridLayout* layout =
-      SetLayoutManager(std::make_unique<views::GridLayout>(this));
-
-  views::ColumnSet* columns = layout->AddColumnSet(0);
-  for (int i = 0; i < 4; i++) {
-    columns->AddColumn(views::GridLayout::LEADING,
-                       views::GridLayout::LEADING, 0,
-                       views::GridLayout::USE_PREF, 0, 0);
-  }
-
-  layout->StartRow(0, 0);
-  layout->AddView(title, 4, 1);
-  layout->StartRowWithPadding(
-      0, 0, 0,
-      provider->GetDistanceMetric(DISTANCE_RELATED_CONTROL_VERTICAL_SMALL));
-  layout->AddView(high_contrast_);
-  layout->AddView(dark_theme_);
-  layout->AddView(learn_more_);
-  layout->AddView(close_);
-
-  // Fit the message to the width of the links in the bubble.
-  const gfx::Size size(GetPreferredSize());
-  title->SetText(l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_NOTIFICATION));
-  title->SizeToFit(size.width());
+  AddChildView(header);
+  AddChildView(high_contrast_);
+  AddChildView(dark_theme_);
 
   // Switching to high-contrast mode has a nasty habit of causing Chrome
   // top-level windows to lose focus, so closing the bubble on deactivate
@@ -146,19 +144,29 @@
   set_close_on_deactivate(false);
 }
 
+base::string16 InvertBubbleView::GetWindowTitle() const {
+  return l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_TITLE);
+}
+
+bool InvertBubbleView::ShouldShowCloseButton() const {
+  return true;
+}
+
 void InvertBubbleView::LinkClicked(views::Link* source, int event_flags) {
   if (source == high_contrast_)
     OpenLink(kHighContrastExtensionUrl, event_flags);
   else if (source == dark_theme_)
     OpenLink(kDarkThemeSearchUrl, event_flags);
-  else if (source == learn_more_)
-    OpenLink(kLearnMoreUrl, event_flags);
-  else if (source == close_)
-    GetWidget()->Close();
   else
     NOTREACHED();
 }
 
+void InvertBubbleView::ButtonPressed(views::Button* sender,
+                                     const ui::Event& event) {
+  if (sender->tag() == kLearnMoreButton)
+    OpenLink(kLearnMoreUrl, event.flags());
+}
+
 void InvertBubbleView::OpenLink(const std::string& url, int event_flags) {
   WindowOpenDisposition disposition =
       ui::DispositionFromEventFlags(event_flags);
diff --git a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
index 8d789bd1..6ea6ba9 100644
--- a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
@@ -169,6 +169,7 @@
     const char* name;
     int id;
   } localized_strings[] = {
+      {"loading", IDS_SETTINGS_LOADING},
       {"networkProxy", IDS_SETTINGS_INTERNET_NETWORK_PROXY_PROXY},
       {"networkProxyAddException",
        IDS_SETTINGS_INTERNET_NETWORK_PROXY_ADD_EXCEPTION},
diff --git a/chrome/browser/vr/testapp/gl_renderer.cc b/chrome/browser/vr/testapp/gl_renderer.cc
index 757170b..8580bf1c 100644
--- a/chrome/browser/vr/testapp/gl_renderer.cc
+++ b/chrome/browser/vr/testapp/gl_renderer.cc
@@ -14,6 +14,14 @@
 
 namespace vr {
 
+namespace {
+
+void OnPresentedFrame(const gfx::PresentationFeedback& feedback) {
+  // Do nothing for now.
+}
+
+}  // namespace
+
 GlRenderer::GlRenderer(const scoped_refptr<gl::GLSurface>& surface,
                        vr::VrTestContext* vr)
     : surface_(surface), vr_(vr), weak_ptr_factory_(this) {}
@@ -43,7 +51,7 @@
   context_->MakeCurrent(surface_.get());
   vr_->DrawFrame();
   PostRenderFrameTask(
-      surface_->SwapBuffers(gl::GLSurface::PresentationCallback()));
+      surface_->SwapBuffers(base::BindRepeating(&OnPresentedFrame)));
 }
 
 void GlRenderer::PostRenderFrameTask(gfx::SwapResult result) {
diff --git a/chrome/browser/vr/ui_scene_constants.h b/chrome/browser/vr/ui_scene_constants.h
index 19a0b3e..7c632330 100644
--- a/chrome/browser/vr/ui_scene_constants.h
+++ b/chrome/browser/vr/ui_scene_constants.h
@@ -61,14 +61,14 @@
 static constexpr float kUrlBarVerticalOffsetDMM = -0.516f;
 static constexpr float kUrlBarRotationRad = gfx::DegToRad(-10.0f);
 static constexpr float kUrlBarFontHeightDMM = 0.027f;
-static constexpr float kUrlBarIconSizeDMM = 0.05f;
+static constexpr float kUrlBarIconSizeDMM = 0.038f;
 static constexpr float kUrlBarBackButtonWidthDMM = 0.087f;
 static constexpr float kUrlBarBackButtonIconOffsetDMM = 0.0045f;
 static constexpr float kUrlBarSeparatorWidthDMM = 0.002f;
 static constexpr float kUrlBarOriginRegionWidthDMM = 0.583f;
-static constexpr float kUrlBarOriginContentWidthDMM = 0.536f;
-static constexpr float kUrlBarOriginContentOffsetDMM = 0.007f;
-static constexpr float kUrlBarFieldSpacingDMM = 0.008f;
+static constexpr float kUrlBarOriginContentWidthDMM = 0.543f;
+static constexpr float kUrlBarOriginContentOffsetDMM = 0.020f;
+static constexpr float kUrlBarFieldSpacingDMM = 0.014f;
 static constexpr float kUrlBarOfflineIconTextSpacingDMM = 0.004f;
 static constexpr float kUrlBarSecuritySeparatorHeightDMM = 0.026f;
 static constexpr float kUrlBarOriginFadeWidth = 0.044f;
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 0ffd7238..7d2d1b08 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -1479,6 +1479,8 @@
                           base::Unretained(browser_)));
   origin_content->SetSize(kUrlBarOriginContentWidthDMM, kUrlBarHeightDMM);
   origin_content->SetTranslate(kUrlBarOriginContentOffsetDMM, 0, 0);
+  origin_content->set_x_anchoring(LEFT);
+  origin_content->set_x_centering(LEFT);
   VR_BIND_VISIBILITY(origin_content, !model->fullscreen_enabled());
   origin_content->AddBinding(
       VR_BIND_FUNC(ToolbarState, Model, model_, model->toolbar_state, UrlBar,
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index d3616051..4644fde 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -128,14 +128,14 @@
 // interstitial error pages (e.g. certificate errors).
 const char kCommittedInterstitials[] = "committed-interstitials";
 
-// Comma-separated list of BrowserThreads that cause browser process to crash
-// if the given browser thread is not responsive. UI,IO,DB,FILE,CACHE are the
-// list of BrowserThreads that are supported.
+// Comma-separated list of BrowserThreads that cause browser process to crash if
+// the given browser thread is not responsive. UI/IO are the BrowserThreads that
+// are supported.
 //
 // For example:
-//    --crash-on-hang-threads=UI:3:18,IO:3:18 --> Crash the browser if UI or IO
-//      is not responsive for 18 seconds and the number of browser threads that
-//      are responding is less than or equal to 3.
+//    --crash-on-hang-threads=UI:18,IO:18 --> Crash the browser if UI or IO is
+//    not responsive for 18 seconds while the other browser thread is
+//    responsive.
 const char kCrashOnHangThreads[]            = "crash-on-hang-threads";
 
 // Some platforms like ChromeOS default to empty desktop.
diff --git a/chrome/common/extensions/docs/examples/tutorials/hello_extensions.zip b/chrome/common/extensions/docs/examples/tutorials/hello_extensions.zip
deleted file mode 100644
index 2eb1940..0000000
--- a/chrome/common/extensions/docs/examples/tutorials/hello_extensions.zip
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/templates/articles/extensions_index.html b/chrome/common/extensions/docs/templates/articles/extensions_index.html
index 57d546a..2e569e4 100644
--- a/chrome/common/extensions/docs/templates/articles/extensions_index.html
+++ b/chrome/common/extensions/docs/templates/articles/extensions_index.html
@@ -43,18 +43,20 @@
 
 <p>
   Extensions are distributed through the
-  <a href="https://chrome.google.com/webstore/developer/dashboard">Chrome Developer Dashboard</a>
+  <a href="https://chrome.google.com/webstore/developer/dashboard">
+    Chrome Developer Dashboard</a>
   and published to the
   <a href="http://chrome.google.com/webstore">Chrome Web Store</a>.
   For more information, see the
-  <a href="http://code.google.com/chrome/webstore">store developer documentation</a>.
+  <a href="http://code.google.com/chrome/webstore">
+    store developer documentation</a>.
 </p>
 
 <h2 id="hello-extensions">Hello Extensions</h2>
 <p>
 Take a small step into extensions with this quick Hello Extensions example.
 Create a new directory to store files or download them
-<a href="examples/tutorials/" download="hello_extensions.zip">
+<a href="examples/tutorials/hello_extensions" download="hello_extensions">
   here.
 </a>
 </p>
@@ -92,7 +94,8 @@
 </pre>
 <p>
   Download
-  <a href="examples/tutorials/hello_extensions" download="hello_extensions.png">
+  <a href="examples/tutorials/hello_extensions/hello_extensions.png"
+  download="hello_extensions.png">
   <code>hello_extensions.png</code> here</a>
    and then create a file titled <code>hello.html</code>:
 </p>
@@ -164,13 +167,17 @@
   </li>
   <li>
     Subscribe to the
-    <a href="http://groups.google.com/a/chromium.org/group/chromium-extensions">chromium-extensions group</a>
+    <a href="http://groups.google.com/a/chromium.org/group/chromium-extensions">
+      chromium-extensions group</a>
   </li>
 </ol>
 
 <h2 id="Featured-videos">Featured videos</h2>
 
 <p>
-  <a href="http://www.youtube.com/view_play_list?p=CA101D6A85FE9D4B">Technical videos</a> <br>
-  <a href="http://www.youtube.com/view_play_list?p=38DF05697DE372B1">Developer snapshots</a>
+  <a href="http://www.youtube.com/view_play_list?p=CA101D6A85FE9D4B">
+    Technical videos</a>
+    <br>
+  <a href="http://www.youtube.com/view_play_list?p=38DF05697DE372B1">
+    Developer snapshots</a>
 </p>
diff --git a/chrome/common/extensions/docs/templates/intros/commands.html b/chrome/common/extensions/docs/templates/intros/commands.html
index f48d5fc..f27ee9a 100644
--- a/chrome/common/extensions/docs/templates/intros/commands.html
+++ b/chrome/common/extensions/docs/templates/intros/commands.html
@@ -22,8 +22,10 @@
 Tab key was removed from list of supported keys in Chrome version 33 and above
 for accessibility reasons.<p>
 
-<p>* Also note that on Mac 'Ctrl' is automatically converted to 'Command'. If
-you want 'Ctrl' instead, please specify 'MacCtrl'.</p>
+<p>* Please note that on Mac 'Ctrl' is automatically converted to 'Command'. If
+you want 'Ctrl' instead, please specify 'MacCtrl' under <code>"mac"</code>.
+Specifying 'MacCtrl' under <code>"default"</code>
+will cause the extension to be uninstallable.</p>
 
 <p>* Additionally, on Chrome OS, you can specify 'Search' as a modifier.</p>
 
diff --git a/chrome/installer/mini_installer/BUILD.gn b/chrome/installer/mini_installer/BUILD.gn
index f606dfe..4f10825 100644
--- a/chrome/installer/mini_installer/BUILD.gn
+++ b/chrome/installer/mini_installer/BUILD.gn
@@ -137,10 +137,6 @@
       release_file,
     ]
 
-    if (v8_use_snapshot) {
-      inputs += [ "$root_out_dir/v8_context_snapshot.bin" ]
-    }
-
     outputs = [
       # See also chrome.packed.7z conditionally added below.
       "$output_dir/chrome.7z",
diff --git a/chrome/test/chromedriver/BUILD.gn b/chrome/test/chromedriver/BUILD.gn
index a7a8ce6a..d91cb06b 100644
--- a/chrome/test/chromedriver/BUILD.gn
+++ b/chrome/test/chromedriver/BUILD.gn
@@ -326,29 +326,6 @@
   ]
 }
 
-group("chromedriver_py_tests") {
-  testonly = true
-  deps = [
-    ":chromedriver",
-    "//chrome:chrome",
-  ]
-
-  _py_files = read_file("test/run_py_tests.pydeps", "list lines")
-
-  # Filter out comments.
-  set_sources_assignment_filter([ "#*" ])
-  sources = _py_files
-
-  data = sources + [
-           "//chrome/test/data/chromedriver/",
-           "//testing/xvfb.py",
-         ]
-
-  data_deps = [
-    "//chrome/test/chromedriver",
-  ]
-}
-
 test("chromedriver_unittests") {
   sources = [
     "capabilities_unittest.cc",
diff --git a/chrome/test/chromedriver/chrome/adb.h b/chrome/test/chromedriver/chrome/adb.h
index 47c8b1f5..cb439db 100644
--- a/chrome/test/chromedriver/chrome/adb.h
+++ b/chrome/test/chromedriver/chrome/adb.h
@@ -36,6 +36,9 @@
   virtual Status GetPidByName(const std::string& device_serial,
                               const std::string& process_name,
                               int* pid) = 0;
+  virtual Status GetSocketByPattern(const std::string& device_serial,
+                                    const std::string& grep_pattern,
+                                    std::string* socket_name) = 0;
 };
 
 #endif  // CHROME_TEST_CHROMEDRIVER_CHROME_ADB_H_
diff --git a/chrome/test/chromedriver/chrome/adb_impl.cc b/chrome/test/chromedriver/chrome/adb_impl.cc
index c42b995..a6fd1864 100644
--- a/chrome/test/chromedriver/chrome/adb_impl.cc
+++ b/chrome/test/chromedriver/chrome/adb_impl.cc
@@ -236,6 +236,32 @@
                 "Failed to get PID for the following process: " + process_name);
 }
 
+Status AdbImpl::GetSocketByPattern(const std::string& device_serial,
+                                   const std::string& grep_pattern,
+                                   std::string* socket_name) {
+  std::string response;
+  std::string grep_command = "grep -a '" + grep_pattern + "' /proc/net/unix";
+  Status status =
+      ExecuteHostShellCommand(device_serial, grep_command, &response);
+
+  if (!status.IsOk())
+    return status;
+
+  for (const base::StringPiece& line : base::SplitString(
+           response, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+    std::vector<base::StringPiece> tokens = base::SplitStringPiece(
+        line, base::kWhitespaceASCII, base::TRIM_WHITESPACE,
+        base::SPLIT_WANT_NONEMPTY);
+    if (tokens.size() != 8)
+      continue;
+    *socket_name = tokens[7].as_string();
+    return Status(kOk);
+  }
+
+  return Status(kUnknownError,
+                "Failed to get sockets matching: " + grep_pattern);
+}
+
 Status AdbImpl::ExecuteCommand(
     const std::string& command, std::string* response) {
   scoped_refptr<ResponseBuffer> response_buffer = new ResponseBuffer;
diff --git a/chrome/test/chromedriver/chrome/adb_impl.h b/chrome/test/chromedriver/chrome/adb_impl.h
index 5f82dd3..d86d962 100644
--- a/chrome/test/chromedriver/chrome/adb_impl.h
+++ b/chrome/test/chromedriver/chrome/adb_impl.h
@@ -48,6 +48,9 @@
   Status GetPidByName(const std::string& device_serial,
                       const std::string& process_name,
                       int* pid) override;
+  Status GetSocketByPattern(const std::string& device_serial,
+                            const std::string& grep_pattern,
+                            std::string* socket_name) override;
 
  private:
   Status ExecuteCommand(const std::string& command,
diff --git a/chrome/test/chromedriver/chrome/device_manager.cc b/chrome/test/chromedriver/chrome/device_manager.cc
index f9f8ad7..73d4b0f9 100644
--- a/chrome/test/chromedriver/chrome/device_manager.cc
+++ b/chrome/test/chromedriver/chrome/device_manager.cc
@@ -130,7 +130,22 @@
             "process name must be specified if not equal to package name");
       return status;
     }
-    *device_socket = base::StringPrintf("webview_devtools_remote_%d", pid);
+
+    std::string socket_name;
+    // The leading '@' means abstract UNIX sockets. Some apps have a custom
+    // substring between the required "webview_devtools_remote_" prefix and
+    // their PID, which Chrome DevTools accepts and we also should.
+    std::string pattern =
+        base::StringPrintf("@webview_devtools_remote_.*%d", pid);
+    status = adb_->GetSocketByPattern(serial_, pattern, &socket_name);
+    if (status.IsError()) {
+      if (socket_name.empty())
+        status.AddDetails(
+            "make sure the app has its WebView configured for debugging");
+      return status;
+    }
+    // When used in adb with "localabstract:", the leading '@' is not needed.
+    *device_socket = socket_name.substr(1);
   }
 
   return adb_->ForwardPort(serial_, port, *device_socket);
diff --git a/chrome/test/chromedriver/chrome/device_manager_unittest.cc b/chrome/test/chromedriver/chrome/device_manager_unittest.cc
index 4ae544c..dfa9e2f 100644
--- a/chrome/test/chromedriver/chrome/device_manager_unittest.cc
+++ b/chrome/test/chromedriver/chrome/device_manager_unittest.cc
@@ -71,6 +71,13 @@
     *pid = 0; // avoid uninit error crbug.com/393231
     return Status(kOk);
   }
+
+  Status GetSocketByPattern(const std::string& device_serial,
+                            const std::string& grep_pattern,
+                            std::string* socket_name) override {
+    *socket_name = "@webview_devtools_remote_0";
+    return Status(kOk);
+  }
 };
 
 }  // namespace
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index c103dc03..c534895 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -124,6 +124,7 @@
     'MobileEmulationCapabilityTest.testDeviceMetricsWithDeviceWidth',
     # https://bugs.chromium.org/p/chromium/issues/detail?id=803678
     'ChromeDriverTest.testGoBackAndGoForward'
+    'ChromeDriverTest.testAlertHandlingOnPageUnload',
 ]
 _OS_SPECIFIC_FILTER['mac'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1927
@@ -2701,14 +2702,6 @@
       '', '--android-package',
       help=('Android package key. Possible values: ' +
             str(_ANDROID_NEGATIVE_FILTER.keys())))
-
-  parser.add_option(
-      '', '--isolated-script-test-output',
-      help='JSON output file used by swarming')
-  parser.add_option(
-      '', '--isolated-script-test-perf-output',
-      help='JSON perf output file used by swarming, ignored')
-
   options, args = parser.parse_args()
 
   options.chromedriver = util.GetAbsolutePathOfUserPath(options.chromedriver)
@@ -2760,32 +2753,4 @@
   ChromeDriverTest.GlobalTearDown()
   HeadlessInvalidCertificateTest.GlobalTearDown()
   MobileEmulationCapabilityTest.GlobalTearDown()
-
-  if options.isolated_script_test_output:
-    output = {
-        'interrupted': False,
-        'num_failures_by_type': { },
-        'path_delimiter': '.',
-        'seconds_since_epoch': time.time(),
-        'tests': { },
-        'version': 3,
-    }
-
-    for test in tests:
-      output['tests'][test.id()] = {
-          'expected': 'PASS',
-          'actual': 'PASS'
-      }
-
-    for failure in result.failures + result.errors:
-      output['tests'][failure[0].id()]['actual'] = 'FAIL'
-
-    num_fails = len(result.failures) + len(result.errors)
-    output['num_failures_by_type']['FAIL'] = num_fails
-    output['num_failures_by_type']['PASS'] = len(output['tests']) - num_fails
-
-    with open(options.isolated_script_test_output, 'w') as fp:
-      json.dump(output, fp)
-      fp.write('\n')
-
   sys.exit(len(result.failures) + len(result.errors))
diff --git a/chrome/test/chromedriver/test/run_py_tests.pydeps b/chrome/test/chromedriver/test/run_py_tests.pydeps
deleted file mode 100644
index 4b709124..0000000
--- a/chrome/test/chromedriver/test/run_py_tests.pydeps
+++ /dev/null
@@ -1,70 +0,0 @@
-# Generated by running:
-#   build/print_python_deps.py --root chrome/test/chromedriver --output chrome/test/chromedriver/test/run_py_tests.pydeps chrome/test/chromedriver/test/run_py_tests.py
-../../../build/android/devil_chromium.py
-../../../build/android/pylib/__init__.py
-../../../build/android/pylib/constants/__init__.py
-../../../build/android/pylib/constants/host_paths.py
-../../../third_party/catapult/common/py_utils/py_utils/__init__.py
-../../../third_party/catapult/common/py_utils/py_utils/cloud_storage.py
-../../../third_party/catapult/common/py_utils/py_utils/cloud_storage_global_lock.py
-../../../third_party/catapult/common/py_utils/py_utils/lock.py
-../../../third_party/catapult/common/py_utils/py_utils/tempfile_ext.py
-../../../third_party/catapult/dependency_manager/dependency_manager/__init__.py
-../../../third_party/catapult/dependency_manager/dependency_manager/archive_info.py
-../../../third_party/catapult/dependency_manager/dependency_manager/base_config.py
-../../../third_party/catapult/dependency_manager/dependency_manager/cloud_storage_info.py
-../../../third_party/catapult/dependency_manager/dependency_manager/dependency_info.py
-../../../third_party/catapult/dependency_manager/dependency_manager/dependency_manager_util.py
-../../../third_party/catapult/dependency_manager/dependency_manager/exceptions.py
-../../../third_party/catapult/dependency_manager/dependency_manager/local_path_info.py
-../../../third_party/catapult/dependency_manager/dependency_manager/manager.py
-../../../third_party/catapult/dependency_manager/dependency_manager/uploader.py
-../../../third_party/catapult/devil/devil/__init__.py
-../../../third_party/catapult/devil/devil/android/__init__.py
-../../../third_party/catapult/devil/devil/android/apk_helper.py
-../../../third_party/catapult/devil/devil/android/constants/__init__.py
-../../../third_party/catapult/devil/devil/android/constants/chrome.py
-../../../third_party/catapult/devil/devil/android/constants/file_system.py
-../../../third_party/catapult/devil/devil/android/decorators.py
-../../../third_party/catapult/devil/devil/android/device_errors.py
-../../../third_party/catapult/devil/devil/android/device_signal.py
-../../../third_party/catapult/devil/devil/android/device_temp_file.py
-../../../third_party/catapult/devil/devil/android/device_utils.py
-../../../third_party/catapult/devil/devil/android/forwarder.py
-../../../third_party/catapult/devil/devil/android/install_commands.py
-../../../third_party/catapult/devil/devil/android/logcat_monitor.py
-../../../third_party/catapult/devil/devil/android/md5sum.py
-../../../third_party/catapult/devil/devil/android/sdk/__init__.py
-../../../third_party/catapult/devil/devil/android/sdk/aapt.py
-../../../third_party/catapult/devil/devil/android/sdk/adb_wrapper.py
-../../../third_party/catapult/devil/devil/android/sdk/build_tools.py
-../../../third_party/catapult/devil/devil/android/sdk/intent.py
-../../../third_party/catapult/devil/devil/android/sdk/keyevent.py
-../../../third_party/catapult/devil/devil/android/sdk/split_select.py
-../../../third_party/catapult/devil/devil/android/sdk/version_codes.py
-../../../third_party/catapult/devil/devil/android/valgrind_tools/__init__.py
-../../../third_party/catapult/devil/devil/android/valgrind_tools/base_tool.py
-../../../third_party/catapult/devil/devil/base_error.py
-../../../third_party/catapult/devil/devil/constants/__init__.py
-../../../third_party/catapult/devil/devil/constants/exit_codes.py
-../../../third_party/catapult/devil/devil/devil_env.py
-../../../third_party/catapult/devil/devil/utils/__init__.py
-../../../third_party/catapult/devil/devil/utils/cmd_helper.py
-../../../third_party/catapult/devil/devil/utils/host_utils.py
-../../../third_party/catapult/devil/devil/utils/lazy/__init__.py
-../../../third_party/catapult/devil/devil/utils/lazy/weak_constant.py
-../../../third_party/catapult/devil/devil/utils/parallelizer.py
-../../../third_party/catapult/devil/devil/utils/reraiser_thread.py
-../../../third_party/catapult/devil/devil/utils/timeout_retry.py
-../../../third_party/catapult/devil/devil/utils/watchdog_timer.py
-../../../third_party/catapult/devil/devil/utils/zip_utils.py
-../../../third_party/catapult/third_party/zipfile/zipfile_2_7_13.py
-chrome_paths.py
-client/chromedriver.py
-client/command_executor.py
-client/webelement.py
-server/server.py
-test/run_py_tests.py
-test/unittest_util.py
-test/webserver.py
-util.py
diff --git a/chrome/test/media_router/test_media_sinks_observer.h b/chrome/test/media_router/test_media_sinks_observer.h
index f0da58a3..169a559 100644
--- a/chrome/test/media_router/test_media_sinks_observer.h
+++ b/chrome/test/media_router/test_media_sinks_observer.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef CHROME_TEST_MEDIA_ROUTER_TEST_MEDIA_SINKS_OBSERVER_H_
+#define CHROME_TEST_MEDIA_ROUTER_TEST_MEDIA_SINKS_OBSERVER_H_
+
 #include <map>
 #include <string>
 #include <vector>
 
 #include "chrome/browser/media/router/media_sinks_observer.h"
 
-#ifndef CHROME_TEST_MEDIA_ROUTER_TEST_MEDIA_SINKS_OBSERVER_H_
-#define CHROME_TEST_MEDIA_ROUTER_TEST_MEDIA_SINKS_OBSERVER_H_
-
 namespace media_router {
 
 class MediaRouter;
diff --git a/chromecast/browser/media/supported_codec_finder.h b/chromecast/browser/media/supported_codec_finder.h
index 11d3cf06..5e982fe 100644
--- a/chromecast/browser/media/supported_codec_finder.h
+++ b/chromecast/browser/media/supported_codec_finder.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef CHROMECAST_BROWSER_MEDIA_SUPPORTED_CODEC_FINDER_H_
+#define CHROMECAST_BROWSER_MEDIA_SUPPORTED_CODEC_FINDER_H_
+
 namespace chromecast {
 namespace media {
 
@@ -15,3 +18,5 @@
 
 }  // namespace media
 }  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_MEDIA_SUPPORTED_CODEC_FINDER_H_
diff --git a/chromecast/net/fake_connectivity_checker.h b/chromecast/net/fake_connectivity_checker.h
index 411b0489..c3a5ac3 100644
--- a/chromecast/net/fake_connectivity_checker.h
+++ b/chromecast/net/fake_connectivity_checker.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef CHROMECAST_NET_FAKE_CONNECTIVITY_CHECKER_H_
+#define CHROMECAST_NET_FAKE_CONNECTIVITY_CHECKER_H_
+
 #include "base/macros.h"
 #include "chromecast/net/connectivity_checker.h"
 
@@ -31,3 +34,5 @@
 };
 
 }  // namespace chromecast
+
+#endif  // CHROMECAST_NET_FAKE_CONNECTIVITY_CHECKER_H_
diff --git a/chromeos/components/tether/host_connection_metrics_logger.cc b/chromeos/components/tether/host_connection_metrics_logger.cc
index 2b4c4ebc..d43d610 100644
--- a/chromeos/components/tether/host_connection_metrics_logger.cc
+++ b/chromeos/components/tether/host_connection_metrics_logger.cc
@@ -68,6 +68,16 @@
       RecordConnectionResultFailure(
           ConnectionToHostResult_FailureEventType::NO_CELL_DATA);
       break;
+    case ConnectionToHostResult::
+        CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_FAILED:
+      RecordConnectionResultFailure(
+          ConnectionToHostResult_FailureEventType::ENABLING_HOTSPOT_FAILED);
+      break;
+    case ConnectionToHostResult::
+        CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_TIMEOUT:
+      RecordConnectionResultFailure(
+          ConnectionToHostResult_FailureEventType::ENABLING_HOTSPOT_TIMEOUT);
+      break;
     default:
       NOTREACHED();
   };
diff --git a/chromeos/components/tether/host_connection_metrics_logger.h b/chromeos/components/tether/host_connection_metrics_logger.h
index 06bb8e78..3dae478 100644
--- a/chromeos/components/tether/host_connection_metrics_logger.h
+++ b/chromeos/components/tether/host_connection_metrics_logger.h
@@ -27,7 +27,9 @@
     CONNECTION_RESULT_FAILURE_TETHERING_TIMED_OUT_FIRST_TIME_SETUP_WAS_REQUIRED,
     CONNECTION_RESULT_FAILURE_TETHERING_TIMED_OUT_FIRST_TIME_SETUP_WAS_NOT_REQUIRED,
     CONNECTION_RESULT_FAILURE_TETHERING_UNSUPPORTED,
-    CONNECTION_RESULT_FAILURE_NO_CELL_DATA
+    CONNECTION_RESULT_FAILURE_NO_CELL_DATA,
+    CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_FAILED,
+    CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_TIMEOUT
   };
 
   // Record the result of an attempted host connection.
@@ -63,6 +65,10 @@
                            RecordConnectionResultFailureTetheringUnsupported);
   FRIEND_TEST_ALL_PREFIXES(HostConnectionMetricsLoggerTest,
                            RecordConnectionResultFailureNoCellData);
+  FRIEND_TEST_ALL_PREFIXES(HostConnectionMetricsLoggerTest,
+                           RecordConnectionResultFailureEnablingHotspotFailed);
+  FRIEND_TEST_ALL_PREFIXES(HostConnectionMetricsLoggerTest,
+                           RecordConnectionResultFailureEnablingHotspotTimeout);
 
   // An Instant Tethering connection can fail for several different reasons.
   // Though traditionally success and each failure case would be logged to a
@@ -96,6 +102,8 @@
     CLIENT_CONNECTION_ERROR = 2,
     TETHERING_UNSUPPORTED = 3,
     NO_CELL_DATA = 4,
+    ENABLING_HOTSPOT_FAILED = 5,
+    ENABLING_HOTSPOT_TIMEOUT = 6,
     FAILURE_MAX
   };
 
diff --git a/chromeos/components/tether/host_connection_metrics_logger_unittest.cc b/chromeos/components/tether/host_connection_metrics_logger_unittest.cc
index 6c8abec2..4e0c212 100644
--- a/chromeos/components/tether/host_connection_metrics_logger_unittest.cc
+++ b/chromeos/components/tether/host_connection_metrics_logger_unittest.cc
@@ -230,6 +230,32 @@
                     ConnectionToHostResult_SuccessEventType::FAILURE);
 }
 
+TEST_F(HostConnectionMetricsLoggerTest,
+       RecordConnectionResultFailureEnablingHotspotFailed) {
+  metrics_logger_->RecordConnectionToHostResult(
+      HostConnectionMetricsLogger::ConnectionToHostResult::
+          CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_FAILED);
+
+  VerifyFailure(
+      HostConnectionMetricsLogger::ConnectionToHostResult_FailureEventType::
+          ENABLING_HOTSPOT_FAILED);
+  VerifySuccess(HostConnectionMetricsLogger::
+                    ConnectionToHostResult_SuccessEventType::FAILURE);
+}
+
+TEST_F(HostConnectionMetricsLoggerTest,
+       RecordConnectionResultFailureEnablingHotspotTimeout) {
+  metrics_logger_->RecordConnectionToHostResult(
+      HostConnectionMetricsLogger::ConnectionToHostResult::
+          CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_TIMEOUT);
+
+  VerifyFailure(
+      HostConnectionMetricsLogger::ConnectionToHostResult_FailureEventType::
+          ENABLING_HOTSPOT_TIMEOUT);
+  VerifySuccess(HostConnectionMetricsLogger::
+                    ConnectionToHostResult_SuccessEventType::FAILURE);
+}
+
 }  // namespace tether
 
 }  // namespace chromeos
diff --git a/chromeos/components/tether/proto/tether.proto b/chromeos/components/tether/proto/tether.proto
index 17e1b813..f8809db 100644
--- a/chromeos/components/tether/proto/tether.proto
+++ b/chromeos/components/tether/proto/tether.proto
@@ -63,7 +63,7 @@
 // Next id: 1
 message TetherAvailabilityRequest {}
 
-// Next id: 3
+// Next id: 6
 message TetherAvailabilityResponse {
   enum ResponseCode {
     UNKNOWN_ERROR = 0;
@@ -81,7 +81,7 @@
 // Next id: 1
 message ConnectTetheringRequest {}
 
-// Next id: 5
+// Next id: 8
 message ConnectTetheringResponse {
   enum ResponseCode {
     UNKNOWN_ERROR = 0;
@@ -90,6 +90,8 @@
     TETHERING_TIMEOUT = 3;
     TETHERING_UNSUPPORTED = 4;
     NO_CELL_DATA = 5;
+    ENABLING_HOTSPOT_FAILED = 6;
+    ENABLING_HOTSPOT_TIMEOUT = 7;
   }
 
   optional ResponseCode response_code = 1;
diff --git a/chromeos/components/tether/tether_connector_impl.cc b/chromeos/components/tether/tether_connector_impl.cc
index 90465d6..be9cfff 100644
--- a/chromeos/components/tether/tether_connector_impl.cc
+++ b/chromeos/components/tether/tether_connector_impl.cc
@@ -405,6 +405,20 @@
         CONNECTION_RESULT_FAILURE_NO_CELL_DATA;
   }
 
+  if (error_code ==
+      ConnectTetheringResponse_ResponseCode::
+          ConnectTetheringResponse_ResponseCode_ENABLING_HOTSPOT_FAILED) {
+    return HostConnectionMetricsLogger::ConnectionToHostResult::
+        CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_FAILED;
+  }
+
+  if (error_code ==
+      ConnectTetheringResponse_ResponseCode::
+          ConnectTetheringResponse_ResponseCode_ENABLING_HOTSPOT_TIMEOUT) {
+    return HostConnectionMetricsLogger::ConnectionToHostResult::
+        CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_TIMEOUT;
+  }
+
   return HostConnectionMetricsLogger::ConnectionToHostResult::
       CONNECTION_RESULT_FAILURE_UNKNOWN_ERROR;
 }
diff --git a/chromeos/components/tether/tether_connector_impl_unittest.cc b/chromeos/components/tether/tether_connector_impl_unittest.cc
index 46766ae..5864db2a 100644
--- a/chromeos/components/tether/tether_connector_impl_unittest.cc
+++ b/chromeos/components/tether/tether_connector_impl_unittest.cc
@@ -473,6 +473,26 @@
 }
 
 TEST_F(TetherConnectorImplTest,
+       TestConnectTetheringOperationFails_EnableHotspotFailed) {
+  VerifyConnectTetheringOperationFails(
+      ConnectTetheringResponse_ResponseCode::
+          ConnectTetheringResponse_ResponseCode_ENABLING_HOTSPOT_FAILED,
+      false /* setup_required */,
+      HostConnectionMetricsLogger::ConnectionToHostResult::
+          CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_FAILED);
+}
+
+TEST_F(TetherConnectorImplTest,
+       TestConnectTetheringOperationFails_EnableHotspotTimeout) {
+  VerifyConnectTetheringOperationFails(
+      ConnectTetheringResponse_ResponseCode::
+          ConnectTetheringResponse_ResponseCode_ENABLING_HOTSPOT_TIMEOUT,
+      false /* setup_required */,
+      HostConnectionMetricsLogger::ConnectionToHostResult::
+          CONNECTION_RESULT_FAILURE_ENABLING_HOTSPOT_TIMEOUT);
+}
+
+TEST_F(TetherConnectorImplTest,
        ConnectionToHostFailedNotificationRemovedWhenConnectionStarts) {
   // Start with the "connection to host failed" notification showing.
   fake_notification_presenter_->NotifyConnectionToHostFailed();
diff --git a/chromeos/dbus/fake_smb_provider_client.cc b/chromeos/dbus/fake_smb_provider_client.cc
index f45d3889..1dace416 100644
--- a/chromeos/dbus/fake_smb_provider_client.cc
+++ b/chromeos/dbus/fake_smb_provider_client.cc
@@ -32,7 +32,7 @@
 void FakeSmbProviderClient::ReadDirectory(int32_t mount_id,
                                           const base::FilePath& directory_path,
                                           ReadDirectoryCallback callback) {
-  smbprovider::DirectoryEntryList entry_list;
+  smbprovider::DirectoryEntryListProto entry_list;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), smbprovider::ERROR_OK, entry_list));
@@ -41,7 +41,7 @@
 void FakeSmbProviderClient::GetMetadataEntry(int32_t mount_id,
                                              const base::FilePath& entry_path,
                                              GetMetdataEntryCallback callback) {
-  smbprovider::DirectoryEntry entry;
+  smbprovider::DirectoryEntryProto entry;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), smbprovider::ERROR_OK, entry));
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc
index ad83a5cd..9de599a 100644
--- a/chromeos/dbus/smb_provider_client.cc
+++ b/chromeos/dbus/smb_provider_client.cc
@@ -53,14 +53,14 @@
 
   void Mount(const base::FilePath& share_path,
              MountCallback callback) override {
-    smbprovider::MountOptions options;
+    smbprovider::MountOptionsProto options;
     options.set_path(share_path.value());
     CallMethod(smbprovider::kMountMethod, options,
                &SmbProviderClientImpl::HandleMountCallback, &callback);
   }
 
   void Unmount(int32_t mount_id, StatusCallback callback) override {
-    smbprovider::UnmountOptions options;
+    smbprovider::UnmountOptionsProto options;
     options.set_mount_id(mount_id);
     CallMethod(smbprovider::kUnmountMethod, options,
                &SmbProviderClientImpl::HandleUnmountCallback, &callback);
@@ -69,24 +69,24 @@
   void ReadDirectory(int32_t mount_id,
                      const base::FilePath& directory_path,
                      ReadDirectoryCallback callback) override {
-    smbprovider::ReadDirectoryOptions options;
+    smbprovider::ReadDirectoryOptionsProto options;
     options.set_mount_id(mount_id);
     options.set_directory_path(directory_path.value());
     CallMethod(smbprovider::kReadDirectoryMethod, options,
                &SmbProviderClientImpl::HandleProtoCallback<
-                   smbprovider::DirectoryEntryList>,
+                   smbprovider::DirectoryEntryListProto>,
                &callback);
   }
 
   void GetMetadataEntry(int32_t mount_id,
                         const base::FilePath& entry_path,
                         GetMetdataEntryCallback callback) override {
-    smbprovider::GetMetadataEntryOptions options;
+    smbprovider::GetMetadataEntryOptionsProto options;
     options.set_mount_id(mount_id);
     options.set_entry_path(entry_path.value());
     CallMethod(smbprovider::kGetMetadataEntryMethod, options,
                &SmbProviderClientImpl::HandleProtoCallback<
-                   smbprovider::DirectoryEntry>,
+                   smbprovider::DirectoryEntryProto>,
                &callback);
   }
 
@@ -94,7 +94,7 @@
                 const base::FilePath& file_path,
                 bool writeable,
                 OpenFileCallback callback) override {
-    smbprovider::OpenFileOptions options;
+    smbprovider::OpenFileOptionsProto options;
     options.set_mount_id(mount_id);
     options.set_file_path(file_path.value());
     options.set_writeable(writeable);
@@ -105,7 +105,7 @@
   void CloseFile(int32_t mount_id,
                  int32_t file_id,
                  StatusCallback callback) override {
-    smbprovider::CloseFileOptions options;
+    smbprovider::CloseFileOptionsProto options;
     options.set_mount_id(mount_id);
     options.set_file_id(file_id);
     CallMethod(smbprovider::kCloseFileMethod, options,
@@ -117,7 +117,7 @@
                 int64_t offset,
                 int32_t length,
                 ReadFileCallback callback) override {
-    smbprovider::ReadFileOptions options;
+    smbprovider::ReadFileOptionsProto options;
     options.set_mount_id(mount_id);
     options.set_file_id(file_id);
     options.set_offset(offset);
@@ -130,7 +130,7 @@
                    const base::FilePath& entry_path,
                    bool recursive,
                    StatusCallback callback) override {
-    smbprovider::DeleteEntryOptions options;
+    smbprovider::DeleteEntryOptionsProto options;
     options.set_mount_id(mount_id);
     options.set_entry_path(entry_path.value());
     options.set_recursive(recursive);
@@ -141,7 +141,7 @@
   void CreateFile(int32_t mount_id,
                   const base::FilePath& file_path,
                   StatusCallback callback) override {
-    smbprovider::CreateFileOptions options;
+    smbprovider::CreateFileOptionsProto options;
     options.set_mount_id(mount_id);
     options.set_file_path(file_path.value());
     CallMethod(smbprovider::kCreateFileMethod, options,
diff --git a/chromeos/dbus/smb_provider_client.h b/chromeos/dbus/smb_provider_client.h
index c072b67..e4de2c7 100644
--- a/chromeos/dbus/smb_provider_client.h
+++ b/chromeos/dbus/smb_provider_client.h
@@ -23,14 +23,14 @@
  public:
   using GetMetdataEntryCallback =
       base::OnceCallback<void(smbprovider::ErrorType error,
-                              const smbprovider::DirectoryEntry& entry)>;
+                              const smbprovider::DirectoryEntryProto& entry)>;
   using MountCallback =
       base::OnceCallback<void(smbprovider::ErrorType error, int32_t mount_id)>;
   using OpenFileCallback =
       base::OnceCallback<void(smbprovider::ErrorType error, int32_t file_id)>;
-  using ReadDirectoryCallback =
-      base::OnceCallback<void(smbprovider::ErrorType error,
-                              const smbprovider::DirectoryEntryList& entries)>;
+  using ReadDirectoryCallback = base::OnceCallback<void(
+      smbprovider::ErrorType error,
+      const smbprovider::DirectoryEntryListProto& entries)>;
   using StatusCallback = base::OnceCallback<void(smbprovider::ErrorType error)>;
   using ReadFileCallback = base::OnceCallback<void(smbprovider::ErrorType error,
                                                    const base::ScopedFD& fd)>;
diff --git a/chromeos/printing/ppd_cache.cc b/chromeos/printing/ppd_cache.cc
index 9e358fc2..2a25921 100644
--- a/chromeos/printing/ppd_cache.cc
+++ b/chromeos/printing/ppd_cache.cc
@@ -87,12 +87,13 @@
 }
 
 // Store implementation, blocks on file access.  Must be run on a thread that
-// allows I/O.
+// allows I/O.  If |age| is non-zero, explicitly set the age of the resulting
+// file to be |age| before Now.
 void StoreImpl(const base::FilePath& cache_dir,
                const std::string& key,
-               const std::string& contents) {
+               const std::string& contents,
+               base::TimeDelta age) {
   base::AssertBlockingAllowed();
-
   MaybeCreateCache(cache_dir);
   if (contents.size() > kMaxPpdSizeBytes) {
     LOG(ERROR) << "Ignoring attempt to cache large object";
@@ -111,6 +112,12 @@
       if (!base::DeleteFile(path, false)) {
         LOG(ERROR) << "Failed to cleanup failed creation.";
       }
+    } else {
+      // Successfully wrote the file, adjust the age if requested.
+      if (!age.is_zero()) {
+        base::Time mod_time = base::Time::Now() - age;
+        file.SetTimes(mod_time, mod_time);
+      }
     }
   }
 }
@@ -122,14 +129,13 @@
 // callback is run.
 class PpdCacheImpl : public PpdCache {
  public:
-  explicit PpdCacheImpl(const base::FilePath& cache_base_dir)
+  explicit PpdCacheImpl(
+      const base::FilePath& cache_base_dir,
+      scoped_refptr<base::SequencedTaskRunner> fetch_task_runner,
+      scoped_refptr<base::SequencedTaskRunner> store_task_runner)
       : cache_base_dir_(cache_base_dir),
-        fetch_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
-            {base::TaskPriority::USER_VISIBLE, base::MayBlock(),
-             base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
-        store_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
-            {base::TaskPriority::BACKGROUND, base::MayBlock(),
-             base::TaskShutdownBehavior::BLOCK_SHUTDOWN})) {}
+        fetch_task_runner_(std::move(fetch_task_runner)),
+        store_task_runner_(std::move(store_task_runner)) {}
 
   // Public API functions.
   void Find(const std::string& key, FindCallback cb) override {
@@ -144,7 +150,17 @@
              const std::string& contents,
              const base::Closure& cb) override {
     store_task_runner_->PostTaskAndReply(
-        FROM_HERE, base::Bind(&StoreImpl, cache_base_dir_, key, contents), cb);
+        FROM_HERE,
+        base::Bind(&StoreImpl, cache_base_dir_, key, contents,
+                   base::TimeDelta()),
+        cb);
+  }
+
+  void StoreForTesting(const std::string& key,
+                       const std::string& contents,
+                       base::TimeDelta age) override {
+    store_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&StoreImpl, cache_base_dir_, key, contents, age));
   }
 
  private:
@@ -161,7 +177,21 @@
 
 // static
 scoped_refptr<PpdCache> PpdCache::Create(const base::FilePath& cache_base_dir) {
-  return scoped_refptr<PpdCache>(new PpdCacheImpl(cache_base_dir));
+  return scoped_refptr<PpdCache>(
+      new PpdCacheImpl(cache_base_dir,
+                       base::CreateSequencedTaskRunnerWithTraits(
+                           {base::TaskPriority::USER_VISIBLE, base::MayBlock(),
+                            base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}),
+                       base::CreateSequencedTaskRunnerWithTraits(
+                           {base::TaskPriority::BACKGROUND, base::MayBlock(),
+                            base::TaskShutdownBehavior::BLOCK_SHUTDOWN})));
+}
+
+scoped_refptr<PpdCache> PpdCache::CreateForTesting(
+    const base::FilePath& cache_base_dir,
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
+  return scoped_refptr<PpdCache>(
+      new PpdCacheImpl(cache_base_dir, io_task_runner, io_task_runner));
 }
 
 }  // namespace chromeos
diff --git a/chromeos/printing/ppd_cache.h b/chromeos/printing/ppd_cache.h
index 9743320..96a717b 100644
--- a/chromeos/printing/ppd_cache.h
+++ b/chromeos/printing/ppd_cache.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "chromeos/chromeos_export.h"
 
@@ -23,8 +24,6 @@
 // the cache).  However, changing *any* field in PpdReference will make the
 // previous cache entry invalid.  This is the intentional behavior -- we want to
 // re-run the resolution logic if we have new meta-information about a printer.
-//
-// All cache functions must be called on a thread which is permitted to do I/O.
 class CHROMEOS_EXPORT PpdCache : public base::RefCounted<PpdCache> {
  public:
   struct FindResult {
@@ -32,10 +31,10 @@
     // valid.
     bool success = false;
 
-    // How old is this entry?
+    // How old is this entry?  Zero on failure.
     base::TimeDelta age;
 
-    // Contents of the entry.
+    // Contents of the entry.  Empty on failure.
     std::string contents;
   };
 
@@ -46,16 +45,28 @@
   // cache needs to store state.
   static scoped_refptr<PpdCache> Create(const base::FilePath& cache_base_dir);
 
+  // Create a PpdCache that uses the given task runner for background
+  // processing.
+  static scoped_refptr<PpdCache> CreateForTesting(
+      const base::FilePath& cache_base_dir,
+      scoped_refptr<base::SequencedTaskRunner> io_task_runner);
+
   // Start a Find, looking, for an entry with the given key that is at most
   // |max_age| old.  |cb| will be invoked on the calling thread.
   virtual void Find(const std::string& key, FindCallback cb) = 0;
 
-  // Store the given contents at the given key.  If cb is non-null, it will
-  // be invoked on completion.
+  // Store |contents| at the the location indicated by |key|.  |cb| will be
+  // invoked on completion.
   virtual void Store(const std::string& key,
                      const std::string& contents,
                      const base::Closure& cb) = 0;
 
+  // Store the given contents at the given key, and change the resulting
+  // cache file's last modified date to be |age| before now.
+  virtual void StoreForTesting(const std::string& key,
+                               const std::string& contents,
+                               base::TimeDelta age) = 0;
+
  protected:
   friend class base::RefCounted<PpdCache>;
   virtual ~PpdCache() {}
diff --git a/chromeos/printing/ppd_cache_unittest.cc b/chromeos/printing/ppd_cache_unittest.cc
index d7d3dae..bf24cd7 100644
--- a/chromeos/printing/ppd_cache_unittest.cc
+++ b/chromeos/printing/ppd_cache_unittest.cc
@@ -112,5 +112,24 @@
   EXPECT_FALSE(find_result_.success);
 }
 
+// Test that we fill in the age field with something plausible.
+TEST_F(PpdCacheTest, HitAge) {
+  auto cache = CreateTestCache();
+  const char kTestKey[] = "My totally awesome key";
+  const char kTestContents[] = "Like, totally awesome contents";
+  cache->Store(
+      kTestKey, kTestContents,
+      base::Bind(&PpdCacheTest::CaptureStoreResult, base::Unretained(this)));
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_store_results_, 1);
+
+  cache->Find(kTestKey, base::Bind(&PpdCacheTest::CaptureFindResult,
+                                   base::Unretained(this)));
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_find_results_, 1);
+  // The age should be well under a second, but accept anything under an hour.
+  EXPECT_LT(find_result_.age, TimeDelta::FromHours(1));
+}
+
 }  // namespace
 }  // namespace chromeos
diff --git a/chromeos/printing/ppd_provider.cc b/chromeos/printing/ppd_provider.cc
index 52052ee..3cb38841 100644
--- a/chromeos/printing/ppd_provider.cc
+++ b/chromeos/printing/ppd_provider.cc
@@ -128,6 +128,18 @@
   std::unique_ptr<std::unordered_map<std::string, PrintersJSON>> printers;
 };
 
+// Carried information for an inflight PPD resolution.
+struct PpdResolutionQueueEntry {
+  // Original reference being resolved.
+  Printer::PpdReference reference;
+
+  // If non-empty, the contents from the cache for this resolution.
+  std::string cached_contents;
+
+  // Callback to be invoked on completion.
+  PpdProvider::ResolvePpdCallback callback;
+};
+
 // Extract cupsFilter/cupsFilter2 filter names from a line from a ppd.
 
 // cupsFilter2 lines look like this:
@@ -232,20 +244,6 @@
   return filled_fields == 1;
 }
 
-std::string PpdReferenceToCacheKey(const Printer::PpdReference& reference) {
-  DCHECK(PpdReferenceIsWellFormed(reference));
-  // The key prefixes here are arbitrary, but ensure we can't have an (unhashed)
-  // collision between keys generated from different PpdReference fields.
-  if (!reference.effective_make_and_model.empty()) {
-    return std::string("em:") + reference.effective_make_and_model;
-  } else {
-    return std::string("up:") + reference.user_supplied_ppd_url;
-  }
-}
-
-// Handles the result after PPD storage.
-void OnPpdStored() {}
-
 // Fetch the file pointed at by |url| and store it in |file_contents|.
 // Returns true if the fetch was successful.
 bool FetchFile(const GURL& url, std::string* file_contents) {
@@ -458,15 +456,15 @@
     }
     while (!ppd_resolution_queue_.empty()) {
       auto& next = ppd_resolution_queue_.front();
-      if (!next.first.user_supplied_ppd_url.empty()) {
-        DCHECK(next.first.effective_make_and_model.empty());
-        GURL url(next.first.user_supplied_ppd_url);
+      if (!next.reference.user_supplied_ppd_url.empty()) {
+        DCHECK(next.reference.effective_make_and_model.empty());
+        GURL url(next.reference.user_supplied_ppd_url);
         DCHECK(url.is_valid());
         StartFetch(url, FT_PPD);
         return;
       }
-      DCHECK(!next.first.effective_make_and_model.empty());
-      int ppd_index_shard = IndexShard(next.first.effective_make_and_model);
+      DCHECK(!next.reference.effective_make_and_model.empty());
+      int ppd_index_shard = IndexShard(next.reference.effective_make_and_model);
       if (!base::ContainsKey(cached_ppd_idxs_, ppd_index_shard)) {
         // Have to have the ppd index before we can resolve by ppd server
         // key.
@@ -475,7 +473,7 @@
       }
       // Get the URL from the ppd index and start the fetch.
       auto& cached_ppd_index = cached_ppd_idxs_[ppd_index_shard];
-      auto it = cached_ppd_index.find(next.first.effective_make_and_model);
+      auto it = cached_ppd_index.find(next.reference.effective_make_and_model);
       if (it != cached_ppd_index.end()) {
         StartFetch(GetPpdURL(it->second), FT_PPD);
         return;
@@ -483,11 +481,11 @@
       // This ppd reference isn't in the index.  That's not good. Fail
       // out the current resolution and go try to start the next
       // thing if there is one.
-      LOG(ERROR) << "PPD " << next.first.effective_make_and_model
+      LOG(ERROR) << "PPD " << next.reference.effective_make_and_model
                  << " not found in server index";
 
-      FinishPpdResolution(std::move(next.second), PpdProvider::INTERNAL_ERROR,
-                          std::string());
+      FinishPpdResolution(std::move(next.callback), {},
+                          PpdProvider::INTERNAL_ERROR);
       ppd_resolution_queue_.pop_front();
     }
   }
@@ -545,10 +543,10 @@
     // Do a sanity check here, so we can assume |reference| is well-formed in
     // the rest of this class.
     if (!PpdReferenceIsWellFormed(lowercase_reference)) {
-      FinishPpdResolution(std::move(cb), PpdProvider::INTERNAL_ERROR,
-                          std::string());
+      FinishPpdResolution(std::move(cb), {}, PpdProvider::INTERNAL_ERROR);
       return;
     }
+
     // First step, check the cache.  If the cache lookup fails, we'll (try to)
     // consult the server.
     ppd_cache_->Find(PpdReferenceToCacheKey(lowercase_reference),
@@ -706,18 +704,23 @@
     OnURLFetchComplete(nullptr);
   }
 
+  // Tidy up loose ends on an outstanding PPD resolution.
+  //
+  // If |ppd_contents| is non-empty, the request is resolved successfully
+  // using those contents.  Otherwise |error_code| and an empty ppd
+  // is given to |cb|.
   void FinishPpdResolution(ResolvePpdCallback cb,
-                           PpdProvider::CallbackResultCode result_code,
-                           const std::string& ppd_contents) {
-    if (result_code == PpdProvider::SUCCESS) {
+                           const std::string& ppd_contents,
+                           PpdProvider::CallbackResultCode error_code) {
+    if (!ppd_contents.empty()) {
       base::SequencedTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::BindOnce(std::move(cb), PpdProvider::SUCCESS, ppd_contents,
                          ExtractFiltersFromPpd(ppd_contents)));
     } else {
-      // Just post the failure.
+      DCHECK_NE(error_code, PpdProvider::SUCCESS);
       base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(cb), result_code, std::string(),
+          FROM_HERE, base::BindOnce(std::move(cb), error_code, std::string(),
                                     std::vector<std::string>()));
     }
   }
@@ -728,12 +731,22 @@
   void ResolvePpdCacheLookupDone(const Printer::PpdReference& reference,
                                  ResolvePpdCallback cb,
                                  const PpdCache::FindResult& result) {
-    if (result.success) {
-      // Cache hit.
-      FinishPpdResolution(std::move(cb), PpdProvider::SUCCESS, result.contents);
+    // If all of the following are true, we use the cache result now:
+    //
+    // * It was a cache hit
+    // * The reference is not from a user-supplied ppd file
+    // * The cached data was fresh.
+    //
+    // In all other cases, we go through the full resolution flow (passing along
+    // the cached data, if we got any), even if we got something from the cache.
+    if (result.success && reference.user_supplied_ppd_url.empty() &&
+        result.age < options_.cache_staleness_age) {
+      DCHECK(!result.contents.empty());
+      FinishPpdResolution(std::move(cb), result.contents, PpdProvider::SUCCESS);
     } else {
-      // Cache miss.  Queue it to be satisfied by the fetcher queue.
-      ppd_resolution_queue_.push_back({reference, std::move(cb)});
+      // Save the cache result (if any), and queue up for resolution.
+      ppd_resolution_queue_.push_back(
+          {reference, result.contents, std::move(cb)});
       MaybeStartFetch();
     }
   }
@@ -879,7 +892,6 @@
         FailQueuedServerPpdResolutions(PpdProvider::INTERNAL_ERROR);
         return;
       }
-
       auto& cached_ppd_index = cached_ppd_idxs_[ppd_index_shard];
       for (const auto& entry : contents) {
         cached_ppd_index.insert(
@@ -894,19 +906,23 @@
   void OnPpdFetchComplete() {
     DCHECK(!ppd_resolution_queue_.empty());
     std::string contents;
-
+    auto& entry = ppd_resolution_queue_.front();
     if ((ValidateAndGetResponseAsString(&contents) != PpdProvider::SUCCESS)) {
-      FinishPpdResolution(std::move(ppd_resolution_queue_.front().second),
-                          PpdProvider::SERVER_ERROR, std::string());
+      FinishPpdResolution(std::move(entry.callback), entry.cached_contents,
+                          PpdProvider::SERVER_ERROR);
     } else if (contents.size() > kMaxPpdSizeBytes) {
-      FinishPpdResolution(std::move(ppd_resolution_queue_.front().second),
-                          PpdProvider::PPD_TOO_LARGE, std::string());
+      FinishPpdResolution(std::move(entry.callback), entry.cached_contents,
+                          PpdProvider::PPD_TOO_LARGE);
+    } else if (contents.empty()) {
+      FinishPpdResolution(std::move(entry.callback), entry.cached_contents,
+                          PpdProvider::INTERNAL_ERROR);
     } else {
+      // Success.  Cache it and return it to the user.
       ppd_cache_->Store(
-          PpdReferenceToCacheKey(ppd_resolution_queue_.front().first), contents,
-          base::Bind(&OnPpdStored));
-      FinishPpdResolution(std::move(ppd_resolution_queue_.front().second),
-                          PpdProvider::SUCCESS, contents);
+          PpdReferenceToCacheKey(ppd_resolution_queue_.front().reference),
+          contents, base::Bind(&base::DoNothing));
+      FinishPpdResolution(std::move(entry.callback), contents,
+                          PpdProvider::SUCCESS);
     }
     ppd_resolution_queue_.pop_front();
   }
@@ -1012,23 +1028,26 @@
     manufacturers_resolution_queue_.clear();
   }
 
-  // Fail all server-based ppd and ppd reference resolutions inflight, because
-  // we failed to grab the necessary index data from the server.  Note we leave
-  // any user-based ppd resolutions intact, as they don't depend on the data
-  // we're missing.
+  // Give up on all server-based ppd and ppd reference resolutions inflight,
+  // because we failed to grab the necessary index data from the server.
+  //
+  // User-based ppd resolutions, which depend on local files, are left in the
+  // queue.
+  //
+  // Other entries use cached data, if they found some, or failed outright.
   void FailQueuedServerPpdResolutions(PpdProvider::CallbackResultCode code) {
-    base::circular_deque<std::pair<Printer::PpdReference, ResolvePpdCallback>>
-        filtered_queue;
+    base::circular_deque<PpdResolutionQueueEntry> filtered_queue;
     for (auto& entry : ppd_resolution_queue_) {
-      if (!entry.first.user_supplied_ppd_url.empty()) {
+      if (!entry.reference.user_supplied_ppd_url.empty()) {
         filtered_queue.emplace_back(std::move(entry));
       } else {
-        FinishPpdResolution(std::move(entry.second), code, std::string());
+        FinishPpdResolution(std::move(entry.callback), entry.cached_contents,
+                            code);
       }
     }
     ppd_resolution_queue_ = std::move(filtered_queue);
 
-    // Everything in the ppdreference queue also depends on server information,
+    // Everything in the PpdReference queue also depends on server information,
     // so should also be failed.
     auto task_runner = base::SequencedTaskRunnerHandle::Get();
     for (const auto& entry : ppd_reference_resolution_queue_) {
@@ -1414,9 +1433,7 @@
   base::circular_deque<PrinterResolutionQueueEntry> printers_resolution_queue_;
 
   // Queued ResolvePpd() requests.
-
-  base::circular_deque<std::pair<Printer::PpdReference, ResolvePpdCallback>>
-      ppd_resolution_queue_;
+  base::circular_deque<PpdResolutionQueueEntry> ppd_resolution_queue_;
 
   // Queued ResolvePpdReference() requests.
   base::circular_deque<
@@ -1468,6 +1485,19 @@
 
 }  // namespace
 
+// static
+std::string PpdProvider::PpdReferenceToCacheKey(
+    const Printer::PpdReference& reference) {
+  DCHECK(PpdReferenceIsWellFormed(reference));
+  // The key prefixes here are arbitrary, but ensure we can't have an (unhashed)
+  // collision between keys generated from different PpdReference fields.
+  if (!reference.effective_make_and_model.empty()) {
+    return std::string("em:") + reference.effective_make_and_model;
+  } else {
+    return std::string("up:") + reference.user_supplied_ppd_url;
+  }
+}
+
 PpdProvider::PrinterSearchData::PrinterSearchData() = default;
 PpdProvider::PrinterSearchData::PrinterSearchData(
     const PrinterSearchData& other) = default;
diff --git a/chromeos/printing/ppd_provider.h b/chromeos/printing/ppd_provider.h
index 6c465adf..98abab0 100644
--- a/chromeos/printing/ppd_provider.h
+++ b/chromeos/printing/ppd_provider.h
@@ -47,7 +47,7 @@
     // Other error that is not expected to be transient.
     INTERNAL_ERROR,
 
-    // The provded PPD was too large to be processed.
+    // The provided PPD was too large to be processed.
     PPD_TOO_LARGE,
   };
 
@@ -56,6 +56,12 @@
   struct Options {
     Options() {}
 
+    // Any results from PpdCache older than this are treated as
+    // non-authoritative -- PpdProvider will attempt to re-resolve from the
+    // network anyways and only use the cache results if the network is
+    // unavailable.
+    base::TimeDelta cache_staleness_age = base::TimeDelta::FromDays(14);
+
     // Root of the ppd serving hierarchy.
     std::string ppd_server_root = "https://www.gstatic.com/chromeos_printing";
   };
@@ -180,6 +186,11 @@
   virtual void ReverseLookup(const std::string& effective_make_and_model,
                              const ReverseLookupCallback& cb) = 0;
 
+  // Transform from ppd reference to ppd cache key.  This is exposed for
+  // testing, and should not be used by other code.
+  static std::string PpdReferenceToCacheKey(
+      const Printer::PpdReference& reference);
+
  protected:
   friend class base::RefCounted<PpdProvider>;
   virtual ~PpdProvider() {}
diff --git a/chromeos/printing/ppd_provider_unittest.cc b/chromeos/printing/ppd_provider_unittest.cc
index 43ad93d..bae81eae 100644
--- a/chromeos/printing/ppd_provider_unittest.cc
+++ b/chromeos/printing/ppd_provider_unittest.cc
@@ -74,14 +74,28 @@
 
   void TearDown() override { StopFakePpdServer(); }
 
-  // Create and return a provider for a test that uses the given |locale|.
-  scoped_refptr<PpdProvider> CreateProvider(const std::string& locale) {
+  // Create and return a provider for a test that uses the given |locale|.  If
+  // run_cache_on_test_thread is true, we'll run the cache using the
+  // scoped_task_environment_; otherwise we'll let it spawn it's own background
+  // threads.  You should only run the cache on the test thread if you need to
+  // explicity drain cache actions independently of draining ppd provider
+  // actions; otherwise letting the cache spawn its own thread should be safe,
+  // and better exercises the code paths under test.
+  scoped_refptr<PpdProvider> CreateProvider(const std::string& locale,
+                                            bool run_cache_on_test_thread) {
     auto provider_options = PpdProvider::Options();
     provider_options.ppd_server_root = std::string("https://") + kPpdServer;
 
+    if (run_cache_on_test_thread) {
+      ppd_cache_ = PpdCache::CreateForTesting(
+          ppd_cache_temp_dir_.GetPath(),
+          scoped_task_environment_.GetMainThreadTaskRunner());
+    } else {
+      ppd_cache_ = PpdCache::Create(ppd_cache_temp_dir_.GetPath());
+    }
     return PpdProvider::Create(locale, request_context_getter_.get(),
-                               PpdCache::Create(ppd_cache_temp_dir_.GetPath()),
-                               base::Version("40.8.6753.09"), provider_options);
+                               ppd_cache_, base::Version("40.8.6753.09"),
+                               provider_options);
   }
 
   // Create an interceptor that serves a small fileset of ppd server files.
@@ -252,7 +266,7 @@
   void RunLocalizationTest(const std::string& browser_locale,
                            const std::string& expected_used_locale) {
     captured_resolve_manufacturers_.clear();
-    auto provider = CreateProvider(browser_locale);
+    auto provider = CreateProvider(browser_locale, false);
     provider->ResolveManufacturers(base::Bind(
         &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
     scoped_task_environment_.RunUntilIdle();
@@ -302,8 +316,9 @@
   base::ScopedTempDir ppd_cache_temp_dir_;
   base::ScopedTempDir interceptor_temp_dir_;
 
-  // Provider to be used in the test.
-  scoped_refptr<PpdProvider> ppd_provider_;
+  // Reference to the underlying ppd_cache_ so we can muck with it to test
+  // cache-dependent behavior of ppd_provider_.
+  scoped_refptr<PpdCache> ppd_cache_;
 
   // Misc extra stuff needed for the test environment to function.
   //  base::TestMessageLoop loop_;
@@ -313,7 +328,7 @@
 // Test that we get back manufacturer maps as expected.
 TEST_F(PpdProviderTest, ManufacturersFetch) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   // Issue two requests at the same time, both should be resolved properly.
   provider->ResolveManufacturers(base::Bind(
       &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
@@ -333,7 +348,7 @@
 // is almost exactly the same as the above test, we just don't bring up the fake
 // server first.
 TEST_F(PpdProviderTest, ManufacturersFetchNoServer) {
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   // Issue two requests at the same time, both should be resolved properly.
   provider->ResolveManufacturers(base::Bind(
       &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
@@ -363,7 +378,7 @@
 // simultaneously.
 TEST_F(PpdProviderTest, RepeatedMakeModel) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
 
   PpdProvider::PrinterSearchData unrecognized_printer;
   unrecognized_printer.make_and_model = {"Printer Printer"};
@@ -403,7 +418,7 @@
 // Test successful and unsuccessful usb resolutions.
 TEST_F(PpdProviderTest, UsbResolution) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
 
   PpdProvider::PrinterSearchData search_data;
 
@@ -458,7 +473,7 @@
 // sure we can get the PpdReference for each of the resolved printers.
 TEST_F(PpdProviderTest, ResolvePrinters) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
 
   // Grab the manufacturer list, but don't bother to save it, we know what
   // should be in it and we check that elsewhere.  We just need to run the
@@ -502,7 +517,7 @@
 // INTERNAL_ERROR.
 TEST_F(PpdProviderTest, ResolvePrintersBadReference) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   provider->ResolveManufacturers(base::Bind(&ResolveManufacturersNop));
   scoped_task_environment_.RunUntilIdle();
 
@@ -517,7 +532,7 @@
 // Test that if the server is unavailable, we get SERVER_ERRORs back out.
 TEST_F(PpdProviderTest, ResolvePrintersNoServer) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   provider->ResolveManufacturers(base::Bind(&ResolveManufacturersNop));
   scoped_task_environment_.RunUntilIdle();
 
@@ -538,7 +553,7 @@
 // Test a successful ppd resolution from an effective_make_and_model reference.
 TEST_F(PpdProviderTest, ResolveServerKeyPpd) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   Printer::PpdReference ref;
   ref.effective_make_and_model = "printer_b_ref";
   provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd,
@@ -561,7 +576,7 @@
 // implications.
 TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpdFromNetworkFails) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
 
   Printer::PpdReference ref;
   ref.user_supplied_ppd_url = base::StringPrintf(
@@ -579,7 +594,7 @@
 // reading from a file.  Note we shouldn't need the server to be up
 // to do this successfully, as we should be able to do this offline.
 TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpdFromFile) {
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
@@ -605,7 +620,7 @@
 // Test that we cache ppd resolutions when we fetch them and that we can resolve
 // from the cache without the server available.
 TEST_F(PpdProviderTest, ResolvedPpdsGetCached) {
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   std::string user_ppd_contents = "Woohoo";
   Printer::PpdReference ref;
   {
@@ -635,7 +650,7 @@
 
   // Recreate the provider to make sure we don't have any memory caches which
   // would mask problems with disk persistence.
-  provider = CreateProvider("en");
+  provider = CreateProvider("en", false);
 
   // Re-resolve.
   provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd,
@@ -651,7 +666,7 @@
 // from the ppds resolved.
 TEST_F(PpdProviderTest, ExtractPpdFilters) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   Printer::PpdReference ref;
   ref.effective_make_and_model = "printer_a_ref";
   provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd,
@@ -685,7 +700,7 @@
 // given effective make and model.
 TEST_F(PpdProviderTest, ReverseLookup) {
   StartFakePpdServer();
-  auto provider = CreateProvider("en");
+  auto provider = CreateProvider("en", false);
   std::string ref = "printer_a_ref";
   provider->ReverseLookup(ref,
                           base::Bind(&PpdProviderTest::CaptureReverseLookup,
@@ -710,5 +725,162 @@
   EXPECT_EQ(PpdProvider::NOT_FOUND, failed_capture.code);
 }
 
+// If we have a fresh entry in the cache, we shouldn't need to go out to the
+// network at all to successfully resolve a ppd.
+TEST_F(PpdProviderTest, FreshCacheHitNoNetworkTraffic) {
+  // Explicitly *not* starting a fake server.
+  std::string cached_ppd_contents =
+      "These cached contents are different from what's being served";
+  auto provider = CreateProvider("en", true);
+  Printer::PpdReference ref;
+  ref.effective_make_and_model = "printer_a_ref";
+  std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
+  // Cache exists, and is just created, so should be fresh.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents, base::TimeDelta());
+  scoped_task_environment_.RunUntilIdle();
+  provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd,
+                                       base::Unretained(this)));
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+
+  // Should get the cached (not served) results back, and not have hit the
+  // network.
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(cached_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+}
+
+// If we have a stale cache entry and a good network connection, does the cache
+// get refreshed during a resolution?
+TEST_F(PpdProviderTest, StaleCacheGetsRefreshed) {
+  StartFakePpdServer();
+  std::string cached_ppd_contents =
+      "These cached contents are different from what's being served";
+  auto provider = CreateProvider("en", true);
+  // printer_ref_a resolves to kCupsFilterPpdContents on the server.
+  std::string expected_ppd = kCupsFilterPpdContents;
+  Printer::PpdReference ref;
+  ref.effective_make_and_model = "printer_a_ref";
+  std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
+  // Cache exists, and is 6 months old, so really stale.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents,
+                              base::TimeDelta::FromDays(180));
+  scoped_task_environment_.RunUntilIdle();
+  provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd,
+                                       base::Unretained(this)));
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+
+  // Should get the served results back, not the stale cached ones.
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(captured_resolve_ppd_[0].ppd_contents, expected_ppd);
+  EXPECT_GT(interceptor_->GetHitCount(), 0);
+
+  // Check that the cache was also updated.
+  PpdCache::FindResult captured_find_result;
+  // This is just a complicated syntax around the idea "use the Find callback to
+  // save the result in captured_find_result.
+  ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
+                   base::BindOnce(
+                       [](PpdCache::FindResult* captured_find_result,
+                          const PpdCache::FindResult& find_result) {
+                         *captured_find_result = find_result;
+                       },
+                       &captured_find_result));
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_find_result.success, true);
+  EXPECT_EQ(captured_find_result.contents, expected_ppd);
+  EXPECT_LT(captured_find_result.age, base::TimeDelta::FromDays(1));
+}
+
+// Test that, if we have an old entry in the cache that needs to be refreshed,
+// and we fail to contact the server, we still use the cached version.
+TEST_F(PpdProviderTest, StaleCacheGetsUsedIfNetworkFails) {
+  // Note that we're explicitly *not* starting the Fake ppd server in this test.
+  std::string cached_ppd_contents =
+      "These cached contents are different from what's being served";
+  auto provider = CreateProvider("en", true);
+  Printer::PpdReference ref;
+  ref.effective_make_and_model = "printer_a_ref";
+  std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
+  // Cache exists, and is 6 months old, so really stale.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents,
+                              base::TimeDelta::FromDays(180));
+  scoped_task_environment_.RunUntilIdle();
+  provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd,
+                                       base::Unretained(this)));
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+
+  // Should successfully resolve from the cache, even though it's stale.
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(cached_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+
+  // Check that the cache is *not* updated; it should remain stale.
+  PpdCache::FindResult captured_find_result;
+  // This is just a complicated syntax around the idea "use the Find callback to
+  // save the result in captured_find_result.
+  ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
+                   base::BindOnce(
+                       [](PpdCache::FindResult* captured_find_result,
+                          const PpdCache::FindResult& find_result) {
+                         *captured_find_result = find_result;
+                       },
+                       &captured_find_result));
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_find_result.success, true);
+  EXPECT_EQ(captured_find_result.contents, cached_ppd_contents);
+  EXPECT_GT(captured_find_result.age, base::TimeDelta::FromDays(179));
+}
+
+// For user-provided ppds, we should always use the latest version on
+// disk if it still exists there.
+TEST_F(PpdProviderTest, UserPpdAlwaysRefreshedIfAvailable) {
+  base::ScopedTempDir temp_dir;
+  StartFakePpdServer();
+  std::string cached_ppd_contents = "Cached Ppd Contents";
+  std::string disk_ppd_contents = "Updated Ppd Contents";
+  auto provider = CreateProvider("en", true);
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
+
+  Printer::PpdReference ref;
+  ref.user_supplied_ppd_url =
+      base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
+
+  // Put cached_ppd_contents into the cache.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents, base::TimeDelta());
+  scoped_task_environment_.RunUntilIdle();
+
+  // Write different contents to disk, so that the cached contents are
+  // now stale.
+  ASSERT_EQ(base::WriteFile(filename, disk_ppd_contents.data(),
+                            disk_ppd_contents.size()),
+            static_cast<int>(disk_ppd_contents.size()));
+
+  provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd,
+                                       base::Unretained(this)));
+  scoped_task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(disk_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+
+  // Check that the cache was also updated with the new contents.
+  PpdCache::FindResult captured_find_result;
+  ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
+                   base::BindOnce(
+                       [](PpdCache::FindResult* captured_find_result,
+                          const PpdCache::FindResult& find_result) {
+                         *captured_find_result = find_result;
+                       },
+                       &captured_find_result));
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_find_result.success, true);
+  EXPECT_EQ(captured_find_result.contents, disk_ppd_contents);
+}
+
 }  // namespace
 }  // namespace chromeos
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index f9fd778..2fd093b 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -212,22 +212,36 @@
 }
 
 void AutofillAgent::DidChangeScrollOffset() {
-  if (!focus_requires_scroll_ && is_popup_possibly_visible_ &&
-      element_.Focused()) {
-    FormData form;
-    FormFieldData field;
-    if (form_util::FindFormAndFieldForFormControlElement(element_, &form,
-                                                         &field)) {
-      GetAutofillDriver()->TextFieldDidScroll(
-          form, field,
-          render_frame()->GetRenderView()->ElementBoundsInWindow(element_));
-    }
+  if (!focus_requires_scroll_) {
+    // Post a task here since scroll offset may change during layout.
+    // (https://crbug.com/804886)
+    weak_ptr_factory_.InvalidateWeakPtrs();
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&AutofillAgent::DidChangeScrollOffsetImpl,
+                                  weak_ptr_factory_.GetWeakPtr(), element_));
+  } else if (!IsKeyboardAccessoryEnabled()) {
+    HidePopup();
   }
+}
 
-  if (IsKeyboardAccessoryEnabled())
+void AutofillAgent::DidChangeScrollOffsetImpl(
+    const WebFormControlElement& element) {
+  if (element != element_ || focus_requires_scroll_ ||
+      !is_popup_possibly_visible_ || !element_.Focused())
     return;
 
-  HidePopup();
+  FormData form;
+  FormFieldData field;
+  if (form_util::FindFormAndFieldForFormControlElement(element_, &form,
+                                                       &field)) {
+    GetAutofillDriver()->TextFieldDidScroll(
+        form, field,
+        render_frame()->GetRenderView()->ElementBoundsInWindow(element_));
+  }
+
+  // Ignore subsequent scroll offset changes.
+  if (!IsKeyboardAccessoryEnabled())
+    HidePopup();
 }
 
 void AutofillAgent::FocusedNodeChanged(const WebNode& node) {
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 0ec39ed..e6f1b4a 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -193,6 +193,7 @@
   FRIEND_TEST_ALL_PREFIXES(FormAutocompleteTest, CollectFormlessElements);
 
   void OnTextFieldDidChange(const blink::WebInputElement& element);
+  void DidChangeScrollOffsetImpl(const blink::WebFormControlElement& element);
 
   // Shows the autofill suggestions for |element|. This call is asynchronous
   // and may or may not lead to the showing of a suggestion popup (no popup is
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index ab0c22d..3b969bd 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -1330,6 +1330,8 @@
     std::set<ServerFieldType> seen_types;
     ServerFieldType previous_type = UNKNOWN_TYPE;
 
+    bool is_hidden_section = false;
+    base::string16 last_visible_section;
     for (const auto& field : fields_) {
       const ServerFieldType current_type = field->Type().GetStorableType();
       // All credit card fields belong to the same section that's different
@@ -1347,13 +1349,26 @@
       if (AutofillType(current_type).group() == PHONE_HOME)
         already_saw_current_type = false;
 
-      // Ignore non-focusable field and presentation role fields while inferring
-      // boundaries between sections.
       bool ignored_field =
           !field->is_focusable ||
           field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
-      if (ignored_field)
+
+      // This is the first visible field after a hidden section. Consider it as
+      // the continuation of the last visible section.
+      if (!ignored_field && is_hidden_section) {
+        current_section = last_visible_section;
+      }
+
+      // Start a new section by an ignored field, only if the next field is also
+      // already seen.
+      size_t field_index = &field - &fields_[0];
+      if (ignored_field &&
+          (is_hidden_section ||
+           !((field_index + 1) < fields_.size() &&
+             seen_types.count(
+                 fields_[field_index + 1]->Type().GetStorableType()) > 0))) {
         already_saw_current_type = false;
+      }
 
       // Some forms have adjacent fields of the same type.  Two common examples:
       //  * Forms with two email fields, where the second is meant to "confirm"
@@ -1368,8 +1383,17 @@
         already_saw_current_type = false;
 
       if (current_type != UNKNOWN_TYPE && already_saw_current_type) {
-        // We reached the end of a section, so start a new section.
-        seen_types.clear();
+        // Keep track of seen_types if the new section is hidden. The next
+        // visible section might be the continuation of the previous visible
+        // section.
+        if (ignored_field) {
+          is_hidden_section = true;
+          last_visible_section = current_section;
+        }
+        if (!is_hidden_section)
+          seen_types.clear();
+
+        // The end of a section, so start a new section.
         current_section = field->unique_name();
       }
 
@@ -1383,6 +1407,7 @@
       if (!ignored_field) {
         seen_types.insert(current_type);
         previous_type = current_type;
+        is_hidden_section = false;
       }
 
       field->set_section(base::UTF16ToUTF8(current_section));
diff --git a/components/exo/keyboard.h b/components/exo/keyboard.h
index 871e26a..8353519 100644
--- a/components/exo/keyboard.h
+++ b/components/exo/keyboard.h
@@ -39,6 +39,8 @@
   Keyboard(KeyboardDelegate* delegate, Seat* seat);
   ~Keyboard() override;
 
+  KeyboardDelegate* delegate() const { return delegate_; }
+
   bool HasDeviceConfigurationDelegate() const;
   void SetDeviceConfigurationDelegate(
       KeyboardDeviceConfigurationDelegate* delegate);
diff --git a/components/exo/pointer.h b/components/exo/pointer.h
index 5a87744..d3be265 100644
--- a/components/exo/pointer.h
+++ b/components/exo/pointer.h
@@ -48,6 +48,8 @@
   explicit Pointer(PointerDelegate* delegate);
   ~Pointer() override;
 
+  PointerDelegate* delegate() const { return delegate_; }
+
   // Set the pointer surface, i.e., the surface that contains the pointer image
   // (cursor). The |hotspot| argument defines the position of the pointer
   // surface relative to the pointer location. Its top-left corner is always at
diff --git a/components/exo/touch.h b/components/exo/touch.h
index 63b37a8..88d1048 100644
--- a/components/exo/touch.h
+++ b/components/exo/touch.h
@@ -27,6 +27,8 @@
   explicit Touch(TouchDelegate* delegate);
   ~Touch() override;
 
+  TouchDelegate* delegate() const { return delegate_; }
+
   // Set delegate for stylus events.
   void SetStylusDelegate(TouchStylusDelegate* delegate);
   bool HasStylusDelegate() const;
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 3c166c0d..4244919a 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -72,6 +72,7 @@
     "//third_party/wayland:wayland_server",
     "//third_party/wayland-protocols:alpha_compositing_protocol",
     "//third_party/wayland-protocols:gaming_input_protocol",
+    "//third_party/wayland-protocols:input_timestamps_protocol",
     "//third_party/wayland-protocols:keyboard_configuration_protocol",
     "//third_party/wayland-protocols:keyboard_extension_protocol",
     "//third_party/wayland-protocols:pointer_gestures_protocol",
@@ -153,6 +154,7 @@
   public_deps = [
     "//skia",
     "//third_party/wayland:wayland_client",
+    "//third_party/wayland-protocols:input_timestamps_protocol",
     "//third_party/wayland-protocols:linux_dmabuf_protocol",
     "//third_party/wayland-protocols:presentation_time_protocol",
   ]
@@ -183,6 +185,7 @@
     "//build/config:exe_and_shlib_deps",
     "//skia",
     "//third_party/wayland:wayland_client",
+    "//third_party/wayland-protocols:input_timestamps_protocol",
     "//third_party/wayland-protocols:linux_dmabuf_protocol",
     "//third_party/wayland-protocols:presentation_time_protocol",
     "//ui/gfx/geometry",
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index 88e6255..92ef697 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -112,6 +112,10 @@
   } else if (strcmp(interface, "wl_subcompositor") == 0) {
     globals->subcompositor.reset(static_cast<wl_subcompositor*>(
         wl_registry_bind(registry, id, &wl_subcompositor_interface, 1)));
+  } else if (strcmp(interface, "zwp_input_timestamps_manager_v1") == 0) {
+    globals->input_timestamps_manager.reset(
+        static_cast<zwp_input_timestamps_manager_v1*>(wl_registry_bind(
+            registry, id, &zwp_input_timestamps_manager_v1_interface, 1)));
   }
 }
 
diff --git a/components/exo/wayland/clients/client_base.h b/components/exo/wayland/clients/client_base.h
index 3122ce5..4b395db 100644
--- a/components/exo/wayland/clients/client_base.h
+++ b/components/exo/wayland/clients/client_base.h
@@ -68,6 +68,7 @@
     std::unique_ptr<wl_seat> seat;
     std::unique_ptr<wl_subcompositor> subcompositor;
     std::unique_ptr<zaura_shell> aura_shell;
+    std::unique_ptr<zwp_input_timestamps_manager_v1> input_timestamps_manager;
   };
 
   struct Buffer {
diff --git a/components/exo/wayland/clients/client_helper.cc b/components/exo/wayland/clients/client_helper.cc
index 943e3045..7d0a1ec 100644
--- a/components/exo/wayland/clients/client_helper.cc
+++ b/components/exo/wayland/clients/client_helper.cc
@@ -4,6 +4,7 @@
 
 #include "components/exo/wayland/clients/client_helper.h"
 
+#include <input-timestamps-unstable-v1-client-protocol.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
 #include <wayland-client-core.h>
@@ -47,6 +48,9 @@
 DEFAULT_DELETER(zaura_shell, zaura_shell_destroy)
 DEFAULT_DELETER(zaura_surface, zaura_surface_destroy)
 DEFAULT_DELETER(zaura_output, zaura_output_destroy)
+DEFAULT_DELETER(zwp_input_timestamps_manager_v1,
+                zwp_input_timestamps_manager_v1_destroy);
+DEFAULT_DELETER(zwp_input_timestamps_v1, zwp_input_timestamps_v1_destroy)
 DEFAULT_DELETER(zwp_linux_buffer_params_v1, zwp_linux_buffer_params_v1_destroy)
 DEFAULT_DELETER(zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1_destroy)
 
diff --git a/components/exo/wayland/clients/client_helper.h b/components/exo/wayland/clients/client_helper.h
index 0f3eb96f..f791086 100644
--- a/components/exo/wayland/clients/client_helper.h
+++ b/components/exo/wayland/clients/client_helper.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_EXO_WAYLAND_CLIENTS_CLIENT_HELPER_H_
 #define COMPONENTS_EXO_WAYLAND_CLIENTS_CLIENT_HELPER_H_
 
+#include <input-timestamps-unstable-v1-client-protocol.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
 #include <wayland-client-core.h>
@@ -52,6 +53,8 @@
 DEFAULT_DELETER_FDECL(zaura_shell)
 DEFAULT_DELETER_FDECL(zaura_surface)
 DEFAULT_DELETER_FDECL(zaura_output)
+DEFAULT_DELETER_FDECL(zwp_input_timestamps_manager_v1)
+DEFAULT_DELETER_FDECL(zwp_input_timestamps_v1)
 DEFAULT_DELETER_FDECL(zwp_linux_buffer_params_v1)
 DEFAULT_DELETER_FDECL(zwp_linux_dmabuf_v1)
 
diff --git a/components/exo/wayland/clients/rects.cc b/components/exo/wayland/clients/rects.cc
index f15af306..3c74efa5 100644
--- a/components/exo/wayland/clients/rects.cc
+++ b/components/exo/wayland/clients/rects.cc
@@ -47,7 +47,11 @@
 // Benchmark warmup frames before starting measurement.
 const int kBenchmarkWarmupFrames = 10;
 
-using EventTimeStack = std::vector<uint32_t>;
+struct EventTimes {
+  std::vector<base::TimeTicks> motion_timestamps;
+  base::TimeTicks pointer_timestamp;
+  base::TimeTicks touch_timestamp;
+};
 
 void PointerEnter(void* data,
                   wl_pointer* pointer,
@@ -66,9 +70,9 @@
                    uint32_t time,
                    wl_fixed_t x,
                    wl_fixed_t y) {
-  EventTimeStack* stack = static_cast<EventTimeStack*>(data);
+  EventTimes* event_times = static_cast<EventTimes*>(data);
 
-  stack->push_back(time);
+  event_times->motion_timestamps.push_back(event_times->pointer_timestamp);
 }
 
 void PointerButton(void* data,
@@ -119,9 +123,9 @@
                  int32_t id,
                  wl_fixed_t x,
                  wl_fixed_t y) {
-  EventTimeStack* stack = static_cast<EventTimeStack*>(data);
+  EventTimes* event_times = static_cast<EventTimes*>(data);
 
-  stack->push_back(time);
+  event_times->motion_timestamps.push_back(event_times->touch_timestamp);
 }
 
 void TouchFrame(void* data, wl_touch* touch) {}
@@ -207,6 +211,20 @@
   LOG(WARNING) << "Frame discarded";
 }
 
+void InputTimestamp(void* data,
+                    struct zwp_input_timestamps_v1* zwp_input_timestamps_v1,
+                    uint32_t tv_sec_hi,
+                    uint32_t tv_sec_lo,
+                    uint32_t tv_nsec) {
+  auto* timestamp = static_cast<base::TimeTicks*>(data);
+  int64_t seconds = (static_cast<int64_t>(tv_sec_hi) << 32) + tv_sec_lo;
+  int64_t microseconds = seconds * base::Time::kMicrosecondsPerSecond +
+                         tv_nsec / base::Time::kNanosecondsPerMicrosecond;
+
+  *timestamp =
+      base::TimeTicks() + base::TimeDelta::FromMicroseconds(microseconds);
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -237,7 +255,7 @@
   if (!ClientBase::Init(params))
     return 1;
 
-  EventTimeStack event_times;
+  EventTimes event_times;
 
   std::unique_ptr<wl_pointer> pointer(
       static_cast<wl_pointer*>(wl_seat_get_pointer(globals_.seat.get())));
@@ -262,6 +280,30 @@
                                       TouchFrame, TouchCancel};
   wl_touch_add_listener(touch.get(), &touch_listener, &event_times);
 
+  zwp_input_timestamps_v1_listener input_timestamps_listener = {InputTimestamp};
+
+  std::unique_ptr<zwp_input_timestamps_v1> pointer_timestamps(
+      zwp_input_timestamps_manager_v1_get_pointer_timestamps(
+          globals_.input_timestamps_manager.get(), pointer.get()));
+  if (!pointer_timestamps) {
+    LOG(ERROR) << "Can't get pointer timestamps";
+    return 1;
+  }
+  zwp_input_timestamps_v1_add_listener(pointer_timestamps.get(),
+                                       &input_timestamps_listener,
+                                       &event_times.pointer_timestamp);
+
+  std::unique_ptr<zwp_input_timestamps_v1> touch_timestamps(
+      zwp_input_timestamps_manager_v1_get_touch_timestamps(
+          globals_.input_timestamps_manager.get(), touch.get()));
+  if (!touch_timestamps) {
+    LOG(ERROR) << "Can't get touch timestamps";
+    return 1;
+  }
+  zwp_input_timestamps_v1_add_listener(touch_timestamps.get(),
+                                       &input_timestamps_listener,
+                                       &event_times.touch_timestamp);
+
   Schedule schedule;
   std::unique_ptr<wl_callback> frame_callback;
   wl_callback_listener frame_listener = {FrameCallback};
@@ -336,7 +378,7 @@
       }
 
       SkCanvas* canvas = buffer->sk_surface->getCanvas();
-      if (event_times.empty()) {
+      if (event_times.motion_timestamps.empty()) {
         canvas->clear(transparent_background_ ? SK_ColorTRANSPARENT
                                               : SK_ColorBLACK);
       } else {
@@ -344,20 +386,22 @@
         // since last frame. Latest event at the top.
         int y = 0;
         // Note: Rounding up to ensure we cover the whole canvas.
-        int h =
-            (size_.height() + (event_times.size() / 2)) / event_times.size();
-        while (!event_times.empty()) {
+        int h = (size_.height() + (event_times.motion_timestamps.size() / 2)) /
+                event_times.motion_timestamps.size();
+        while (!event_times.motion_timestamps.empty()) {
           SkIRect rect = SkIRect::MakeXYWH(0, y, size_.width(), h);
           SkPaint paint;
-          paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0,
-                                       (event_times.back() & 0x00ff00) >> 8,
-                                       (event_times.back() & 0xff0000) >> 16));
+          base::TimeDelta event_time =
+              event_times.motion_timestamps.back() - base::TimeTicks();
+          int64_t event_time_msec = event_time.InMilliseconds();
+          paint.setColor(SkColorSetRGB((event_time_msec & 0x0000ff) >> 0,
+                                       (event_time_msec & 0x00ff00) >> 8,
+                                       (event_time_msec & 0xff0000) >> 16));
           canvas->drawIRect(rect, paint);
-          std::string text = base::UintToString(event_times.back());
+          std::string text = base::NumberToString(event_time.InMicroseconds());
           canvas->drawText(text.c_str(), text.length(), 8, y + 32, text_paint);
-          frame->event_times.push_back(base::TimeTicks::FromInternalValue(
-              event_times.back() * base::Time::kMicrosecondsPerMillisecond));
-          event_times.pop_back();
+          frame->event_times.push_back(event_times.motion_timestamps.back());
+          event_times.motion_timestamps.pop_back();
           y += h;
         }
       }
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index cfe4708..1c187a9 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -9,6 +9,7 @@
 #include <gaming-input-unstable-v1-server-protocol.h>
 #include <gaming-input-unstable-v2-server-protocol.h>
 #include <grp.h>
+#include <input-timestamps-unstable-v1-server-protocol.h>
 #include <keyboard-configuration-unstable-v1-server-protocol.h>
 #include <keyboard-extension-unstable-v1-server-protocol.h>
 #include <linux/input.h>
@@ -196,6 +197,41 @@
   return TimeTicksToMilliseconds(base::TimeTicks::Now());
 }
 
+class WaylandInputDelegate {
+ public:
+  class Observer {
+   public:
+    virtual void OnDelegateDestroying(WaylandInputDelegate* delegate) = 0;
+    virtual void OnSendTimestamp(base::TimeTicks time_stamp) = 0;
+
+   protected:
+    virtual ~Observer() = default;
+  };
+
+  void AddObserver(Observer* observer) { observers_.AddObserver(observer); }
+
+  void RemoveObserver(Observer* observer) {
+    observers_.RemoveObserver(observer);
+  }
+
+  void SendTimestamp(base::TimeTicks time_stamp) {
+    for (auto& observer : observers_)
+      observer.OnSendTimestamp(time_stamp);
+  }
+
+ protected:
+  WaylandInputDelegate() = default;
+  virtual ~WaylandInputDelegate() {
+    for (auto& observer : observers_)
+      observer.OnDelegateDestroying(this);
+  }
+
+ private:
+  base::ObserverList<Observer> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandInputDelegate);
+};
+
 uint32_t WaylandDataDeviceManagerDndAction(DndAction action) {
   switch (action) {
     case DndAction::kNone:
@@ -3130,7 +3166,8 @@
 
 // Pointer delegate class that accepts events for surfaces owned by the same
 // client as a pointer resource.
-class WaylandPointerDelegate : public PointerDelegate {
+class WaylandPointerDelegate : public WaylandInputDelegate,
+                               public PointerDelegate {
  public:
   explicit WaylandPointerDelegate(wl_resource* pointer_resource)
       : pointer_resource_(pointer_resource) {}
@@ -3162,6 +3199,7 @@
   }
   void OnPointerMotion(base::TimeTicks time_stamp,
                        const gfx::PointF& location) override {
+    SendTimestamp(time_stamp);
     wl_pointer_send_motion(
         pointer_resource_, TimeTicksToMilliseconds(time_stamp),
         wl_fixed_from_double(location.x()), wl_fixed_from_double(location.y()));
@@ -3182,6 +3220,7 @@
     uint32_t serial = next_serial();
     for (auto button : buttons) {
       if (button_flags & button.flag) {
+        SendTimestamp(time_stamp);
         wl_pointer_send_button(
             pointer_resource_, serial, TimeTicksToMilliseconds(time_stamp),
             button.value, pressed ? WL_POINTER_BUTTON_STATE_PRESSED
@@ -3203,11 +3242,13 @@
     }
 
     double x_value = offset.x() * kAxisStepDistance;
+    SendTimestamp(time_stamp);
     wl_pointer_send_axis(pointer_resource_, TimeTicksToMilliseconds(time_stamp),
                          WL_POINTER_AXIS_HORIZONTAL_SCROLL,
                          wl_fixed_from_double(-x_value));
 
     double y_value = offset.y() * kAxisStepDistance;
+    SendTimestamp(time_stamp);
     wl_pointer_send_axis(pointer_resource_, TimeTicksToMilliseconds(time_stamp),
                          WL_POINTER_AXIS_VERTICAL_SCROLL,
                          wl_fixed_from_double(-y_value));
@@ -3215,9 +3256,11 @@
   void OnPointerScrollStop(base::TimeTicks time_stamp) override {
     if (wl_resource_get_version(pointer_resource_) >=
         WL_POINTER_AXIS_STOP_SINCE_VERSION) {
+      SendTimestamp(time_stamp);
       wl_pointer_send_axis_stop(pointer_resource_,
                                 TimeTicksToMilliseconds(time_stamp),
                                 WL_POINTER_AXIS_HORIZONTAL_SCROLL);
+      SendTimestamp(time_stamp);
       wl_pointer_send_axis_stop(pointer_resource_,
                                 TimeTicksToMilliseconds(time_stamp),
                                 WL_POINTER_AXIS_VERTICAL_SCROLL);
@@ -3266,7 +3309,6 @@
 const struct wl_pointer_interface pointer_implementation = {pointer_set_cursor,
                                                             pointer_release};
 
-#if BUILDFLAG(USE_XKBCOMMON)
 
 ////////////////////////////////////////////////////////////////////////////////
 // wl_keyboard_interface:
@@ -3274,13 +3316,15 @@
 // Keyboard delegate class that accepts events for surfaces owned by the same
 // client as a keyboard resource.
 class WaylandKeyboardDelegate
-    : public KeyboardDelegate,
+    : public WaylandInputDelegate,
+      public KeyboardDelegate,
       public KeyboardObserver
 #if defined(OS_CHROMEOS)
     ,
       public chromeos::input_method::ImeKeyboard::Observer
 #endif
 {
+#if BUILDFLAG(USE_XKBCOMMON)
  public:
   explicit WaylandKeyboardDelegate(wl_resource* keyboard_resource)
       : keyboard_resource_(keyboard_resource),
@@ -3342,6 +3386,7 @@
                          ui::DomCode key,
                          bool pressed) override {
     uint32_t serial = next_serial();
+    SendTimestamp(time_stamp);
     wl_keyboard_send_key(keyboard_resource_, serial,
                          TimeTicksToMilliseconds(time_stamp), DomCodeToKey(key),
                          pressed ? WL_KEYBOARD_KEY_STATE_PRESSED
@@ -3460,8 +3505,11 @@
   std::unique_ptr<xkb_state, ui::XkbStateDeleter> xkb_state_;
 
   DISALLOW_COPY_AND_ASSIGN(WaylandKeyboardDelegate);
+#endif
 };
 
+#if BUILDFLAG(USE_XKBCOMMON)
+
 void keyboard_release(wl_client* client, wl_resource* resource) {
   wl_resource_destroy(resource);
 }
@@ -3475,7 +3523,7 @@
 
 // Touch delegate class that accepts events for surfaces owned by the same
 // client as a touch resource.
-class WaylandTouchDelegate : public TouchDelegate {
+class WaylandTouchDelegate : public WaylandInputDelegate, public TouchDelegate {
  public:
   explicit WaylandTouchDelegate(wl_resource* touch_resource)
       : touch_resource_(touch_resource) {}
@@ -3495,18 +3543,21 @@
                    const gfx::PointF& location) override {
     wl_resource* surface_resource = GetSurfaceResource(surface);
     DCHECK(surface_resource);
+    SendTimestamp(time_stamp);
     wl_touch_send_down(touch_resource_, next_serial(),
                        TimeTicksToMilliseconds(time_stamp), surface_resource,
                        id, wl_fixed_from_double(location.x()),
                        wl_fixed_from_double(location.y()));
   }
   void OnTouchUp(base::TimeTicks time_stamp, int id) override {
+    SendTimestamp(time_stamp);
     wl_touch_send_up(touch_resource_, next_serial(),
                      TimeTicksToMilliseconds(time_stamp), id);
   }
   void OnTouchMotion(base::TimeTicks time_stamp,
                      int id,
                      const gfx::PointF& location) override {
+    SendTimestamp(time_stamp);
     wl_touch_send_motion(touch_resource_, TimeTicksToMilliseconds(time_stamp),
                          id, wl_fixed_from_double(location.x()),
                          wl_fixed_from_double(location.y()));
@@ -4637,6 +4688,94 @@
                                  data, nullptr);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// input_timestamps_v1 interface:
+
+class WaylandInputTimestamps : public WaylandInputDelegate::Observer {
+ public:
+  WaylandInputTimestamps(wl_resource* resource, WaylandInputDelegate* delegate)
+      : resource_(resource), delegate_(delegate) {
+    delegate_->AddObserver(this);
+  }
+
+  ~WaylandInputTimestamps() override {
+    if (delegate_)
+      delegate_->RemoveObserver(this);
+  }
+
+  // Overridden from WaylandInputDelegate::Observer:
+  void OnDelegateDestroying(WaylandInputDelegate* delegate) override {
+    DCHECK(delegate_ == delegate);
+    delegate_ = nullptr;
+  }
+  void OnSendTimestamp(base::TimeTicks time_stamp) override {
+    timespec ts = (time_stamp - base::TimeTicks()).ToTimeSpec();
+
+    zwp_input_timestamps_v1_send_timestamp(
+        resource_, static_cast<uint64_t>(ts.tv_sec) >> 32,
+        ts.tv_sec & 0xffffffff, ts.tv_nsec);
+  }
+
+ private:
+  wl_resource* const resource_;
+  WaylandInputDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandInputTimestamps);
+};
+
+void input_timestamps_destroy(struct wl_client* client,
+                              struct wl_resource* resource) {
+  wl_resource_destroy(resource);
+}
+
+const struct zwp_input_timestamps_v1_interface input_timestamps_implementation =
+    {input_timestamps_destroy};
+
+////////////////////////////////////////////////////////////////////////////////
+// input_timestamps_manager_v1 interface:
+
+void input_timestamps_manager_destroy(struct wl_client* client,
+                                      struct wl_resource* resource) {
+  wl_resource_destroy(resource);
+}
+
+template <typename T, typename D>
+void input_timestamps_manager_get_timestamps(wl_client* client,
+                                             wl_resource* resource,
+                                             uint32_t id,
+                                             wl_resource* input_resource) {
+  wl_resource* input_timestamps_resource =
+      wl_resource_create(client, &zwp_input_timestamps_v1_interface, 1, id);
+
+  auto input_timestamps = std::make_unique<WaylandInputTimestamps>(
+      input_timestamps_resource,
+      static_cast<WaylandInputDelegate*>(
+          static_cast<D*>(GetUserDataAs<T>(input_resource)->delegate())));
+
+  SetImplementation(input_timestamps_resource, &input_timestamps_implementation,
+                    std::move(input_timestamps));
+}
+
+const struct zwp_input_timestamps_manager_v1_interface
+    input_timestamps_manager_implementation = {
+        input_timestamps_manager_destroy,
+        input_timestamps_manager_get_timestamps<Keyboard,
+                                                WaylandKeyboardDelegate>,
+        input_timestamps_manager_get_timestamps<Pointer,
+                                                WaylandPointerDelegate>,
+        input_timestamps_manager_get_timestamps<Touch, WaylandTouchDelegate>};
+
+void bind_input_timestamps_manager(wl_client* client,
+                                   void* data,
+                                   uint32_t version,
+                                   uint32_t id) {
+  wl_resource* resource = wl_resource_create(
+      client, &zwp_input_timestamps_manager_v1_interface, 1, id);
+
+  wl_resource_set_implementation(
+      resource, &input_timestamps_manager_implementation, nullptr, nullptr);
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -4691,6 +4830,9 @@
                    display_, bind_stylus_tools);
   wl_global_create(wl_display_.get(), &zcr_keyboard_extension_v1_interface, 1,
                    display_, bind_keyboard_extension);
+  wl_global_create(wl_display_.get(),
+                   &zwp_input_timestamps_manager_v1_interface, 1, display_,
+                   bind_input_timestamps_manager);
 }
 
 Server::~Server() {}
diff --git a/components/metrics_services_manager/metrics_services_manager.cc b/components/metrics_services_manager/metrics_services_manager.cc
index 559e806..03c23eaf 100644
--- a/components/metrics_services_manager/metrics_services_manager.cc
+++ b/components/metrics_services_manager/metrics_services_manager.cc
@@ -165,4 +165,8 @@
                     client_->IsMetricsConsentGiven(), may_upload);
 }
 
+bool MetricsServicesManager::IsMetricsReportingEnabled() const {
+  return client_->IsMetricsReportingEnabled();
+}
+
 }  // namespace metrics_services_manager
diff --git a/components/metrics_services_manager/metrics_services_manager.h b/components/metrics_services_manager/metrics_services_manager.h
index 1a1e81b..912bf9a 100644
--- a/components/metrics_services_manager/metrics_services_manager.h
+++ b/components/metrics_services_manager/metrics_services_manager.h
@@ -80,6 +80,9 @@
   // Update the managed services when permissions for uploading metrics change.
   void UpdateUploadPermissions(bool may_upload);
 
+  // Gets the current state of metric reporting.
+  bool IsMetricsReportingEnabled() const;
+
  private:
   // Update the managed services when permissions for recording/uploading
   // metrics change.
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index 4b43a465..71d00033 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -104,7 +104,19 @@
   return http2_settings;
 }
 
-void ConfigureHttp2Params(base::StringPiece http2_trial_group,
+bool ConfigureWebsocketOverHttp2(
+    const base::CommandLine& command_line,
+    const VariationParameters& http2_trial_params) {
+  if (command_line.HasSwitch(switches::kEnableWebsocketOverHttp2))
+    return true;
+
+  const std::string websocket_value =
+      GetVariationParam(http2_trial_params, "websocket_over_http2");
+  return websocket_value == "true";
+}
+
+void ConfigureHttp2Params(const base::CommandLine& command_line,
+                          base::StringPiece http2_trial_group,
                           const VariationParameters& http2_trial_params,
                           net::HttpNetworkSession::Params* params) {
   if (http2_trial_group.starts_with(kHttp2FieldTrialDisablePrefix)) {
@@ -112,6 +124,8 @@
     return;
   }
   params->http2_settings = GetHttp2Settings(http2_trial_params);
+  params->enable_websocket_over_http2 =
+      ConfigureWebsocketOverHttp2(command_line, http2_trial_params);
 }
 
 bool ShouldEnableQuic(base::StringPiece quic_trial_group,
@@ -493,7 +507,8 @@
   if (!variations::GetVariationParams(kHttp2FieldTrialName,
                                       &http2_trial_params))
     http2_trial_params.clear();
-  ConfigureHttp2Params(http2_trial_group, http2_trial_params, params);
+  ConfigureHttp2Params(command_line, http2_trial_group, http2_trial_params,
+                       params);
 
   const std::string tfo_trial_group =
       base::FieldTrialList::FindFullName(kTCPFastOpenFieldTrialName);
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index b8d7dc77..4450e7b 100644
--- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -65,6 +65,7 @@
 
   EXPECT_TRUE(params_.enable_http2);
   EXPECT_TRUE(params_.http2_settings.empty());
+  EXPECT_FALSE(params_.enable_websocket_over_http2);
 
   EXPECT_FALSE(params_.enable_quic);
   EXPECT_EQ("Chrome/52.0.2709.0 Linux x86_64", params_.quic_user_agent_id);
@@ -774,4 +775,26 @@
   EXPECT_TRUE(params_.quic_headers_include_h2_stream_dependency);
 }
 
+TEST_F(NetworkSessionConfiguratorTest,
+       WebsocketOverHttp2EnabledFromCommandLine) {
+  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+  command_line.AppendSwitch(switches::kEnableWebsocketOverHttp2);
+
+  ParseCommandLineAndFieldTrials(command_line);
+
+  EXPECT_TRUE(params_.enable_websocket_over_http2);
+}
+
+TEST_F(NetworkSessionConfiguratorTest,
+       WebsocketOverHttp2EnabledFromFieldTrial) {
+  std::map<std::string, std::string> field_trial_params;
+  field_trial_params["websocket_over_http2"] = "true";
+  variations::AssociateVariationParams("HTTP2", "Enabled", field_trial_params);
+  base::FieldTrialList::CreateFieldTrial("HTTP2", "Enabled");
+
+  ParseFieldTrials();
+
+  EXPECT_TRUE(params_.enable_websocket_over_http2);
+}
+
 }  // namespace network_session_configurator
diff --git a/components/network_session_configurator/common/network_switch_list.h b/components/network_session_configurator/common/network_switch_list.h
index 723e78d..ff5ea223 100644
--- a/components/network_session_configurator/common/network_switch_list.h
+++ b/components/network_session_configurator/common/network_switch_list.h
@@ -11,6 +11,9 @@
 // Disables the HTTP/2 protocol.
 NETWORK_SWITCH(kDisableHttp2, "disable-http2")
 
+// Enable Websocket over HTTP/2.
+NETWORK_SWITCH(kEnableWebsocketOverHttp2, "enable-websocket-over-http2")
+
 // Enables Alternate-Protocol when the port is user controlled (> 1024).
 NETWORK_SWITCH(kEnableUserAlternateProtocolPorts,
                "enable-user-controlled-alternate-protocol-ports")
diff --git a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
index e5055d8c..5472f3e4 100644
--- a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
+++ b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
@@ -68,6 +68,8 @@
   return item;
 }
 
+void GetAllItemsDummyCallback(const std::vector<OfflineItem>& items) {}
+
 }  // namespace
 
 class RecentTabSuggestionsProviderTestNoLoad : public testing::Test {
@@ -89,6 +91,8 @@
             ui_adapter_);
     provider_ = std::make_unique<RecentTabSuggestionsProvider>(
         &observer_, ui_adapter_, pref_service());
+    // Force adapter to load its cache.
+    ui_adapter_->GetAllItems(base::BindOnce(&GetAllItemsDummyCallback));
   }
 
   Category recent_tabs_category() {
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
index d33d3f03..1150c058 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
@@ -15,9 +15,9 @@
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
 #include "components/ntp_snippets/user_classifier.h"
+#include "components/signin/core/browser/signin_manager_base.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
-#include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
 
 using language::UrlLanguageHistogram;
@@ -124,7 +124,8 @@
 }  // namespace
 
 RemoteSuggestionsFetcherImpl::RemoteSuggestionsFetcherImpl(
-    identity::IdentityManager* identity_manager,
+    SigninManagerBase* signin_manager,
+    OAuth2TokenService* token_service,
     scoped_refptr<URLRequestContextGetter> url_request_context_getter,
     PrefService* pref_service,
     UrlLanguageHistogram* language_histogram,
@@ -132,7 +133,8 @@
     const GURL& api_endpoint,
     const std::string& api_key,
     const UserClassifier* user_classifier)
-    : identity_manager_(identity_manager),
+    : signin_manager_(signin_manager),
+      token_service_(token_service),
       url_request_context_getter_(std::move(url_request_context_getter)),
       language_histogram_(language_histogram),
       parse_json_callback_(parse_json_callback),
@@ -177,7 +179,7 @@
       .SetUrlRequestContextGetter(url_request_context_getter_)
       .SetUserClassifier(*user_classifier_);
 
-  if (identity_manager_->HasPrimaryAccount()) {
+  if (signin_manager_->IsAuthenticated()) {
     // Signed-in: get OAuth token --> fetch suggestions.
     pending_requests_.emplace(std::move(builder), std::move(callback));
     StartTokenRequest();
@@ -209,7 +211,7 @@
     const std::string& oauth_access_token) {
   // TODO(jkrcal, treib): Add unit-tests for authenticated fetches.
   builder.SetUrl(fetch_url_)
-      .SetAuthentication(identity_manager_->GetPrimaryAccountInfo().account_id,
+      .SetAuthentication(signin_manager_->GetAuthenticatedAccountId(),
                          base::StringPrintf(kAuthorizationRequestHeaderFormat,
                                             oauth_access_token.c_str()));
   StartRequest(std::move(builder), std::move(callback));
@@ -232,8 +234,8 @@
   }
 
   OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
-  token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForPrimaryAccount(
-      "ntp_snippets", scopes,
+  token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
+      "ntp_snippets", signin_manager_, token_service_, scopes,
       base::BindOnce(&RemoteSuggestionsFetcherImpl::AccessTokenFetchFinished,
                      base::Unretained(this)),
       identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h
index f5a33841..0d95ca46 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h
@@ -20,14 +20,15 @@
 #include "components/ntp_snippets/remote/request_params.h"
 #include "net/url_request/url_request_context_getter.h"
 
+class OAuth2TokenService;
 class PrefService;
+class SigninManagerBase;
 
 namespace base {
 class Value;
 }  // namespace base
 
 namespace identity {
-class IdentityManager;
 class PrimaryAccountAccessTokenFetcher;
 }
 
@@ -42,7 +43,8 @@
 class RemoteSuggestionsFetcherImpl : public RemoteSuggestionsFetcher {
  public:
   RemoteSuggestionsFetcherImpl(
-      identity::IdentityManager* identity_manager,
+      SigninManagerBase* signin_manager,
+      OAuth2TokenService* token_service,
       scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
       PrefService* pref_service,
       language::UrlLanguageHistogram* language_histogram,
@@ -88,7 +90,8 @@
                      const std::string& error_details);
 
   // Authentication for signed-in users.
-  identity::IdentityManager* identity_manager_;
+  SigninManagerBase* signin_manager_;
+  OAuth2TokenService* token_service_;
 
   std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_;
 
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index f0779a4..67d205b 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -10,7 +10,6 @@
 
 #include "base/containers/circular_deque.h"
 #include "base/json/json_reader.h"
-#include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/test_mock_time_task_runner.h"
@@ -27,12 +26,14 @@
 #include "components/ntp_snippets/remote/test_utils.h"
 #include "components/ntp_snippets/user_classifier.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
 #include "components/variations/entropy_provider.h"
 #include "components/variations/variations_params_manager.h"
+#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_test_util.h"
-#include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -58,7 +59,7 @@
 const char kTestChromeContentSuggestionsSignedInUrl[] =
     "https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/fetch";
 
-const char kTestAccount[] = "foo@bar.com";
+const char kTestEmail[] = "foo@bar.com";
 
 // Artificial time delay for JSON parsing.
 const int64_t kTestJsonParsingLatencyMs = 20;
@@ -258,7 +259,9 @@
 
 }  // namespace
 
-class RemoteSuggestionsFetcherImplTestBase : public testing::Test {
+class RemoteSuggestionsFetcherImplTestBase
+    : public testing::Test,
+      public OAuth2TokenService::DiagnosticsObserver {
  public:
   explicit RemoteSuggestionsFetcherImplTestBase(const GURL& gurl)
       : default_variation_params_(
@@ -278,6 +281,8 @@
   }
 
   ~RemoteSuggestionsFetcherImplTestBase() override {
+    if (fake_token_service_)
+      fake_token_service_->RemoveDiagnosticsObserver(this);
   }
 
   void ResetFetcher() { ResetFetcherWithAPIKey(kAPIKey); }
@@ -286,8 +291,16 @@
     scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
         new net::TestURLRequestContextGetter(mock_task_runner_.get());
 
+    if (fake_token_service_)
+      fake_token_service_->RemoveDiagnosticsObserver(this);
+    fake_token_service_ = std::make_unique<FakeProfileOAuth2TokenService>(
+        std::make_unique<FakeOAuth2TokenServiceDelegate>(
+            request_context_getter.get()));
+
+    fake_token_service_->AddDiagnosticsObserver(this);
+
     fetcher_ = std::make_unique<RemoteSuggestionsFetcherImpl>(
-        identity_test_env_.identity_manager(),
+        utils_.fake_signin_manager(), fake_token_service_.get(),
         std::move(request_context_getter), utils_.pref_service(), nullptr,
         base::BindRepeating(&ParseJsonDelayed),
         GetFetchEndpoint(version_info::Channel::STABLE), api_key,
@@ -298,8 +311,26 @@
   }
 
   void SignIn() {
-    identity_test_env_.MakePrimaryAccountAvailable(kTestAccount, kTestAccount,
-                                                   "token");
+#if defined(OS_CHROMEOS)
+    utils_.fake_signin_manager()->SignIn(kTestEmail);
+#else
+    utils_.fake_signin_manager()->SignIn(kTestEmail, "user", "password");
+#endif
+  }
+
+  void IssueRefreshToken() {
+    fake_token_service_->GetDelegate()->UpdateCredentials(kTestEmail, "token");
+  }
+
+  void IssueOAuth2Token() {
+    fake_token_service_->IssueAllTokensForAccount(kTestEmail, "access_token",
+                                                  base::Time::Max());
+  }
+
+  void CancelOAuth2TokenRequests() {
+    fake_token_service_->IssueErrorForAllPendingRequestsForAccount(
+        kTestEmail, GoogleServiceAuthError(
+                        GoogleServiceAuthError::State::REQUEST_CANCELED));
   }
 
   RemoteSuggestionsFetcher::SnippetsAvailableCallback
@@ -349,12 +380,23 @@
     fake_url_fetcher_factory_->SetFakeResponse(test_url_, response_data,
                                                response_code, status);
   }
+  void set_on_access_token_request_callback(base::OnceClosure callback) {
+    on_access_token_request_callback_ = std::move(callback);
+  }
 
  protected:
   std::map<std::string, std::string> default_variation_params_;
-  identity::IdentityTestEnvironment identity_test_env_;
 
  private:
+  // OAuth2TokenService::DiagnosticsObserver:
+  void OnAccessTokenRequested(
+      const std::string& account_id,
+      const std::string& consumer_id,
+      const OAuth2TokenService::ScopeSet& scopes) override {
+    if (on_access_token_request_callback_)
+      std::move(on_access_token_request_callback_).Run();
+  }
+
   // TODO(tzik): Remove |clock_| after updating GetMockTickClock to own the
   // instance. http://crbug.com/789079
   std::unique_ptr<base::Clock> clock_;
@@ -365,11 +407,13 @@
   FailingFakeURLFetcherFactory failing_url_fetcher_factory_;
   // Initialized lazily in SetFakeResponse().
   std::unique_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory_;
+  std::unique_ptr<FakeProfileOAuth2TokenService> fake_token_service_;
   std::unique_ptr<RemoteSuggestionsFetcherImpl> fetcher_;
   std::unique_ptr<UserClassifier> user_classifier_;
   MockSnippetsAvailableCallback mock_callback_;
   const GURL test_url_;
   base::HistogramTester histogram_tester_;
+  base::OnceClosure on_access_token_request_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(RemoteSuggestionsFetcherImplTestBase);
 };
@@ -445,7 +489,11 @@
 }
 
 TEST_F(RemoteSuggestionsSignedInFetcherTest, ShouldFetchSuccessfully) {
+  base::RunLoop run_loop;
+  set_on_access_token_request_callback(run_loop.QuitClosure());
+
   SignIn();
+  IssueRefreshToken();
 
   const std::string kJsonStr =
       "{\"categories\" : [{"
@@ -475,9 +523,9 @@
   fetcher().FetchSnippets(test_params(),
                           ToSnippetsAvailableCallback(&mock_callback()));
 
-  identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
-      "access_token", base::Time::Max());
+  run_loop.Run();
 
+  IssueOAuth2Token();
   // Wait for the fake response.
   FastForwardUntilNoTasksRemain();
 
@@ -492,7 +540,11 @@
 }
 
 TEST_F(RemoteSuggestionsSignedInFetcherTest, ShouldRetryWhenOAuthCancelled) {
+  base::RunLoop run_loop;
+  set_on_access_token_request_callback(run_loop.QuitClosure());
+
   SignIn();
+  IssueRefreshToken();
 
   const std::string kJsonStr =
       "{\"categories\" : [{"
@@ -522,15 +574,20 @@
   fetcher().FetchSnippets(test_params(),
                           ToSnippetsAvailableCallback(&mock_callback()));
 
-  // Cancel the first access token request that's made.
-  identity_test_env_.WaitForAccessTokenRequestAndRespondWithError(
-      GoogleServiceAuthError(GoogleServiceAuthError::State::REQUEST_CANCELED));
+  // Wait for the first access token request to be made.
+  run_loop.Run();
 
-  // RemoteSuggestionsFetcher should retry fetching an access token if the first
-  // attempt is cancelled. Respond with a valid access token on the retry.
-  identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
-      "access_token", base::Time::Max());
+  // Before cancelling the outstanding access token request, prepare to wait for
+  // the second access token request to be made in response to the cancellation.
+  base::RunLoop run_loop2;
+  set_on_access_token_request_callback(run_loop2.QuitClosure());
 
+  CancelOAuth2TokenRequests();
+
+  // Wait for the second access token request to be made.
+  run_loop2.Run();
+
+  IssueOAuth2Token();
   // Wait for the fake response.
   FastForwardUntilNoTasksRemain();
 
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.cc b/components/offline_pages/core/downloads/download_ui_adapter.cc
index 3d9be479..4334e0c 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter.cc
@@ -88,7 +88,6 @@
       request_coordinator_(request_coordinator),
       delegate_(std::move(delegate)),
       state_(State::NOT_LOADED),
-      observers_count_(0),
       weak_ptr_factory_(this) {
   delegate_->SetUIAdapter(this);
   if (aggregator_)
@@ -105,10 +104,7 @@
   DCHECK(observer);
   if (observers_.HasObserver(observer))
     return;
-  if (observers_count_ == 0)
-    LoadCache();
   observers_.AddObserver(observer);
-  ++observers_count_;
   // If the items are already loaded, post the notification right away.
   // Don't just invoke it from here to avoid reentrancy in the client.
   if (state_ == State::LOADED) {
@@ -125,10 +121,6 @@
   if (!observers_.HasObserver(observer))
     return;
   observers_.RemoveObserver(observer);
-  --observers_count_;
-  // Once the last observer is gone, clear cached data.
-  if (observers_count_ == 0)
-    ClearCache();
 }
 
 void DownloadUIAdapter::OfflinePageModelLoaded(OfflinePageModel* model) {
@@ -209,6 +201,9 @@
 
 void DownloadUIAdapter::OnNetworkProgress(const SavePageRequest& request,
                                           int64_t received_bytes) {
+  if (state_ != State::LOADED)
+    return;
+
   for (auto& item : items_) {
     if (item.second->is_request &&
         item.second->offline_id == request.request_id()) {
@@ -225,6 +220,9 @@
 
 void DownloadUIAdapter::TemporaryHiddenStatusChanged(
     const ClientId& client_id) {
+  if (state_ != State::LOADED)
+    return;
+
   bool hidden = delegate_->IsTemporarilyHiddenInUI(client_id);
 
   for (const auto& item : items_) {
@@ -246,60 +244,65 @@
 
 void DownloadUIAdapter::GetAllItems(
     OfflineContentProvider::MultipleItemCallback callback) {
-  std::vector<OfflineItem> items;
-  for (const auto& item : items_) {
-    if (delegate_->IsTemporarilyHiddenInUI(item.second->client_id))
-      continue;
-    items.push_back(*(item.second->ui_item));
+  if (state_ == State::LOADED) {
+    ReplyWithAllItems(std::move(callback));
+    return;
   }
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), items));
+  postponed_callbacks_.emplace_back(std::move(callback));
+  LoadCache();
 }
 
+// TODO(dimich): Remove this method since it is not used currently. If needed,
+// it has to be updated to fault in the initial load of items. Currently it
+// simply returns nullopt if the cache is not loaded.
 void DownloadUIAdapter::GetItemById(
     const ContentId& id,
     OfflineContentProvider::SingleItemCallback callback) {
   base::Optional<OfflineItem> offline_item;
-  OfflineItems::const_iterator it = items_.find(id.id);
-  if (it != items_.end() && it->second->ui_item &&
-      !delegate_->IsTemporarilyHiddenInUI(it->second->client_id)) {
-    offline_item = *it->second->ui_item.get();
+  if (state_ == State::LOADED) {
+    OfflineItems::const_iterator it = items_.find(id.id);
+    if (it != items_.end() && it->second->ui_item &&
+        !delegate_->IsTemporarilyHiddenInUI(it->second->client_id)) {
+      offline_item = *it->second->ui_item.get();
+    }
   }
-
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), offline_item));
 }
 
 bool DownloadUIAdapter::AreItemsAvailable() {
-  return state_ == State::LOADED;
+  return true;
 }
 
 void DownloadUIAdapter::OpenItem(const ContentId& id) {
-  OfflineItems::const_iterator it = items_.find(id.id);
-  if (it == items_.end())
+  if (state_ == State::LOADED) {
+    OpenItemByGuid(id.id);
     return;
+  }
 
-  const OfflineItem* item = it->second->ui_item.get();
-  if (!item)
-    return;
-
-  delegate_->OpenItem(*item, GetOfflineIdByGuid(id.id));
+  postponed_operations_.push_back(
+      base::BindOnce(&DownloadUIAdapter::OpenItemByGuid,
+                     weak_ptr_factory_.GetWeakPtr(), id.id));
+  LoadCache();
 }
 
 void DownloadUIAdapter::RemoveItem(const ContentId& id) {
-  OfflineItems::const_iterator it = items_.find(id.id);
-  if (it == items_.end())
+  if (state_ == State::LOADED) {
+    RemoveItemByGuid(id.id);
     return;
+  }
 
-  std::vector<int64_t> page_ids;
-  page_ids.push_back(it->second->offline_id);
-  model_->DeletePagesByOfflineId(
-      page_ids, base::Bind(&DownloadUIAdapter::OnDeletePagesDone,
-                           weak_ptr_factory_.GetWeakPtr()));
+  postponed_operations_.push_back(
+      base::BindOnce(&DownloadUIAdapter::RemoveItemByGuid,
+                     weak_ptr_factory_.GetWeakPtr(), id.id));
+  LoadCache();
 }
 
 int64_t DownloadUIAdapter::GetOfflineIdByGuid(const std::string& guid) const {
+  if (state_ != State::LOADED)
+    return 0;
+
   if (deleting_item_ && deleting_item_->ui_item->id.id == guid)
     return deleting_item_->offline_id;
 
@@ -365,11 +368,15 @@
 // Note that several LoadCache calls may be issued before the async GetAllPages
 // comes back.
 void DownloadUIAdapter::LoadCache() {
+  if (state_ != State::NOT_LOADED)
+    return;
   state_ = State::LOADING_PAGES;
   model_->GetAllPages(base::Bind(&DownloadUIAdapter::OnOfflinePagesLoaded,
                                  weak_ptr_factory_.GetWeakPtr()));
 }
 
+// TODO(dimich): Start clearing this cache on UI close. Also, after OpenItem can
+// done without loading all items from database.
 void DownloadUIAdapter::ClearCache() {
   // Once loaded, this class starts to observe the model. Only remove observer
   // if it was added.
@@ -432,6 +439,19 @@
   state_ = State::LOADED;
   for (auto& observer : observers_)
     observer.OnItemsAvailable(this);
+
+  // If there are callers waiting for GetAllItems callback, call them.
+  for (auto& callback : postponed_callbacks_) {
+    ReplyWithAllItems(std::move(callback));
+  }
+  postponed_callbacks_.clear();
+
+  // If there were requests to perform operations on items before cache was
+  // loaded, perform them now.
+  for (auto& operation : postponed_operations_) {
+    std::move(operation).Run();
+  }
+  postponed_operations_.clear();
 }
 
 void DownloadUIAdapter::NotifyItemsLoaded(
@@ -440,7 +460,6 @@
     observer->OnItemsAvailable(this);
 }
 
-
 void DownloadUIAdapter::OnDeletePagesDone(DeletePageResult result) {
   // TODO(dimich): Consider adding UMA to record user actions.
 }
@@ -497,4 +516,50 @@
   deleting_item_.reset();
 }
 
+void DownloadUIAdapter::ReplyWithAllItems(
+    OfflineContentProvider::MultipleItemCallback callback) {
+  std::vector<OfflineItem> items;
+  for (const auto& item : items_) {
+    if (delegate_->IsTemporarilyHiddenInUI(item.second->client_id))
+      continue;
+    items.push_back(*(item.second->ui_item));
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), items));
+}
+
+void DownloadUIAdapter::OpenItemByGuid(const std::string& guid) {
+  if (state_ != State::LOADED) {
+    return;
+  }
+
+  OfflineItems::const_iterator it = items_.find(guid);
+  if (it == items_.end())
+    return;
+
+  const OfflineItem* item = it->second->ui_item.get();
+  if (!item)
+    return;
+
+  delegate_->OpenItem(*item, GetOfflineIdByGuid(guid));
+}
+
+void DownloadUIAdapter::RemoveItemByGuid(const std::string& guid) {
+  if (state_ != State::LOADED) {
+    return;
+  }
+
+  OfflineItems::const_iterator it = items_.find(guid);
+  if (it == items_.end())
+    return;
+
+  std::vector<int64_t> page_ids;
+  page_ids.push_back(it->second->offline_id);
+
+  model_->DeletePagesByOfflineId(
+      page_ids, base::BindRepeating(&DownloadUIAdapter::OnDeletePagesDone,
+                                    weak_ptr_factory_.GetWeakPtr()));
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.h b/components/offline_pages/core/downloads/download_ui_adapter.h
index 657c150..cc5b947 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.h
+++ b/components/offline_pages/core/downloads/download_ui_adapter.h
@@ -115,6 +115,9 @@
 
   Delegate* delegate() { return delegate_.get(); }
 
+  // Test method, to verify the internal cache is not loaded too early.
+  bool IsCacheLoadedForTest() { return (state_ != State::NOT_LOADED); }
+
  private:
   enum class State { NOT_LOADED, LOADING_PAGES, LOADING_REQUESTS, LOADED };
 
@@ -176,6 +179,11 @@
   // during the |ItemDeleted| callback.
   void DeleteItemHelper(const std::string& guid);
 
+  void ReplyWithAllItems(OfflineContentProvider::MultipleItemCallback callback);
+
+  void OpenItemByGuid(const std::string& guid);
+  void RemoveItemByGuid(const std::string& guid);
+
   // A valid offline content aggregator, supplied at construction.
   OfflineContentAggregator* aggregator_;
 
@@ -193,11 +201,18 @@
   // The cache of UI items. The key is OfflineItem.guid.
   OfflineItems items_;
 
+  // The callbacks for GetAllItems waiting for cache initialization.
+  std::vector<OfflineContentProvider::MultipleItemCallback>
+      postponed_callbacks_;
+
+  // The requests for operations with items waiting for cache initialization.
+  // std::vector<base::OnceCallback<const std::string&>> postponed_operations_;
+  std::vector<base::OnceClosure> postponed_operations_;
+
   std::unique_ptr<ItemInfo> deleting_item_;
 
   // The observers.
   base::ObserverList<OfflineContentProvider::Observer> observers_;
-  int observers_count_;
 
   base::WeakPtrFactory<DownloadUIAdapter> weak_ptr_factory_;
 
diff --git a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
index 0ad63ef7..aab3a11 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
@@ -63,6 +63,10 @@
   EXPECT_EQ(expected.value().state, actual.value().state);
 }
 
+void GetAllItemsAndIgnoreResult(const std::vector<OfflineItem>& actual) {
+  // Do nothing.
+}
+
 void GetAllItemsAndVerify(size_t expected_size,
                           const std::vector<OfflineItem>& actual) {
   EXPECT_EQ(expected_size, actual.size());
@@ -193,8 +197,10 @@
   RequestCoordinator* request_coordinator() {
     return request_coordinator_taco_->request_coordinator();
   }
+  bool items_loaded() { return adapter->IsCacheLoadedForTest(); }
+  void AddInitialPage();
+  int64_t AddInitialRequest(const GURL& url, const ClientId& client_id);
 
-  bool items_loaded;
   std::vector<std::string> added_guids, updated_guids, deleted_guids;
   int64_t download_progress_bytes;
   std::unique_ptr<MockOfflinePageModel> model;
@@ -209,8 +215,7 @@
 };
 
 DownloadUIAdapterTest::DownloadUIAdapterTest()
-    : items_loaded(false),
-      task_runner_(new base::TestMockTimeTaskRunner),
+    : task_runner_(new base::TestMockTimeTaskRunner),
       task_runner_handle_(task_runner_) {}
 
 DownloadUIAdapterTest::~DownloadUIAdapterTest() {}
@@ -235,7 +240,7 @@
 }
 
 void DownloadUIAdapterTest::OnItemsAvailable(OfflineContentProvider* provider) {
-  items_loaded = true;
+  // TODO(dimich): remove this event.
 }
 
 void DownloadUIAdapterTest::OnItemsAdded(
@@ -269,12 +274,32 @@
       params, base::Bind(&SavePageLaterCallback));
 }
 
+void DownloadUIAdapterTest::AddInitialPage() {
+  model->AddInitialPage();
+  // Trigger cache load in the adapter.
+  adapter->GetAllItems(base::BindOnce(&GetAllItemsAndIgnoreResult));
+  PumpLoop();
+}
+
+int64_t DownloadUIAdapterTest::AddInitialRequest(const GURL& url,
+                                                 const ClientId& client_id) {
+  int64_t id = AddRequest(url, client_id);
+  // Trigger cache load in the adapter.
+  adapter->GetAllItems(base::BindOnce(&GetAllItemsAndIgnoreResult));
+  PumpLoop();
+  return id;
+}
+
+// TODO(dimich): Remove this flag and OnItemsAvailable from interface.
+TEST_F(DownloadUIAdapterTest, ItemsAvailableIsAlwaysTrue) {
+  EXPECT_TRUE(adapter->AreItemsAvailable());
+}
+
 TEST_F(DownloadUIAdapterTest, InitialLoad) {
   EXPECT_NE(nullptr, adapter.get());
-  model->AddInitialPage();
-  EXPECT_FALSE(items_loaded);
-  PumpLoop();
-  EXPECT_TRUE(items_loaded);
+  EXPECT_FALSE(items_loaded());
+  AddInitialPage();
+  EXPECT_TRUE(items_loaded());
   OfflineItem item(kTestContentId1);
   adapter->GetItemById(kTestContentId1,
                        base::BindOnce(&GetItemAndVerify, item));
@@ -282,10 +307,9 @@
 }
 
 TEST_F(DownloadUIAdapterTest, InitialItemConversion) {
-  model->AddInitialPage();
+  AddInitialPage();
   EXPECT_EQ(1UL, model->pages.size());
   EXPECT_EQ(kTestGuid1, model->pages[kTestOfflineId1].client_id.id);
-  PumpLoop();
 
   auto callback = [](const base::Optional<OfflineItem>& item) {
     EXPECT_EQ(kTestGuid1, item.value().id.id);
@@ -303,8 +327,7 @@
 }
 
 TEST_F(DownloadUIAdapterTest, ItemDeletedAdded) {
-  model->AddInitialPage();
-  PumpLoop();
+  AddInitialPage();
   // Add page, notify adapter.
   OfflinePageItem page(GURL(kTestUrl), kTestOfflineId2, kTestClientId2,
                        base::FilePath(kTestFilePath), kFileSize,
@@ -323,8 +346,7 @@
 }
 
 TEST_F(DownloadUIAdapterTest, NotVisibleItem) {
-  model->AddInitialPage();
-  PumpLoop();
+  AddInitialPage();
   adapter_delegate->is_visible = false;
   OfflinePageItem page1(
       GURL(kTestUrl), kTestOfflineId2, kTestClientIdOtherNamespace,
@@ -337,8 +359,7 @@
 
 TEST_F(DownloadUIAdapterTest, TemporarilyNotVisibleItem) {
   adapter_delegate->is_temporarily_hidden = true;
-  model->AddInitialPage();
-  PumpLoop();
+  AddInitialPage();
   // Initial Item should be invisible in the collection now.
   adapter->GetItemById(kTestContentId1,
                        base::BindOnce(&GetItemAndVerify, base::nullopt));
@@ -377,8 +398,7 @@
 }
 
 TEST_F(DownloadUIAdapterTest, ItemAdded) {
-  model->AddInitialPage();
-  PumpLoop();
+  AddInitialPage();
   // Clear the initial page and replace it with updated one.
   model->pages.clear();
   // Add a new page which did not exist before.
@@ -395,24 +415,9 @@
   EXPECT_EQ(0UL, updated_guids.size());
 }
 
-TEST_F(DownloadUIAdapterTest, NoHangingLoad) {
-  model->AddInitialPage();
-  EXPECT_NE(nullptr, adapter.get());
-  EXPECT_FALSE(items_loaded);
-  // Removal of last observer causes cache unload of not-yet-loaded cache.
-  adapter->RemoveObserver(this);
-  // This will complete async fetch of items, but...
-  PumpLoop();
-  // items should not be loaded when there is no observers!
-  EXPECT_FALSE(items_loaded);
-  // This should not crash.
-  adapter->AddObserver(this);
-}
-
 TEST_F(DownloadUIAdapterTest, LoadExistingRequest) {
-  AddRequest(GURL(kTestUrl), kTestClientId1);
-  PumpLoop();
-  EXPECT_TRUE(items_loaded);
+  AddInitialRequest(GURL(kTestUrl), kTestClientId1);
+  EXPECT_TRUE(items_loaded());
   OfflineItem item(kTestContentId1);
   item.state = OfflineItemState::IN_PROGRESS;
   adapter->GetItemById(kTestContentId1,
@@ -421,8 +426,8 @@
 }
 
 TEST_F(DownloadUIAdapterTest, AddRequest) {
-  PumpLoop();
-  EXPECT_TRUE(items_loaded);
+  AddInitialPage();
+  EXPECT_TRUE(items_loaded());
   EXPECT_EQ(0UL, added_guids.size());
   AddRequest(GURL(kTestUrl), kTestClientId1);
   PumpLoop();
@@ -436,8 +441,7 @@
 }
 
 TEST_F(DownloadUIAdapterTest, RemoveRequest) {
-  int64_t id = AddRequest(GURL(kTestUrl), kTestClientId1);
-  PumpLoop();
+  int64_t id = AddInitialRequest(GURL(kTestUrl), kTestClientId1);
   // No added requests, the initial one is loaded.
   EXPECT_EQ(0UL, added_guids.size());
   OfflineItem item(kTestContentId1);
@@ -467,8 +471,8 @@
 }
 
 TEST_F(DownloadUIAdapterTest, PauseAndResume) {
-  PumpLoop();
-  EXPECT_TRUE(items_loaded);
+  AddInitialPage();
+  EXPECT_TRUE(items_loaded());
 
   AddRequest(GURL(kTestUrl), kTestClientId1);
   PumpLoop();
@@ -503,8 +507,7 @@
 }
 
 TEST_F(DownloadUIAdapterTest, OnChangedReceivedAfterPageAdded) {
-  AddRequest(GURL(kTestUrl), kTestClientId1);
-  PumpLoop();
+  AddInitialRequest(GURL(kTestUrl), kTestClientId1);
   OfflineItem item(kTestContentId1);
   item.state = OfflineItemState::IN_PROGRESS;
   adapter->GetItemById(kTestContentId1,
@@ -537,8 +540,7 @@
 TEST_F(DownloadUIAdapterTest, RequestBecomesPage) {
   // This will cause requests to be 'offlined' all the way and removed.
   offliner_stub->enable_callback(true);
-  AddRequest(GURL(kTestUrl), kTestClientId1);
-  PumpLoop();
+  AddInitialRequest(GURL(kTestUrl), kTestClientId1);
 
   OfflineItem item(kTestContentId1);
 
@@ -572,26 +574,9 @@
   PumpLoop();
 }
 
-TEST_F(DownloadUIAdapterTest, RemoveObserversWhenClearingCache) {
-  PumpLoop();
-  EXPECT_TRUE(items_loaded);
-
-  // Remove this from the adapter's observer list.  This should cause the cache
-  // to be cleared.
-  adapter->RemoveObserver(this);
-  items_loaded = false;
-
-  PumpLoop();
-
-  adapter->AddObserver(this);
-  PumpLoop();
-  EXPECT_TRUE(items_loaded);
-}
-
 TEST_F(DownloadUIAdapterTest, UpdateProgress) {
   offliner_stub->enable_callback(true);
-  AddRequest(GURL(kTestUrl), kTestClientId1);
-  PumpLoop();
+  AddInitialRequest(GURL(kTestUrl), kTestClientId1);
 
   auto callback = [](const base::Optional<OfflineItem>& item) {
     ASSERT_TRUE(item.has_value());
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc
index 99f1ae1..d47c1ff 100644
--- a/components/omnibox/browser/zero_suggest_provider.cc
+++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -87,34 +87,24 @@
 // Used for testing whether zero suggest is ever available.
 constexpr char kArbitraryInsecureUrlString[] = "http://www.google.com/";
 
-// Used to determine whether or not Most Visited URLs will be displayed.
-// This is true in either of these two cases:
-//   1. The user is in zero suggest most visited field trial.
-//   2. The user is in zero suggest field trial that enables search-for
-//      queries as suggestions and the user is either not signed-in or they
-//      do not have Google set up as their default search engine.
-bool DisplayZeroSuggestMostVisitedURLs(
+// If the user is not signed-in or the user does not have Google set up as their
+// default search engine, the personalized service is replaced with the most
+// visited service.
+bool PersonalizedServiceShouldFallBackToMostVisited(
     PrefService* prefs,
     bool is_authenticated,
     const TemplateURLService* template_url_service) {
-  if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(prefs))
+  if (!is_authenticated)
     return true;
 
-  if (OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(prefs)) {
-    if (!is_authenticated)
-      return true;
+  if (template_url_service == nullptr)
+    return false;
 
-    if (template_url_service != nullptr) {
-      const TemplateURL* default_provider =
-          template_url_service->GetDefaultSearchProvider();
-      return default_provider == nullptr ||
-             default_provider->GetEngineType(
-                 template_url_service->search_terms_data()) !=
-                 SEARCH_ENGINE_GOOGLE;
-    }
-  }
-
-  return false;
+  const TemplateURL* default_provider =
+      template_url_service->GetDefaultSearchProvider();
+  return default_provider == nullptr ||
+         default_provider->GetEngineType(
+             template_url_service->search_terms_data()) != SEARCH_ENGINE_GOOGLE;
 }
 
 }  // namespace
@@ -143,9 +133,9 @@
     return;
 
   Stop(true, false);
+  result_type_running_ = ResultType::NONE;
   set_field_trial_triggered(false);
   set_field_trial_triggered_in_session(false);
-  results_from_cache_ = false;
   permanent_text_ = input.text();
   current_query_ = input.current_url().spec();
   current_title_ = input.current_title();
@@ -157,42 +147,9 @@
   if (!suggest_url.is_valid())
     return;
 
-  // No need to send the current page URL in personalized suggest or
-  // most visited field trials.
-  const TemplateURLService* template_url_service =
-      client()->GetTemplateURLService();
-  const TemplateURL* default_provider =
-      template_url_service->GetDefaultSearchProvider();
-  const bool can_send_current_url =
-      CanSendURL(input.current_url(), suggest_url, default_provider,
-                 current_page_classification_,
-                 template_url_service->search_terms_data(), client());
-  GURL arbitrary_insecure_url(kArbitraryInsecureUrlString);
-  ZeroSuggestEligibility eligibility = ZeroSuggestEligibility::ELIGIBLE;
-  if (!can_send_current_url) {
-    const bool can_send_ordinary_url =
-        CanSendURL(arbitrary_insecure_url, suggest_url, default_provider,
-                   current_page_classification_,
-                   template_url_service->search_terms_data(), client());
-    eligibility = can_send_ordinary_url
-                      ? ZeroSuggestEligibility::URL_INELIGIBLE
-                      : ZeroSuggestEligibility::GENERALLY_INELIGIBLE;
-  }
-  UMA_HISTOGRAM_ENUMERATION(
-      "Omnibox.ZeroSuggest.Eligible.OnFocus", static_cast<int>(eligibility),
-      static_cast<int>(ZeroSuggestEligibility::ELIGIBLE_MAX_VALUE));
-
-  bool can_attach_current_url =
-      can_send_current_url &&
-      !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
-          client()->GetPrefs()) &&
-      !OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(
-          client()->GetPrefs());
-
-  if (!can_attach_current_url &&
-      !ShouldShowNonContextualZeroSuggest(input.current_url())) {
+  result_type_running_ = TypeOfResultToRun(input.current_url(), suggest_url);
+  if (result_type_running_ == ZeroSuggestProvider::NONE)
     return;
-  }
 
   done_ = false;
 
@@ -201,27 +158,31 @@
   // suggestions, if based on local browsing history.
   MaybeUseCachedSuggestions();
 
-  if (DisplayZeroSuggestMostVisitedURLs(client()->GetPrefs(),
-                                        client()->IsAuthenticated(),
-                                        template_url_service)) {
+  if (result_type_running_ == ZeroSuggestProvider::MOST_VISITED) {
     most_visited_urls_.clear();
     scoped_refptr<history::TopSites> ts = client()->GetTopSites();
-    if (ts) {
-      waiting_for_most_visited_urls_request_ = true;
-      ts->GetMostVisitedURLs(
-          base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable,
-                     weak_ptr_factory_.GetWeakPtr()),
-          false);
+    if (!ts) {
+      done_ = true;
+      result_type_running_ = ResultType::NONE;
+      return;
     }
+
+    ts->GetMostVisitedURLs(
+        base::Bind(&ZeroSuggestProvider::OnMostVisitedUrlsAvailable,
+                   weak_ptr_factory_.GetWeakPtr()),
+        false);
     return;
   }
 
+  const std::string current_url =
+      result_type_running_ == ZeroSuggestProvider::DEFAULT_SERP_FOR_URL
+          ? current_query_
+          : std::string();
   // Create a request for suggestions with |this| as the fetcher delegate.
   client()
       ->GetContextualSuggestionsService(/*create_if_necessary=*/true)
       ->CreateContextualSuggestionsRequest(
-          can_attach_current_url ? current_query_ : std::string(),
-          client()->GetTemplateURLService(),
+          current_url, client()->GetTemplateURLService(),
           /*fetcher_delegate=*/this,
           base::BindOnce(
               &ZeroSuggestProvider::OnContextualSuggestionsFetcherAvailable,
@@ -233,7 +194,6 @@
   if (fetcher_)
     LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REQUEST_INVALIDATED);
   fetcher_.reset();
-  waiting_for_most_visited_urls_request_ = false;
   auto* contextual_suggestions_service =
       client()->GetContextualSuggestionsService(/*create_if_necessary=*/false);
   // contextual_suggestions_service can be null if in incognito mode.
@@ -253,6 +213,8 @@
     current_title_.clear();
     most_visited_urls_.clear();
   }
+
+  result_type_running_ = ZeroSuggestProvider::NONE;
 }
 
 void ZeroSuggestProvider::DeleteMatch(const AutocompleteMatch& match) {
@@ -288,8 +250,7 @@
     : BaseSearchProvider(AutocompleteProvider::TYPE_ZERO_SUGGEST, client),
       history_url_provider_(history_url_provider),
       listener_(listener),
-      results_from_cache_(false),
-      waiting_for_most_visited_urls_request_(false),
+      result_type_running_(ResultType::NONE),
       weak_ptr_factory_(this) {
   // Record whether contextual zero suggest is possible for this user / profile.
   const TemplateURLService* template_url_service =
@@ -354,48 +315,43 @@
 
   LogOmniboxZeroSuggestRequest(ZERO_SUGGEST_REPLY_RECEIVED);
 
-  bool results_updated = false;
-  if (source->GetStatus().is_success() && source->GetResponseCode() == 200) {
-    std::string json_data = SearchSuggestionParser::ExtractJsonData(source);
-    std::unique_ptr<base::Value> data(
-        SearchSuggestionParser::DeserializeJsonData(json_data));
-    if (data) {
-      if (StoreSuggestionResponse(json_data, *data))
-        return;
-      results_updated = ParseSuggestResults(
-          *data, kDefaultZeroSuggestRelevance, false, &results_);
-    }
-  }
+  const bool results_updated =
+      source->GetStatus().is_success() && source->GetResponseCode() == 200 &&
+      UpdateResults(SearchSuggestionParser::ExtractJsonData(source));
   fetcher_.reset();
   done_ = true;
-  ConvertResultsToAutocompleteMatches();
+  result_type_running_ = ZeroSuggestProvider::NONE;
   listener_->OnProviderUpdate(results_updated);
 }
 
-bool ZeroSuggestProvider::StoreSuggestionResponse(
-    const std::string& json_data,
-    const base::Value& parsed_data) {
-  if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
-          client()->GetPrefs()) ||
-      json_data.empty())
-    return false;
-  client()->GetPrefs()->SetString(omnibox::kZeroSuggestCachedResults,
-                                  json_data);
-
-  // If we received an empty result list, we should update the display, as it
-  // may be showing cached results that should not be shown.
-  const base::ListValue* root_list = nullptr;
-  const base::ListValue* results_list = nullptr;
-  if (parsed_data.GetAsList(&root_list) &&
-      root_list->GetList(1, &results_list) &&
-      results_list->empty())
+bool ZeroSuggestProvider::UpdateResults(const std::string& json_data) {
+  std::unique_ptr<base::Value> data(
+      SearchSuggestionParser::DeserializeJsonData(json_data));
+  if (!data)
     return false;
 
-  // We are finished with the request and want to bail early.
-  if (results_from_cache_)
-    done_ = true;
+  // When running the personalized service, we want to store suggestion
+  // responses if non-empty.
+  if (result_type_running_ == ResultType::DEFAULT_SERP && !json_data.empty()) {
+    client()->GetPrefs()->SetString(omnibox::kZeroSuggestCachedResults,
+                                    json_data);
 
-  return results_from_cache_;
+    // If we received an empty result list, we should update the display, as it
+    // may be showing cached results that should not be shown.
+    const base::ListValue* root_list = nullptr;
+    const base::ListValue* results_list = nullptr;
+    const bool non_empty_parsed_list = data->GetAsList(&root_list) &&
+                                       root_list->GetList(1, &results_list) &&
+                                       !results_list->empty();
+    const bool non_empty_cache = !results_.suggest_results.empty() ||
+                                 !results_.navigation_results.empty();
+    if (non_empty_parsed_list && non_empty_cache)
+      return false;
+  }
+  const bool results_updated = ParseSuggestResults(
+      *data, kDefaultZeroSuggestRelevance, false, &results_);
+  ConvertResultsToAutocompleteMatches();
+  return results_updated;
 }
 
 void ZeroSuggestProvider::AddSuggestResultsToMap(
@@ -436,11 +392,12 @@
 
 void ZeroSuggestProvider::OnMostVisitedUrlsAvailable(
     const history::MostVisitedURLList& urls) {
-  if (!waiting_for_most_visited_urls_request_) return;
+  if (result_type_running_ != ResultType::MOST_VISITED)
+    return;
   most_visited_urls_ = urls;
-  waiting_for_most_visited_urls_request_ = false;
   done_ = true;
   ConvertResultsToAutocompleteMatches();
+  result_type_running_ = ResultType::NONE;
   listener_->OnProviderUpdate(true);
 }
 
@@ -474,9 +431,7 @@
   UMA_HISTOGRAM_COUNTS("ZeroSuggest.AllResults", num_results);
 
   // Show Most Visited results after ZeroSuggest response is received.
-  if (DisplayZeroSuggestMostVisitedURLs(client()->GetPrefs(),
-                                        client()->IsAuthenticated(),
-                                        template_url_service)) {
+  if (result_type_running_ == ResultType::MOST_VISITED) {
     if (!current_url_match_.destination_url.is_valid())
       return;
     matches_.push_back(current_url_match_);
@@ -534,7 +489,7 @@
                              results_.verbatim_relevance);
 }
 
-bool ZeroSuggestProvider::ShouldShowNonContextualZeroSuggest(
+bool ZeroSuggestProvider::AllowZeroSuggestSuggestions(
     const GURL& current_page_url) const {
   // Don't show zero suggest on the NTP.
   // TODO(hfung): Experiment with showing MostVisited zero suggest on NTP
@@ -546,17 +501,6 @@
   if (client()->IsOffTheRecord())
     return false;
 
-  // If we cannot send URLs, then only the MostVisited and Personalized
-  // variations can be shown.
-  // The const-cast allows the non-const AutocompleteProviderClient::GetPrefs()
-  // function to be called. OmniboxFieldTrial does not modify prefs, so the
-  // cast is safe in this application.
-  if (!OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(
-          const_cast<AutocompleteProviderClient*>(client())->GetPrefs()) &&
-      !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
-          const_cast<AutocompleteProviderClient*>(client())->GetPrefs()))
-    return false;
-
   // Only show zero suggest for HTTP[S] pages.
   // TODO(mariakhomenko): We may be able to expand this set to include pages
   // with other schemes (e.g. chrome://). That may require improvements to
@@ -566,19 +510,11 @@
       (current_page_url.scheme() != url::kHttpsScheme)))
     return false;
 
-  if (OmniboxFieldTrial::InZeroSuggestMostVisitedWithoutSerpFieldTrial(
-          const_cast<AutocompleteProviderClient*>(client())->GetPrefs()) &&
-      client()
-          ->GetTemplateURLService()
-          ->IsSearchResultsPageFromDefaultSearchProvider(current_page_url))
-    return false;
-
   return true;
 }
 
 void ZeroSuggestProvider::MaybeUseCachedSuggestions() {
-  if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
-          client()->GetPrefs()))
+  if (result_type_running_ != ZeroSuggestProvider::DEFAULT_SERP)
     return;
 
   std::string json_data =
@@ -586,10 +522,70 @@
   if (!json_data.empty()) {
     std::unique_ptr<base::Value> data(
         SearchSuggestionParser::DeserializeJsonData(json_data));
-    if (data && ParseSuggestResults(
-            *data, kDefaultZeroSuggestRelevance, false, &results_)) {
+    if (data && ParseSuggestResults(*data, kDefaultZeroSuggestRelevance, false,
+                                    &results_))
       ConvertResultsToAutocompleteMatches();
-      results_from_cache_ = !matches_.empty();
-    }
   }
 }
+
+ZeroSuggestProvider::ResultType ZeroSuggestProvider::TypeOfResultToRun(
+    const GURL& current_url,
+    const GURL& suggest_url) {
+  // TODO(jered): Consider adding locally-sourced zero-suggestions here too.
+  // These may be useful on the NTP or more relevant to the user than server
+  // suggestions, if based on local browsing history.
+
+  // Check if the URL can be sent in any suggest request.
+  const TemplateURLService* template_url_service =
+      client()->GetTemplateURLService();
+  const TemplateURL* default_provider =
+      template_url_service->GetDefaultSearchProvider();
+  const bool can_send_current_url = CanSendURL(
+      current_url, suggest_url, default_provider, current_page_classification_,
+      template_url_service->search_terms_data(), client());
+
+  // Collect metrics on eligibility.
+  GURL arbitrary_insecure_url(kArbitraryInsecureUrlString);
+  ZeroSuggestEligibility eligibility = ZeroSuggestEligibility::ELIGIBLE;
+  if (!can_send_current_url) {
+    const bool can_send_ordinary_url =
+        CanSendURL(arbitrary_insecure_url, suggest_url, default_provider,
+                   current_page_classification_,
+                   template_url_service->search_terms_data(), client());
+    eligibility = can_send_ordinary_url
+                      ? ZeroSuggestEligibility::URL_INELIGIBLE
+                      : ZeroSuggestEligibility::GENERALLY_INELIGIBLE;
+  }
+  UMA_HISTOGRAM_ENUMERATION(
+      "Omnibox.ZeroSuggest.Eligible.OnFocus", static_cast<int>(eligibility),
+      static_cast<int>(ZeroSuggestEligibility::ELIGIBLE_MAX_VALUE));
+
+  // Check if zero suggestions are allowed in the current context.
+  if (!AllowZeroSuggestSuggestions(current_url))
+    return ResultType::NONE;
+
+  if (OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial(
+          client()->GetPrefs()))
+    return PersonalizedServiceShouldFallBackToMostVisited(
+               client()->GetPrefs(), client()->IsAuthenticated(),
+               template_url_service)
+               ? ResultType::MOST_VISITED
+               : ResultType::DEFAULT_SERP;
+
+  // The const-cast allows the non-const AutocompleteProviderClient::GetPrefs()
+  // function to be called. OmniboxFieldTrial does not modify prefs, so the
+  // cast is safe in this application.
+  if (OmniboxFieldTrial::InZeroSuggestMostVisitedWithoutSerpFieldTrial(
+          const_cast<AutocompleteProviderClient*>(client())->GetPrefs()) &&
+      client()
+          ->GetTemplateURLService()
+          ->IsSearchResultsPageFromDefaultSearchProvider(current_url))
+    return ResultType::NONE;
+
+  if (OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial(
+          client()->GetPrefs()))
+    return ResultType::MOST_VISITED;
+
+  return can_send_current_url ? ResultType::DEFAULT_SERP_FOR_URL
+                              : ResultType::NONE;
+}
diff --git a/components/omnibox/browser/zero_suggest_provider.h b/components/omnibox/browser/zero_suggest_provider.h
index d21e18e6..d27e5250 100644
--- a/components/omnibox/browser/zero_suggest_provider.h
+++ b/components/omnibox/browser/zero_suggest_provider.h
@@ -73,6 +73,18 @@
 
   ~ZeroSuggestProvider() override;
 
+  // ZeroSuggestProvider is processing one of the following type of results
+  // at any time.
+  enum ResultType {
+    NONE,
+    DEFAULT_SERP,          // The default search provider is queried for
+                           // zero-suggest suggestions.
+    DEFAULT_SERP_FOR_URL,  // The default search provider is queried for
+                           // zero-suggest suggestions that are specific
+                           // to the visited URL.
+    MOST_VISITED
+  };
+
   // BaseSearchProvider:
   const TemplateURL* GetTemplateURL(bool is_keyword) const override;
   const AutocompleteInput GetInput(bool is_keyword) const override;
@@ -83,11 +95,18 @@
   // net::URLFetcherDelegate:
   void OnURLFetchComplete(const net::URLFetcher* source) override;
 
-  // Optionally, cache the received |json_data| and return true if we want
-  // to stop processing results at this point. The |parsed_data| is the parsed
-  // version of |json_data| used to determine if we received an empty result.
-  bool StoreSuggestionResponse(const std::string& json_data,
-                               const base::Value& parsed_data);
+  // The function updates |results_| with data parsed from |json_data|.
+  //
+  // * The update is not performed if |json_data| is invalid.
+  // * When the provider is using cached results and |json_data| is non-empty,
+  //   this function updates the cached results.
+  // * When |results_| contains cached results, these are updated only if
+  //   |json_cata| corresponds to an empty list. This is done to ensure that
+  //   the display is cleared, as it may be showing cached results that should
+  //   not be shown.
+  //
+  // The return value is true only when |results_| changed.
+  bool UpdateResults(const std::string& json_data);
 
   // Adds AutocompleteMatches for each of the suggestions in |results| to
   // |map|.
@@ -121,20 +140,29 @@
   void OnContextualSuggestionsFetcherAvailable(
       std::unique_ptr<net::URLFetcher> fetcher);
 
-  // Whether we can show zero suggest suggestions that are not based on
-  // |current_page_url|. Also checks that other conditions for non-contextual
-  // zero suggest are satisfied.
-  bool ShouldShowNonContextualZeroSuggest(const GURL& current_page_url) const;
+  // Whether zero suggest suggestions are allowed in the given context.
+  bool AllowZeroSuggestSuggestions(const GURL& current_page_url) const;
 
   // Checks whether we have a set of zero suggest results cached, and if so
   // populates |matches_| with cached results.
   void MaybeUseCachedSuggestions();
 
+  // Returns the type of results that should be generated for the current
+  // context.
+  // Logs UMA metrics. Should be called exactly once, on Start(), otherwise the
+  // meaning of the data logged would change.
+  ResultType TypeOfResultToRun(const GURL& current_url,
+                               const GURL& suggest_url);
+
   // Used for efficiency when creating the verbatim match.  Can be null.
   HistoryURLProvider* history_url_provider_;
 
   AutocompleteProviderListener* listener_;
 
+  // The result type that is currently being processed by provider.
+  // When the provider is not running, the result type is set to NONE.
+  ResultType result_type_running_;
+
   // The URL for which a suggestion fetch is pending.
   std::string current_query_;
 
@@ -158,14 +186,8 @@
   // the response for the most recent zero suggest input URL.
   SearchSuggestionParser::Results results_;
 
-  // Whether we are currently showing cached zero suggest results.
-  bool results_from_cache_;
-
   history::MostVisitedURLList most_visited_urls_;
 
-  // Whether we are waiting for a most visited visited urls callback to run.
-  bool waiting_for_most_visited_urls_request_;
-
   // For callbacks that may be run after destruction.
   base::WeakPtrFactory<ZeroSuggestProvider> weak_ptr_factory_;
 
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index 5353b79..3b2304f 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -11,11 +11,11 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/signin/core/browser/account_reconcilor_delegate.h"
 #include "components/signin/core/browser/profile_management_switches.h"
@@ -25,6 +25,7 @@
 #include "components/signin/core/browser/signin_metrics.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/google_service_auth_error.h"
 
 namespace {
 
@@ -96,10 +97,12 @@
       reconcile_is_noop_(true),
       chrome_accounts_changed_(false),
       account_reconcilor_lock_count_(0),
-      reconcile_on_unblock_(false) {
+      reconcile_on_unblock_(false),
+      timer_(new base::OneShotTimer) {
   VLOG(1) << "AccountReconcilor::AccountReconcilor";
   DCHECK(delegate_);
   delegate_->set_reconcilor(this);
+  timeout_ = delegate_->GetReconcileTimeout();
 }
 
 AccountReconcilor::~AccountReconcilor() {
@@ -299,6 +302,16 @@
     return;
   }
 
+  if (!timeout_.is_max()) {
+    // This is NOT a repeating callback but to test it, we need a |MockTimer|,
+    // which mocks |Timer| and not |OneShotTimer|. |Timer| currently does not
+    // support a |OnceClosure|.
+    timer_->Start(
+        FROM_HERE, timeout_,
+        base::BindRepeating(&AccountReconcilor::HandleReconcileTimeout,
+                            base::Unretained(this)));
+  }
+
   primary_account_ = signin_manager_->GetAuthenticatedAccountId();
   if (token_service_->GetDelegate()->RefreshTokenHasError(primary_account_) &&
       delegate_->ShouldAbortReconcileIfPrimaryHasError()) {
@@ -504,6 +517,7 @@
   if (is_reconcile_started_ && add_to_cookie_.empty()) {
     signin_metrics::LogSigninAccountReconciliationDuration(duration,
         !error_during_last_reconcile_);
+    timer_->Stop();
   }
 
   is_reconcile_started_ = !add_to_cookie_.empty();
@@ -620,3 +634,14 @@
     StartReconcile();
   }
 }
+
+void AccountReconcilor::set_timer_for_testing(
+    std::unique_ptr<base::Timer> timer) {
+  timer_ = std::move(timer);
+}
+
+void AccountReconcilor::HandleReconcileTimeout() {
+  AbortReconcile();
+  delegate_->OnReconcileError(
+      GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
+}
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 3630c16..4870e8d4 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -15,6 +15,7 @@
 #include "base/observer_list.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -160,6 +161,12 @@
                            AddAccountToCookieCompletedWithBogusAccount);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, NoLoopWithBadPrimary);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, WontMergeAccountsWithError);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsCalled);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsNotCalled);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+                           DelegateTimeoutIsNotCalledIfTimeoutIsNotReached);
+
+  void set_timer_for_testing(std::unique_ptr<base::Timer> timer);
 
   bool IsRegisteredWithTokenService() const {
     return registered_with_token_service_;
@@ -228,6 +235,8 @@
   void UnblockReconcile();
   bool IsReconcileBlocked() const;
 
+  void HandleReconcileTimeout();
+
   std::unique_ptr<signin::AccountReconcilorDelegate> delegate_;
 
   // The ProfileOAuth2TokenService associated with this reconcilor.
@@ -275,6 +284,11 @@
 
   base::ObserverList<Observer, true> observer_list_;
 
+  // A timer to set off reconciliation timeout handlers, if account
+  // reconciliation does not happen in a given timeout duration.
+  std::unique_ptr<base::Timer> timer_;
+  base::TimeDelta timeout_;
+
   DISALLOW_COPY_AND_ASSIGN(AccountReconcilor);
 };
 
diff --git a/components/signin/core/browser/account_reconcilor_delegate.cc b/components/signin/core/browser/account_reconcilor_delegate.cc
index d867f08..fceec4c 100644
--- a/components/signin/core/browser/account_reconcilor_delegate.cc
+++ b/components/signin/core/browser/account_reconcilor_delegate.cc
@@ -4,6 +4,9 @@
 
 #include "components/signin/core/browser/account_reconcilor_delegate.h"
 
+#include "base/time/time.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+
 namespace signin {
 
 bool AccountReconcilorDelegate::IsReconcileEnabled() const {
@@ -31,4 +34,11 @@
   return false;
 }
 
+base::TimeDelta AccountReconcilorDelegate::GetReconcileTimeout() const {
+  return base::TimeDelta::Max();
+}
+
+void AccountReconcilorDelegate::OnReconcileError(
+    const GoogleServiceAuthError& error) {}
+
 }  // namespace signin
diff --git a/components/signin/core/browser/account_reconcilor_delegate.h b/components/signin/core/browser/account_reconcilor_delegate.h
index cb797af4..8960987 100644
--- a/components/signin/core/browser/account_reconcilor_delegate.h
+++ b/components/signin/core/browser/account_reconcilor_delegate.h
@@ -8,7 +8,9 @@
 #include <string>
 #include <vector>
 
+#include "base/time/time.h"
 #include "google_apis/gaia/gaia_auth_util.h"
+#include "google_apis/gaia/google_service_auth_error.h"
 
 class AccountReconcilor;
 
@@ -50,6 +52,16 @@
   virtual void OnReconcileFinished(const std::string& first_account,
                                    bool reconcile_is_noop) {}
 
+  // Returns the desired timeout for account reconciliation. If reconciliation
+  // does not happen within this time, it is aborted and |this| delegate is
+  // informed via |OnReconcileError|, with an error state of
+  // GoogleServiceAuthError::CONNECTION_FAILED. If a delegate does not wish to
+  // set a timeout for account reconciliation, it should not override this
+  // method. Default: |base::TimeDelta::Max()|.
+  virtual base::TimeDelta GetReconcileTimeout() const;
+
+  virtual void OnReconcileError(const GoogleServiceAuthError& error);
+
   void set_reconcilor(AccountReconcilor* reconcilor) {
     reconcilor_ = reconcilor;
   }
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index 6a8801c..9612e76 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include <cstring>
+#include <map>
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "base/macros.h"
@@ -13,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
 #include "base/time/time.h"
+#include "base/timer/mock_timer.h"
 #include "build/build_config.h"
 #include "components/signin/core/browser/account_reconcilor.h"
 #include "components/signin/core/browser/account_tracker_service.h"
@@ -32,6 +35,7 @@
 #include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/google_service_auth_error.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -51,7 +55,7 @@
 // TestSigninClient keeping track of the dice migration.
 class DiceTestSigninClient : public TestSigninClient {
  public:
-  DiceTestSigninClient(PrefService* prefs) : TestSigninClient(prefs) {}
+  explicit DiceTestSigninClient(PrefService* prefs) : TestSigninClient(prefs) {}
 
   void SetReadyForDiceMigration(bool ready) override {
     is_ready_for_dice_migration_ = ready;
@@ -64,6 +68,41 @@
   DISALLOW_COPY_AND_ASSIGN(DiceTestSigninClient);
 };
 
+// An AccountReconcilorDelegate that records all calls (Spy pattern).
+class SpyReconcilorDelegate : public signin::AccountReconcilorDelegate {
+ public:
+  int num_reconcile_finished_calls_{0};
+  int num_reconcile_timeout_calls_{0};
+
+  bool IsReconcileEnabled() const override { return true; }
+
+  bool IsAccountConsistencyEnforced() const override { return true; }
+
+  bool ShouldAbortReconcileIfPrimaryHasError() const override { return true; }
+
+  std::string GetFirstGaiaAccountForReconcile(
+      const std::vector<std::string>& chrome_accounts,
+      const std::vector<gaia::ListedAccount>& gaia_accounts,
+      const std::string& primary_account,
+      bool first_execution) const override {
+    return primary_account;
+  }
+
+  void OnReconcileFinished(const std::string& first_account,
+                           bool is_reconcile_noop) override {
+    ++num_reconcile_finished_calls_;
+  }
+
+  base::TimeDelta GetReconcileTimeout() const override {
+    // Does not matter as long as it is different from base::TimeDelta::Max().
+    return base::TimeDelta::FromMinutes(100);
+  }
+
+  void OnReconcileError(const GoogleServiceAuthError& error) override {
+    ++num_reconcile_timeout_calls_;
+  }
+};
+
 // gmock does not allow mocking classes with move-only parameters, preventing
 // from mocking the AccountReconcilor class directly (because of the
 // unique_ptr<AccountReconcilorDelegate> parameter).
@@ -87,6 +126,23 @@
     Initialize(false /* start_reconcile_if_tokens_available */);
   }
 
+  // Takes ownership of |delegate|.
+  // gmock can't work with move only parameters.
+  explicit DummyAccountReconcilorWithDelegate(
+      ProfileOAuth2TokenService* token_service,
+      SigninManagerBase* signin_manager,
+      SigninClient* client,
+      GaiaCookieManagerService* cookie_manager_service,
+      signin::AccountReconcilorDelegate* delegate)
+      : AccountReconcilor(
+            token_service,
+            signin_manager,
+            client,
+            cookie_manager_service,
+            std::unique_ptr<signin::AccountReconcilorDelegate>(delegate)) {
+    Initialize(false /* start_reconcile_if_tokens_available */);
+  }
+
   static std::unique_ptr<signin::AccountReconcilorDelegate>
   CreateAccountReconcilorDelegate(
       SigninClient* signin_client,
@@ -125,6 +181,13 @@
       GaiaCookieManagerService* cookie_manager_service,
       signin::AccountConsistencyMethod account_consistency);
 
+  explicit MockAccountReconcilor(
+      ProfileOAuth2TokenService* token_service,
+      SigninManagerBase* signin_manager,
+      SigninClient* client,
+      GaiaCookieManagerService* cookie_manager_service,
+      std::unique_ptr<signin::AccountReconcilorDelegate> delegate);
+
   MOCK_METHOD1(PerformMergeAction, void(const std::string& account_id));
   MOCK_METHOD0(PerformLogoutAllAccountsAction, void());
 };
@@ -142,6 +205,19 @@
           cookie_manager_service,
           account_consistency) {}
 
+MockAccountReconcilor::MockAccountReconcilor(
+    ProfileOAuth2TokenService* token_service,
+    SigninManagerBase* signin_manager,
+    SigninClient* client,
+    GaiaCookieManagerService* cookie_manager_service,
+    std::unique_ptr<signin::AccountReconcilorDelegate> delegate)
+    : testing::StrictMock<DummyAccountReconcilorWithDelegate>(
+          token_service,
+          signin_manager,
+          client,
+          cookie_manager_service,
+          delegate.release()) {}
+
 }  // namespace
 
 class AccountReconcilorTest : public ::testing::Test {
@@ -170,6 +246,8 @@
   }
 
   MockAccountReconcilor* GetMockReconcilor();
+  MockAccountReconcilor* GetMockReconcilor(
+      std::unique_ptr<signin::AccountReconcilorDelegate> delegate);
 
   std::string ConnectProfileToAccount(const std::string& gaia_id,
                                       const std::string& username);
@@ -255,6 +333,15 @@
   return mock_reconcilor_.get();
 }
 
+MockAccountReconcilor* AccountReconcilorTest::GetMockReconcilor(
+    std::unique_ptr<signin::AccountReconcilorDelegate> delegate) {
+  mock_reconcilor_ = std::make_unique<MockAccountReconcilor>(
+      &token_service_, &signin_manager_, &test_signin_client_,
+      &cookie_manager_service_, std::move(delegate));
+
+  return mock_reconcilor_.get();
+}
+
 AccountReconcilorTest::~AccountReconcilorTest() {
   if (mock_reconcilor_)
     mock_reconcilor_->Shutdown();
@@ -1734,3 +1821,71 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
   ASSERT_FALSE(reconcilor->error_during_last_reconcile_);
 }
+
+// Test that delegate timeout is called when the delegate offers a valid
+// timeout.
+TEST_F(AccountReconcilorTest, DelegateTimeoutIsCalled) {
+  const std::string account_id =
+      ConnectProfileToAccount("12345", "user@gmail.com");
+  auto spy_delegate0 = std::make_unique<SpyReconcilorDelegate>();
+  SpyReconcilorDelegate* spy_delegate = spy_delegate0.get();
+  AccountReconcilor* reconcilor = GetMockReconcilor(std::move(spy_delegate0));
+  ASSERT_TRUE(reconcilor);
+  auto timer0 = std::make_unique<base::MockTimer>(true /* retain_user_task */,
+                                                  false /* is_repeating */);
+  base::MockTimer* timer = timer0.get();
+  reconcilor->set_timer_for_testing(std::move(timer0));
+
+  reconcilor->StartReconcile();
+  ASSERT_TRUE(reconcilor->is_reconcile_started_);
+  ASSERT_TRUE(timer->IsRunning());
+
+  // Simulate a timeout
+  timer->Fire();
+  EXPECT_EQ(1, spy_delegate->num_reconcile_timeout_calls_);
+  EXPECT_EQ(0, spy_delegate->num_reconcile_finished_calls_);
+  EXPECT_FALSE(reconcilor->is_reconcile_started_);
+}
+
+// Test that delegate timeout is not called when the delegate does not offer a
+// valid timeout.
+TEST_F(AccountReconcilorTest, DelegateTimeoutIsNotCalled) {
+  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+  ConnectProfileToAccount("12345", "user@gmail.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
+                                                              "12345");
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  ASSERT_TRUE(reconcilor);
+  auto timer0 = std::make_unique<base::MockTimer>(true /* retain_user_task */,
+                                                  false /* is_repeating */);
+  base::MockTimer* timer = timer0.get();
+  reconcilor->set_timer_for_testing(std::move(timer0));
+
+  reconcilor->StartReconcile();
+  EXPECT_TRUE(reconcilor->is_reconcile_started_);
+  EXPECT_FALSE(timer->IsRunning());
+}
+
+TEST_F(AccountReconcilorTest, DelegateTimeoutIsNotCalledIfTimeoutIsNotReached) {
+  ConnectProfileToAccount("12345", "user@gmail.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
+                                                              "12345");
+  auto spy_delegate0 = std::make_unique<SpyReconcilorDelegate>();
+  SpyReconcilorDelegate* spy_delegate = spy_delegate0.get();
+  AccountReconcilor* reconcilor = GetMockReconcilor(std::move(spy_delegate0));
+  ASSERT_TRUE(reconcilor);
+  auto timer0 = std::make_unique<base::MockTimer>(true /* retain_user_task */,
+                                                  false /* is_repeating */);
+  base::MockTimer* timer = timer0.get();
+  reconcilor->set_timer_for_testing(std::move(timer0));
+
+  reconcilor->StartReconcile();
+  ASSERT_TRUE(reconcilor->is_reconcile_started_);
+  ASSERT_TRUE(timer->IsRunning());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(timer->IsRunning());
+  EXPECT_EQ(0, spy_delegate->num_reconcile_timeout_calls_);
+  EXPECT_EQ(1, spy_delegate->num_reconcile_finished_calls_);
+  EXPECT_FALSE(reconcilor->is_reconcile_started_);
+}
diff --git a/components/spellcheck/common/spellcheck_common.cc b/components/spellcheck/common/spellcheck_common.cc
index ccd7ada..6db861e 100644
--- a/components/spellcheck/common/spellcheck_common.cc
+++ b/components/spellcheck/common/spellcheck_common.cc
@@ -36,7 +36,7 @@
     {"da", "da-DK"},
     {"de", "de-DE"},
     {"el", "el-GR"},
-    {"en-AU", "en-GB"},
+    {"en-AU", "en-AU"},
     {"en-CA", "en-CA"},
     {"en-GB", "en-GB"},
     {"en-US", "en-US"},
diff --git a/components/test/data/autofill/heuristics/input/149_checkout_qvc.com_non_hidden.html b/components/test/data/autofill/heuristics/input/149_checkout_qvc.com_non_hidden.html
new file mode 100644
index 0000000..af2effa
--- /dev/null
+++ b/components/test/data/autofill/heuristics/input/149_checkout_qvc.com_non_hidden.html
@@ -0,0 +1,418 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
+<!-- begin head html zone file -->
+<head>
+
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+    <title>Shipping Address</title>
+    <meta http-equiv="Content-type" content= "text/html; charset=utf-8">
+</head>
+<body >
+
+
+    <form method="POST" name="frmBilltoShipto" class="frmshipto" action="https://quality-s.qvc.com/qic/qvcapp.aspx/view.1/app.multi/params.file.|Checkout|BilltoShipto,plex" >
+
+      <div style="display:none;">
+        <input type="hidden" name="NextURL" value="BilltoShipto.plex" />
+        <input type="hidden" name="RefererForm" value="BilltoShipto" />
+        <input type="hidden" name="ReturnToPage" value="" />
+        <input type="hidden" name="LineNumber" value="" />
+        <input type="hidden" name="LineTotal" value="" />
+        <input type="hidden" name="Product" value="" />
+        <input type="hidden" name="SpeedbuyInd" value="" />
+        <input type="hidden" name="MemberNumber"  value="" />
+        <input type="hidden" name="ReferenceCode" value="" />
+        <input type="hidden" name="ProspectMemberNumber" value="" />
+        <input type="hidden" name="PermShipToNickName" value="" />
+        <input type="hidden" name="NewMemberSw" value="1" />
+        <input type="hidden" name="SHIPTOSTANDARDIZEDSW" value="" />
+        <input type="hidden" name="ABname" id="ABname" value="" />
+        <input type="hidden" name="ABadd1" id="ABadd1" value="" />
+        <input type="hidden" name="ABadd2" id="ABadd2" value="" />
+        <input type="hidden" name="ABcity" id="ABcity" value="" />
+        <input type="hidden" name="ABstate" id="ABstate" value="" />
+        <input type="hidden" name="ABzip" id="ABzip" value="" />
+        <input type="hidden" name="ABcounty" id="ABcounty" value="" />
+        <input type="hidden" name="ABcountry" id="ABcountry" value="" />
+        <input type="hidden" name="ABgeocode" id="ABgeocode" value="" />
+        <input type="hidden" name="ABzipExtension" id="ABzipExtension" value="" />
+        <input type="hidden" name="ShiptoABNickName" id="ShiptoABNickName" value="" />
+        <input type="hidden" name="ShiptoCounty" id="ShiptoCounty" value="" />
+        <input type="hidden" name="ShiptoGeocode" id="ShiptoGeocode" value="" />
+        <input type="hidden" name="ShiptoZipExtension" id="ShiptoZipExtension" value="" />
+        <input type="hidden" name="BilltoZipExtension" id="BilltoZipExtension" value="" />
+        <input type="hidden" name="AddrBookSelected" id="AddrBookSelected" value="None" />
+        <input type="hidden" name="ShiptoLastName" id="ShiptoLastName" value="None" />
+      </div>
+      <!-- EGC section (Eric Rymers, 07/27/2005) -->
+      <input type="hidden" name="OnlyElecGiftCards" value="0" />
+
+      <!-- EGC section end -->
+
+
+      <div class="fragTitle">New Account Information</div>
+        <div class="formSeparator">
+        <div id="createAccountText" class="createAccountText" style="visibility:hidden;">
+          <p>Start shopping! Create your QVC account and be among the first to hear about new items, special offers and upcoming shows. Your QVC account also allows you to receive order and shipping confirmations. When you sign up, you will receive an 8-digit account number.
+          </div>
+            <!-- begin overlay -->
+              <div id="overlaywrap" style="display:none">
+                <div id="becomeMember"></div>
+                  <div class="clear"><!-- --></div>
+              </div>
+              <!-- end overlay -->
+          </p><br>
+
+          <fieldset>
+          <ol>
+            <li>
+              <label><em>*</em> E-mail Address:</label>
+              <input class="inputbox" type="text" name="EmailAddress" id="EmailAddress" size="25" value="" />
+              <div id="reqEmail" class="labelerror" style="display:none;">E-mail Address is a required field</div>
+
+            </li>
+            <li>
+              <label><em>*</em> Confirm E-mail Address:</label>
+              <input class="inputbox" type="text" id="EmailAddressVerify" size="25" value="" />
+              <div id="reqCEmail" class="labelerror" style="display:none;">Confirm E-mail Address is a required field</div>
+              <div id="noMatchEmail" class="labelerror" style="display:none;">Entered E-mail Addresses did not match</div>
+            </li>
+            <p>Please enter a 4-digit numeric PIN (Personal Identification Number) below. Please make a note of your PIN, as you will need it to access different QVC services.</p>
+            <li>
+              <label><em>*</em> PIN:</label>
+              <input class="inputbox" type="password" name="Pin" id="Pin" size="4" value="" />
+
+
+              <div id="reqCPIN" class="labelerror" style="display:none;">PIN must be entered twice for verification</div>
+              <div id="noMatchPIN" class="labelerror" style="display:none;">Entered PIN values did not match</div>
+            </li>
+            <li>
+              <label><em>*</em> Verify Your PIN:</label>
+              <input class="inputbox" type="password" name="PinVerify" id="PinVerify" size="4" value="" />
+            </li>
+          </ol>
+        </fieldset>
+      </div>
+      <div class="fragTitle">Billing Address</div>
+      <div class="formSeparator">
+
+        <fieldset>
+          <ol>
+            <li>
+              <label><em>*</em> Title:</label>
+              <select name="Prefix">
+                <option value="06">Ms.</option>
+                <option value="02">Mrs.</option>
+                <option value="03">Miss</option>
+                <option value="04">Dr.</option>
+                <option value="01">Mr.</option>
+                <option value="07">Mr/Mrs</option>
+                <option value="08">Father</option>
+                <option value="09">Sister</option>
+              </select>
+            </li>
+            <li>
+              <label><em>*</em> First Name:</label>
+              <input class="inputbox" type="text" size="25" name="BilltoFirstName" id="BilltoFirstName" value="" />
+              <div id="reqBtFirst" class="labelerror" style="display:none;">First Name is a required field</div>
+            </li>
+            <li>
+              <label><em>*</em> Last Name:</label>
+              <input class="inputbox" type="text" size="25" name="BilltoLastName" id="BilltoLastName" value="" />
+              <div id="reqBtLast" class="labelerror" style="display:none;">Last Name is a required field</div>
+            </li>
+            <li>
+              <label><em>*</em> Address Line 1:</label>
+              <input class="inputbox" type="text" size="25" name="BilltoAddress1" id="BilltoAddress1" value="" />
+              <div id="reqBtAddress" class="labelerror" style="display:none;">Address is a required field</div>
+            </li>
+            <li>
+              <label class="noem"> Address Line 2:</label>
+              <input class="inputbox" type="text" size="25" name="BilltoAddress2" id="BilltoAddress2" value="" />
+            </li>
+            <li>
+              <label class="noem"> City:</label>
+              <input class="inputbox" type="text" size="25" name="BilltoCity" id="BilltoCity" value="" />
+            </li>
+            <li>
+              <label class="noem"> State/Province:</label>
+              <!--  -->
+              <select name="BilltoState" id="BilltoState" class="inputbox">
+                  <option value="AL">Alabama</option>
+                <option value="AK">Alaska</option>
+                <option value="AS">American Samoa</option>
+                <option value="AZ">Arizona</option>
+                <option value="AR">Arkansas</option>
+                <option value="AA">Armed Forces Americas</option>
+                <option value="AE">Armed Forces Europe</option>
+                <option value="AP">Armed Forces Pacific</option>
+                <option value="CA">California</option>
+                <option value="CO">Colorado</option>
+                <option value="CT">Connecticut</option>
+                <option value="DE">Delaware</option>
+                <option value="DC">District of Columbia</option>
+                <option value="FM">Federated States of Micronesia</option>
+                <option value="FL">Florida</option>
+                <option value="GA">Georgia</option>
+                <option value="GU">Guam</option>
+                <option value="HI">Hawaii</option>
+                <option value="ID">Idaho</option>
+                <option value="IL">Illinois</option>
+                <option value="IN">Indiana</option>
+                <option value="IA">Iowa</option>
+                <option value="KS">Kansas</option>
+                <option value="KY">Kentucky</option>
+                <option value="LA">Louisiana</option>
+                <option value="ME">Maine</option>
+                <option value="MH">Marshall Islands</option>
+                <option value="MD">Maryland</option>
+                <option value="MA">Massachusetts</option>
+                <option value="MI">Michigan</option>
+                <option value="MN">Minnesota</option>
+                <option value="MS">Mississippi</option>
+                <option value="MO">Missouri</option>
+                <option value="MT">Montana</option>
+                <option value="NE">Nebraska</option>
+                <option value="NV">Nevada</option>
+                <option value="NH">New Hampshire</option>
+                <option value="NJ">New Jersey</option>
+                <option value="NM">New Mexico</option>
+                <option value="NY">New York</option>
+                <option value="NC">North Carolina</option>
+                <option value="ND">North Dakota</option>
+                <option value="MP">Northern Mariana Islands</option>
+                <option value="OH">Ohio</option>
+                <option value="OK">Oklahoma</option>
+                <option value="OR">Oregon</option>
+                <option value="PW">Palau</option>
+                <option value="PA">Pennsylvania</option>
+                <option value="PR">Puerto Rico</option>
+                <option value="RI">Rhode Island</option>
+                <option value="SC">South Carolina</option>
+                <option value="SD">South Dakota</option>
+                <option value="TN">Tennessee</option>
+                <option value="TX">Texas</option>
+                <option value="UT">Utah</option>
+                <option value="VT">Vermont</option>
+                <option value="VI">Virgin Islands</option>
+                <option value="VA">Virginia</option>
+                <option value="WA">Washington</option>
+                <option value="WV">West Virginia</option>
+                <option value="WI">Wisconsin</option>
+                <option value="WY">Wyoming</option>
+                <option value="AB">Alberta</option>
+                <option value="BC">British Columbia</option>
+                <option value="MB">Manitoba</option>
+                <option value="NB">New Brunswick</option>
+                <option value="NL">Newfoundland and Labrador</option>
+                <option value="NS">Nova Scotia</option>
+                <option value="NT">Northwest Territories</option>
+                <option value="NU">Nunavut</option>
+                <option value="ON">Ontario</option>
+                <option value="PE">Prince Edward Island</option>
+                <option value="QC">Québec</option>
+                <option value="SK">Saskatchewan</option>
+                <option value="YT">Yukon</option>
+
+              </select>
+            </li>
+            <li>
+              <label><em>*</em> ZIP/Postal Code:</label>  <!-- JML 07/2008 change input box size from 10 to 6 -->
+              <input class="inputbox" type="text" size="6" maxlength="6" name="BilltoZipCode" id="BilltoZipCode" value="" />
+              <div id="reqBtZIP" class="labelerror" style="display:none;">ZIP/Postal Code is a required field</div>
+
+            </li>
+            <li>
+              <label><em>*</em> Country:</label>
+              <select name="BilltoCountry">
+
+                <option value="US" selected=&quot;selected&quot;> United States </option>
+
+                <option value="CA"> Canada </option>
+
+              </select>
+            </li>
+            <li>
+              <label><em>*</em> Home Phone:</label>
+              <input class="inputbox" type="text" size="3" name="BilltoHpArea" id="BilltoHpArea" value="" />
+              <input class="inputbox" type="text" size="3" name="BilltoHpExchange" id="BilltoHpExchange" value="" />
+              <input class="inputbox" type="text" size="4" name="BilltoHpExt" id="BilltoHpExt" value="" />
+              <div id="reqBtPhone" class="labelerror" style="display:none;">Home Phone is a required field</div>
+
+            </li>
+            <li>
+              <label class="noem">Work Phone:</label>
+              <input class="inputbox" type="text" size="3" name="BilltoWpArea" id="BilltoWpArea" value="" />
+              <input class="inputbox" type="text" size="3" name="BilltoWpExchange" id="BilltoWpExchange" value="" />
+              <input class="inputbox" type="text" size="4" name="BilltoWpExt" id="BilltoWpExt" value="" />
+            </li>
+          </ol>
+        </fieldset>
+        <input type="hidden" name="BilltoCounty" id="BilltoCounty" value="" />
+        <input type="hidden" name="BilltoGeocode" id="BilltoGeocode" value="" />
+      </div>
+      <div class="fragTitle">Ship-To Address</span></div>
+      <div class="formSeparator">
+
+        <fieldset>
+          <ol>
+            <li>
+              <label>Same as Bill-To:</label>  <!-- JML 07/2008 default checkbox setting -->
+              <input type="checkbox" id="SameAsBilltoCheckbox" name="SameAsBilltoCheckbox" value="1" checked="checked" />
+            </li>
+          </ol>
+        </fieldset>
+        <div id="expandShipTo">
+          <p>To choose a Ship-To Address that is different than your Bill-To address, type in the name and address below.</p>
+          <fieldset>
+            <ol>
+              <li>
+                <label><em>*</em> Name:</label>
+                <input class="inputbox" type="text" size="25" name="ShiptoFirstName" id="ShiptoFirstName" value="" />
+                <div id="reqStFirst" class="labelerror" style="display:none;">Name is a required field</div>
+              </li>
+              <li>
+                <label><em>*</em> Address Line 1:</label>
+                <input class="inputbox" type="text" size="25" name="ShiptoAddress1" id="ShiptoAddress1" value="" />
+                <div id="reqStAddress" class="labelerror" style="display:none;">Address is a required field</div>
+              </li>
+              <li>
+                <label class="noem"> Address Line 2:</label>
+                <input class="inputbox" type="text" size="25" name="ShiptoAddress2" id="ShiptoAddress2" value="" />
+              </li>
+              <li>
+                <label class="noem"> City:</label>
+                <input class="inputbox" type="text" size="25" name="ShiptoCity" id="ShiptoCity" value="" />
+              </li>
+              <li>
+                <label class="noem"> State/Province:</label>
+              <!--  -->
+              <select name="ShiptoState" id="ShiptoState" class="inputbox">
+                  <option value="AL">Alabama</option>
+                <option value="AK">Alaska</option>
+                <option value="AS">American Samoa</option>
+                <option value="AZ">Arizona</option>
+                <option value="AR">Arkansas</option>
+                <option value="AA">Armed Forces Americas</option>
+                <option value="AE">Armed Forces Europe</option>
+                <option value="AP">Armed Forces Pacific</option>
+                <option value="CA">California</option>
+                <option value="CO">Colorado</option>
+                <option value="CT">Connecticut</option>
+                <option value="DE">Delaware</option>
+                <option value="DC">District of Columbia</option>
+                <option value="FM">Federated States of Micronesia</option>
+                <option value="FL">Florida</option>
+                <option value="GA">Georgia</option>
+                <option value="GU">Guam</option>
+                <option value="HI">Hawaii</option>
+                <option value="ID">Idaho</option>
+                <option value="IL">Illinois</option>
+                <option value="IN">Indiana</option>
+                <option value="IA">Iowa</option>
+                <option value="KS">Kansas</option>
+                <option value="KY">Kentucky</option>
+                <option value="LA">Louisiana</option>
+                <option value="ME">Maine</option>
+                <option value="MH">Marshall Islands</option>
+                <option value="MD">Maryland</option>
+                <option value="MA">Massachusetts</option>
+                <option value="MI">Michigan</option>
+                <option value="MN">Minnesota</option>
+                <option value="MS">Mississippi</option>
+                <option value="MO">Missouri</option>
+                <option value="MT">Montana</option>
+                <option value="NE">Nebraska</option>
+                <option value="NV">Nevada</option>
+                <option value="NH">New Hampshire</option>
+                <option value="NJ">New Jersey</option>
+                <option value="NM">New Mexico</option>
+                <option value="NY">New York</option>
+                <option value="NC">North Carolina</option>
+                <option value="ND">North Dakota</option>
+                <option value="MP">Northern Mariana Islands</option>
+                <option value="OH">Ohio</option>
+                <option value="OK">Oklahoma</option>
+                <option value="OR">Oregon</option>
+                <option value="PW">Palau</option>
+                <option value="PA">Pennsylvania</option>
+                <option value="PR">Puerto Rico</option>
+                <option value="RI">Rhode Island</option>
+                <option value="SC">South Carolina</option>
+                <option value="SD">South Dakota</option>
+                <option value="TN">Tennessee</option>
+                <option value="TX">Texas</option>
+                <option value="UT">Utah</option>
+                <option value="VT">Vermont</option>
+                <option value="VI">Virgin Islands</option>
+                <option value="VA">Virginia</option>
+                <option value="WA">Washington</option>
+                <option value="WV">West Virginia</option>
+                <option value="WI">Wisconsin</option>
+                <option value="WY">Wyoming</option>
+                <option value="AB">Alberta</option>
+                <option value="BC">British Columbia</option>
+                <option value="MB">Manitoba</option>
+                <option value="NB">New Brunswick</option>
+                <option value="NL">Newfoundland and Labrador</option>
+                <option value="NS">Nova Scotia</option>
+                <option value="NT">Northwest Territories</option>
+                <option value="NU">Nunavut</option>
+                <option value="ON">Ontario</option>
+                <option value="PE">Prince Edward Island</option>
+                <option value="QC">Québec</option>
+                <option value="SK">Saskatchewan</option>
+                <option value="YT">Yukon</option>
+
+              </select>
+              </li>
+              <li>
+                <label><em>*</em> Postal Code:</label>  <!-- JML 07/2008 change input box size from 10 to 6 -->
+                <input class="inputbox" type="text" size="6" maxlength="6" name="ShiptoZipCode" id="ShiptoZipCode" value="" />
+                <div id="reqStZIP" class="labelerror" style="display:none;">ZIP/Postal Code is a required field</div>
+
+              </li>
+              <li>
+                <label><em>*</em> Country:</label>
+                <select name="ShiptoCountry" id="ShiptoCountry">
+
+                  <option value="US" selected=&quot;selected&quot;> United States </option>
+
+                  <option value="CA"> Canada </option>
+
+                </select>
+              </li>
+              <div class="billRadio">
+                <p>Use this address for:<br />
+                  <input type="radio" name="ShiptoRadiobutton" value="ThisOrderOnly" checked="checked" /> <strong>This order only</strong> <br />
+                  <input type="radio" name="ShiptoRadiobutton" value="PermanentShipto" /> <strong>All future orders</strong> (Permanent Ship-To)**
+                </p>
+                <p>** To edit your permanent ship-to address or make any changes in the future, please access your Address Book in "My Account."</p>
+              </div>
+            </ol>
+          </fieldset>
+        </div>
+        <div class="formButtons">
+          <fieldset>
+            <ol>
+              <li>
+              <label><em>*</em> Required Fields</label>
+              <div class="buttonsDiv">
+                <input type="image"  name="Continue"src="https://quality-s.qvc.com/pic/buttons/primary/continue_checkout.gif" alt="Continue Check-Out" />
+
+                  <a href="https://quality-s.qvc.com/qic/qvcapp.aspx/view.1/app.multi/params.file.|Checkout|BilltoShipto,plex.Command.CancelOrder.RefererForm.BilltoShipto"><img src="#" border="0" alt="Cancel Order" /></a>
+
+              </div>
+              </li>
+            </ol>
+          </fieldset>
+        </div>
+      </div>
+
+    </form>
+
+</body>
+</html>
+
+
diff --git a/components/test/data/autofill/heuristics/output/023_checkout_gamestop.com.out b/components/test/data/autofill/heuristics/output/023_checkout_gamestop.com.out
index 91af344a..566c3581 100644
--- a/components/test/data/autofill/heuristics/output/023_checkout_gamestop.com.out
+++ b/components/test/data/autofill/heuristics/output/023_checkout_gamestop.com.out
@@ -11,13 +11,13 @@
 EMAIL_ADDRESS | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$AddressDetails$AddressDetails$txtEmailAddress | Purchaser's Email: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
 EMAIL_ADDRESS | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$AddressDetails$AddressDetails$txtEmailAddressConfirm | Confirm Email: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
 UNKNOWN_TYPE | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$AddressDetails$AddressDetails$chkEmailOptIn | Confirm Email: | on | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-NAME_FIRST | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName | First Name: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-NAME_LAST | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textLastName | Last Name: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-ADDRESS_HOME_LINE1 | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textAddressLine1 | Address 1: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-ADDRESS_HOME_LINE2 | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textAddressLine2 | Address 2: (optional) |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-ADDRESS_HOME_CITY | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textCity | City: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-ADDRESS_HOME_STATE | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$ddlState | State/Province: | -1 | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-ADDRESS_HOME_ZIP | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textZip | Zip/Postal: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-ADDRESS_HOME_COUNTRY | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$ddlCountry | Country: | US | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
-PHONE_HOME_WHOLE_NUMBER | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textPhoneNumberDaytime | Phone Number: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
+NAME_FIRST | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName | First Name: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+NAME_LAST | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textLastName | Last Name: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+ADDRESS_HOME_LINE1 | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textAddressLine1 | Address 1: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+ADDRESS_HOME_LINE2 | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textAddressLine2 | Address 2: (optional) |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+ADDRESS_HOME_CITY | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textCity | City: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+ADDRESS_HOME_STATE | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$ddlState | State/Province: | -1 | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+ADDRESS_HOME_ZIP | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textZip | Zip/Postal: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+ADDRESS_HOME_COUNTRY | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$ddlCountry | Country: | US | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
+PHONE_HOME_WHOLE_NUMBER | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textPhoneNumberDaytime | Phone Number: |  | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$aspShippingAddress$popAddressSelection$AddressDetails1$textFirstName_1-default
 UNKNOWN_TYPE | ctl00$ctl00$ctl00$BaseContentPlaceHolder$mainContentPlaceHolder$MainContentPlaceHolder$chkSameAsBillingAddress |  | on | ctl00$ctl00$ctl00$BaseContentPlaceHolder$cHeader$searchtext_1-default
diff --git a/components/test/data/autofill/heuristics/output/025_checkout_hsn.com.out b/components/test/data/autofill/heuristics/output/025_checkout_hsn.com.out
index 06284cd7..0b32a50 100644
--- a/components/test/data/autofill/heuristics/output/025_checkout_hsn.com.out
+++ b/components/test/data/autofill/heuristics/output/025_checkout_hsn.com.out
@@ -18,14 +18,14 @@
 EMAIL_ADDRESS | Body$NewEmailAddress2 | Email Address |  | Body$BillingIsShippingCheckboxB_1-default
 UNKNOWN_TYPE | Body$WeeklyNewsletterSignup12 | Email me weekly HSN newsletters and special offers | on | Body$BillingIsShippingCheckboxB_1-default
 UNKNOWN_TYPE | Body$TSNewsletterSignup2 | Email me the daily Today's Special | on | Body$BillingIsShippingCheckboxB_1-default
-NAME_FIRST | Body$ShippingAddress$_firstName | First Name |  | Body$BillingIsShippingCheckboxB_1-default
-NAME_LAST | Body$ShippingAddress$_lastName | Last Name |  | Body$BillingIsShippingCheckboxB_1-default
-ADDRESS_HOME_LINE1 | Body$ShippingAddress$_address1 | Address Line 1 |  | Body$BillingIsShippingCheckboxB_1-default
-ADDRESS_HOME_LINE2 | Body$ShippingAddress$_address2 | Address Line 2(optional) |  | Body$BillingIsShippingCheckboxB_1-default
-ADDRESS_HOME_CITY | Body$ShippingAddress$_city | City |  | Body$BillingIsShippingCheckboxB_1-default
-ADDRESS_HOME_STATE | Body$ShippingAddress$_state | State |    | Body$BillingIsShippingCheckboxB_1-default
-ADDRESS_HOME_ZIP | Body$ShippingAddress$_zipcode | Zip Code |  | Body$BillingIsShippingCheckboxB_1-default
-PHONE_HOME_WHOLE_NUMBER | Body$ShippingAddress$_telephone | Phone Number |  | Body$BillingIsShippingCheckboxB_1-default
+NAME_FIRST | Body$ShippingAddress$_firstName | First Name |  | Body$ShippingAddress$_firstName_1-default
+NAME_LAST | Body$ShippingAddress$_lastName | Last Name |  | Body$ShippingAddress$_firstName_1-default
+ADDRESS_HOME_LINE1 | Body$ShippingAddress$_address1 | Address Line 1 |  | Body$ShippingAddress$_firstName_1-default
+ADDRESS_HOME_LINE2 | Body$ShippingAddress$_address2 | Address Line 2(optional) |  | Body$ShippingAddress$_firstName_1-default
+ADDRESS_HOME_CITY | Body$ShippingAddress$_city | City |  | Body$ShippingAddress$_firstName_1-default
+ADDRESS_HOME_STATE | Body$ShippingAddress$_state | State |    | Body$ShippingAddress$_firstName_1-default
+ADDRESS_HOME_ZIP | Body$ShippingAddress$_zipcode | Zip Code |  | Body$ShippingAddress$_firstName_1-default
+PHONE_HOME_WHOLE_NUMBER | Body$ShippingAddress$_telephone | Phone Number |  | Body$ShippingAddress$_firstName_1-default
 UNKNOWN_TYPE | PaymentTypeSelection | Pay with a Credit or Debit Card | 0 | Body$BillingIsShippingCheckboxB_1-default
 CREDIT_CARD_NUMBER | Body$CCNumber | Card Number |  | credit-card-cc
 CREDIT_CARD_EXP_MONTH | Body$CCExpirationDateMonth | Expiration Date | 0 | credit-card-cc
diff --git a/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out b/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out
index f7bdcbf7..f4e9f7a 100644
--- a/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out
+++ b/components/test/data/autofill/heuristics/output/037_checkout_qvc.com.out
@@ -19,11 +19,11 @@
 PHONE_HOME_EXTENSION | BilltoWpExt | Work Phone: |  | EmailAddress_1-default
 UNKNOWN_TYPE | SameAsBilltoCheckbox | Same as Bill-To: | 1 | EmailAddress_1-default
 UNKNOWN_TYPE | ShiptoFirstName | * Name: |  | EmailAddress_1-default
-ADDRESS_HOME_LINE1 | ShiptoAddress1 | * Address Line 1: |  | EmailAddress_1-default
-ADDRESS_HOME_LINE2 | ShiptoAddress2 | Address Line 2: |  | EmailAddress_1-default
-ADDRESS_HOME_CITY | ShiptoCity | City: |  | EmailAddress_1-default
-ADDRESS_HOME_STATE | ShiptoState | State/Province: | AL | EmailAddress_1-default
-ADDRESS_HOME_ZIP | ShiptoZipCode | * Postal Code: |  | EmailAddress_1-default
-ADDRESS_HOME_COUNTRY | ShiptoCountry | * Country: | US | EmailAddress_1-default
-UNKNOWN_TYPE | ShiptoRadiobutton | This order only | ThisOrderOnly | EmailAddress_1-default
-UNKNOWN_TYPE | ShiptoRadiobutton | (Permanent Ship-To)**All future orders | PermanentShipto | EmailAddress_1-default
+ADDRESS_HOME_LINE1 | ShiptoAddress1 | * Address Line 1: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_LINE2 | ShiptoAddress2 | Address Line 2: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_CITY | ShiptoCity | City: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_STATE | ShiptoState | State/Province: | AL | ShiptoAddress1_1-default
+ADDRESS_HOME_ZIP | ShiptoZipCode | * Postal Code: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_COUNTRY | ShiptoCountry | * Country: | US | ShiptoAddress1_1-default
+UNKNOWN_TYPE | ShiptoRadiobutton | This order only | ThisOrderOnly | ShiptoAddress1_1-default
+UNKNOWN_TYPE | ShiptoRadiobutton | (Permanent Ship-To)**All future orders | PermanentShipto | ShiptoAddress1_1-default
diff --git a/components/test/data/autofill/heuristics/output/062_register_newegg.com.out b/components/test/data/autofill/heuristics/output/062_register_newegg.com.out
index 356c04c..d28727c 100644
--- a/components/test/data/autofill/heuristics/output/062_register_newegg.com.out
+++ b/components/test/data/autofill/heuristics/output/062_register_newegg.com.out
@@ -22,19 +22,19 @@
 PHONE_HOME_EXTENSION | BDayPhone_ext1 | Ext |  | LoginName_1-default
 UNKNOWN_TYPE | same | Yes | 1 | LoginName_1-default
 UNKNOWN_TYPE | same | No | 0 | LoginName_1-default
-NAME_FIRST | SFirstName | First Name* |  | LoginName_1-default
-NAME_MIDDLE_INITIAL | SMI | MI |  | LoginName_1-default
-NAME_LAST | SLastName | Last Name* |  | LoginName_1-default
-COMPANY_NAME | SCompanyName | Company Name |  | LoginName_1-default
-ADDRESS_HOME_LINE1 | SAddress1 | Address* |  | LoginName_1-default
-ADDRESS_HOME_LINE2 | SAddress2 | Address 2 |  | LoginName_1-default
-ADDRESS_HOME_CITY | SCity | City* |  | LoginName_1-default
-ADDRESS_HOME_STATE | SState | State* | AK | LoginName_1-default
-ADDRESS_HOME_ZIP | SZip | Zip Code* |  | LoginName_1-default
-PHONE_HOME_CITY_CODE | ShippingPhone_tel1 | Shipping Phone* |  | LoginName_1-default
-PHONE_HOME_NUMBER | ShippingPhone_tel2 |  |  | LoginName_1-default
-PHONE_HOME_NUMBER | ShippingPhone_tel3 |  |  | LoginName_1-default
-PHONE_HOME_EXTENSION | ShippingPhone_ext1 | Ext |  | LoginName_1-default
+NAME_FIRST | SFirstName | First Name* |  | SFirstName_1-default
+NAME_MIDDLE_INITIAL | SMI | MI |  | SFirstName_1-default
+NAME_LAST | SLastName | Last Name* |  | SFirstName_1-default
+COMPANY_NAME | SCompanyName | Company Name |  | SFirstName_1-default
+ADDRESS_HOME_LINE1 | SAddress1 | Address* |  | SFirstName_1-default
+ADDRESS_HOME_LINE2 | SAddress2 | Address 2 |  | SFirstName_1-default
+ADDRESS_HOME_CITY | SCity | City* |  | SFirstName_1-default
+ADDRESS_HOME_STATE | SState | State* | AK | SFirstName_1-default
+ADDRESS_HOME_ZIP | SZip | Zip Code* |  | SFirstName_1-default
+PHONE_HOME_CITY_CODE | ShippingPhone_tel1 | Shipping Phone* |  | SFirstName_1-default
+PHONE_HOME_NUMBER | ShippingPhone_tel2 |  |  | SFirstName_1-default
+PHONE_HOME_NUMBER | ShippingPhone_tel3 |  |  | SFirstName_1-default
+PHONE_HOME_EXTENSION | ShippingPhone_ext1 | Ext |  | SFirstName_1-default
 UNKNOWN_TYPE | custtype | Is this purchase for personal or business use? | 200 | LoginName_1-default
 UNKNOWN_TYPE | Age | Age |  | LoginName_1-default
 UNKNOWN_TYPE | income | Income | 0 | LoginName_1-default
diff --git a/components/test/data/autofill/heuristics/output/080_crbug_53075.out b/components/test/data/autofill/heuristics/output/080_crbug_53075.out
index 8a6dfbe0..5369aaed 100644
--- a/components/test/data/autofill/heuristics/output/080_crbug_53075.out
+++ b/components/test/data/autofill/heuristics/output/080_crbug_53075.out
@@ -15,13 +15,13 @@
 ADDRESS_HOME_COUNTRY | ecomms_country | Country: | 224 | ecomms_company_name_1-default
 UNKNOWN_TYPE | delivery_address | specify a different delivery address | 1 | ecomms_company_name_1-default
 UNKNOWN_TYPE | del_title | Title: |  | ecomms_company_name_1-default
-NAME_FIRST | del_first_name | First Name: |  | ecomms_company_name_1-default
-NAME_LAST | del_last_name | Last Name: |  | ecomms_company_name_1-default
-PHONE_HOME_WHOLE_NUMBER | del_telephone | Telephone: |  | ecomms_company_name_1-default
-PHONE_HOME_WHOLE_NUMBER | del_mobile | Mobile: |  | ecomms_company_name_1-default
-ADDRESS_HOME_LINE1 | del_address1 | Address1: |  | ecomms_company_name_1-default
-ADDRESS_HOME_LINE2 | del_address2 | Address2: |  | ecomms_company_name_1-default
-ADDRESS_HOME_CITY | del_town | Town / City: |  | ecomms_company_name_1-default
-ADDRESS_HOME_STATE | del_county | County: |  | ecomms_company_name_1-default
-ADDRESS_HOME_ZIP | del_postcode | Postcode: |  | ecomms_company_name_1-default
-ADDRESS_HOME_COUNTRY | ecomms_del_country | Country: | 224 | ecomms_company_name_1-default
+NAME_FIRST | del_first_name | First Name: |  | del_first_name_1-default
+NAME_LAST | del_last_name | Last Name: |  | del_first_name_1-default
+PHONE_HOME_WHOLE_NUMBER | del_telephone | Telephone: |  | del_first_name_1-default
+PHONE_HOME_WHOLE_NUMBER | del_mobile | Mobile: |  | del_first_name_1-default
+ADDRESS_HOME_LINE1 | del_address1 | Address1: |  | del_first_name_1-default
+ADDRESS_HOME_LINE2 | del_address2 | Address2: |  | del_first_name_1-default
+ADDRESS_HOME_CITY | del_town | Town / City: |  | del_first_name_1-default
+ADDRESS_HOME_STATE | del_county | County: |  | del_first_name_1-default
+ADDRESS_HOME_ZIP | del_postcode | Postcode: |  | del_first_name_1-default
+ADDRESS_HOME_COUNTRY | ecomms_del_country | Country: | 224 | del_first_name_1-default
diff --git a/components/test/data/autofill/heuristics/output/083_crbug_87517.out b/components/test/data/autofill/heuristics/output/083_crbug_87517.out
index c25e2e2e..9bf531d 100644
--- a/components/test/data/autofill/heuristics/output/083_crbug_87517.out
+++ b/components/test/data/autofill/heuristics/output/083_crbug_87517.out
@@ -26,11 +26,11 @@
 UNKNOWN_TYPE | Tribute_IncludeAmount | Include the amount | 1 | f1_1-default
 UNKNOWN_TYPE | Tribute_IncludeAmount | Do not include the amount | 0 | f1_1-default
 NAME_FULL | Tribute_NotifyName | Name: |  | f1_1-default
-EMAIL_ADDRESS | Tribute_Email | Email: |  | f1_1-default
-ADDRESS_HOME_LINE1 | Tribute_NotifyAddr | Street: |  | f1_1-default
-ADDRESS_HOME_CITY | Tribute_NotifyCity | City / St. / Zip: |  | f1_1-default
-ADDRESS_HOME_STATE | Tribute_NotifyState | City / St. / Zip: |  | f1_1-default
-ADDRESS_HOME_ZIP | Tribute_NotifyZip | City / St. / Zip: |  | f1_1-default
+EMAIL_ADDRESS | Tribute_Email | Email: |  | Tribute_Email_1-default
+ADDRESS_HOME_LINE1 | Tribute_NotifyAddr | Street: |  | Tribute_Email_1-default
+ADDRESS_HOME_CITY | Tribute_NotifyCity | City / St. / Zip: |  | Tribute_Email_1-default
+ADDRESS_HOME_STATE | Tribute_NotifyState | City / St. / Zip: |  | Tribute_Email_1-default
+ADDRESS_HOME_ZIP | Tribute_NotifyZip | City / St. / Zip: |  | Tribute_Email_1-default
 CREDIT_CARD_TYPE | cctype | Credit Card Type * | Visa | credit-card-cc
 CREDIT_CARD_NUMBER | ccard | Credit Card Number * |  | credit-card-cc
 CREDIT_CARD_VERIFICATION_CODE | csc | CSC Number * What Is This? |  | credit-card-cc
diff --git a/components/test/data/autofill/heuristics/output/092_checkout_alaskaair.com.out b/components/test/data/autofill/heuristics/output/092_checkout_alaskaair.com.out
index 20561a7..9fe174d 100644
--- a/components/test/data/autofill/heuristics/output/092_checkout_alaskaair.com.out
+++ b/components/test/data/autofill/heuristics/output/092_checkout_alaskaair.com.out
@@ -36,5 +36,5 @@
 ADDRESS_HOME_STATE | AncillaryCreditCardInformation.BillingAddressEntry.MXStates_Selected | State/Province |  | CreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected_1-default
 UNKNOWN_TYPE | AncillaryCreditCardInformation.BillingAddressEntry.OtherStates_Selected | State/Province |  | CreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected_1-default
 ADDRESS_HOME_ZIP | AncillaryCreditCardInformation.BillingAddressEntry.PostalCode | Zip/Postal Code |  | CreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected_1-default
-ADDRESS_HOME_COUNTRY | AncillaryCreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected | Country Code | 1 | CreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected_1-default
-PHONE_HOME_WHOLE_NUMBER | AncillaryCreditCardInformation.BillingPhoneNumberEntry.Number | Phone (with area code) |  | CreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected_1-default
+ADDRESS_HOME_COUNTRY | AncillaryCreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected | Country Code | 1 | AncillaryCreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected_1-default
+PHONE_HOME_WHOLE_NUMBER | AncillaryCreditCardInformation.BillingPhoneNumberEntry.Number | Phone (with area code) |  | AncillaryCreditCardInformation.BillingPhoneNumberEntry.CountryCode_Selected_1-default
diff --git a/components/test/data/autofill/heuristics/output/096_llbean.out b/components/test/data/autofill/heuristics/output/096_llbean.out
index 646408a..78a58185 100644
--- a/components/test/data/autofill/heuristics/output/096_llbean.out
+++ b/components/test/data/autofill/heuristics/output/096_llbean.out
@@ -18,12 +18,12 @@
 ADDRESS_HOME_ZIP | zipCode | Zip Code |  | personTitle_1-default
 ADDRESS_HOME_CITY | city | City |  | personTitle_1-default
 ADDRESS_HOME_STATE | state | State |  | personTitle_1-default
-ADDRESS_HOME_ZIP | CAPostal | Postal Code |  | personTitle_1-default
-ADDRESS_HOME_CITY | CACity | City |  | personTitle_1-default
-ADDRESS_HOME_STATE | CAProvince | Province |  | personTitle_1-default
-ADDRESS_HOME_CITY | INTLCity | City |  | personTitle_1-default
-ADDRESS_HOME_STATE | INTLCounty | County |  | personTitle_1-default
-ADDRESS_HOME_ZIP | INTLPostal | Postal Code |  | personTitle_1-default
+ADDRESS_HOME_ZIP | CAPostal | Postal Code |  | CAPostal_1-default
+ADDRESS_HOME_CITY | CACity | City |  | CAPostal_1-default
+ADDRESS_HOME_STATE | CAProvince | Province |  | CAPostal_1-default
+ADDRESS_HOME_CITY | INTLCity | City |  | CAPostal_1-default
+ADDRESS_HOME_STATE | INTLCounty | County |  | CAPostal_1-default
+ADDRESS_HOME_ZIP | INTLPostal | Postal Code |  | CAPostal_1-default
 PHONE_HOME_WHOLE_NUMBER | phone1 | Daytime Phone Number (optional) |  | personTitle_1-default
 PHONE_HOME_WHOLE_NUMBER | intlPhone1Prefix | International Country Code |  | personTitle_1-default
 PHONE_HOME_WHOLE_NUMBER | intlPhone1 | Daytime Phone Number |  | personTitle_1-default
diff --git a/components/test/data/autofill/heuristics/output/097_register_alaskaair.com.out b/components/test/data/autofill/heuristics/output/097_register_alaskaair.com.out
index 75d00c7..bde99aa 100644
--- a/components/test/data/autofill/heuristics/output/097_register_alaskaair.com.out
+++ b/components/test/data/autofill/heuristics/output/097_register_alaskaair.com.out
@@ -10,7 +10,7 @@
 UNKNOWN_TYPE | FormUserControl$_personalIdentification$_birthDate$_birthDate$_day | Day |  | FormUserControl$_mileagePlanNumber$_mileagePlanChoice_1-default
 UNKNOWN_TYPE | FormUserControl$_personalIdentification$_birthDate$_birthDate$_yearTextBox | Year | Year | FormUserControl$_mileagePlanNumber$_mileagePlanChoice_1-default
 UNKNOWN_TYPE | FormUserControl$_personalIdentification$_gender$_gender | Gender* |  | FormUserControl$_mileagePlanNumber$_mileagePlanChoice_1-default
-NAME_FIRST | FormUserControl$_guardianInformation$_firstName$_name | First Name* |  | FormUserControl$_mileagePlanNumber$_mileagePlanChoice_1-default
+NAME_FIRST | FormUserControl$_guardianInformation$_firstName$_name | First Name* |  | FormUserControl$_guardianInformation$_firstName$_name_1-default
 NAME_LAST | FormUserControl$_guardianInformation$_lastName$_name | Last Name* |  | FormUserControl$_guardianInformation$_lastName$_name_1-default
 EMAIL_ADDRESS | FormUserControl$_guardianInformation$_email$_emailAddressTextBox | Email Address* |  | FormUserControl$_guardianInformation$_lastName$_name_1-default
 ADDRESS_HOME_COUNTRY | FormUserControl$_mailingAddress$_country | Country* | US | FormUserControl$_guardianInformation$_lastName$_name_1-default
diff --git a/components/test/data/autofill/heuristics/output/112_checkout_m_llbean.com.out b/components/test/data/autofill/heuristics/output/112_checkout_m_llbean.com.out
index 848008f..a3e2103c 100644
--- a/components/test/data/autofill/heuristics/output/112_checkout_m_llbean.com.out
+++ b/components/test/data/autofill/heuristics/output/112_checkout_m_llbean.com.out
@@ -14,12 +14,12 @@
 ADDRESS_HOME_ZIP | _1_zipCode | Enter Zip for City and State |  | _1_zipCode_1-default
 ADDRESS_HOME_CITY | _1_city | City |  | _1_zipCode_1-default
 ADDRESS_HOME_STATE | _1_state |  |  | _1_zipCode_1-default
-ADDRESS_HOME_ZIP | _1_CAPostal | Postal Code |  | _1_zipCode_1-default
-ADDRESS_HOME_CITY | _1_CACity | City |  | _1_zipCode_1-default
-ADDRESS_HOME_STATE | _1_CAProvince | Province |  | _1_zipCode_1-default
-ADDRESS_HOME_CITY | _1_INTLCity | City |  | _1_zipCode_1-default
-ADDRESS_HOME_STATE | _1_INTLCounty | County |  | _1_zipCode_1-default
-ADDRESS_HOME_ZIP | _1_INTLPostal | Postal Code |  | _1_zipCode_1-default
+ADDRESS_HOME_ZIP | _1_CAPostal | Postal Code |  | _1_CAPostal_1-default
+ADDRESS_HOME_CITY | _1_CACity | City |  | _1_CAPostal_1-default
+ADDRESS_HOME_STATE | _1_CAProvince | Province |  | _1_CAPostal_1-default
+ADDRESS_HOME_CITY | _1_INTLCity | City |  | _1_CAPostal_1-default
+ADDRESS_HOME_STATE | _1_INTLCounty | County |  | _1_CAPostal_1-default
+ADDRESS_HOME_ZIP | _1_INTLPostal | Postal Code |  | _1_CAPostal_1-default
 UNKNOWN_TYPE | _1_addressSelect | Home | homeAddress | _1_zipCode_1-default
 UNKNOWN_TYPE | _1_addressSelect | Business | bizAddress | _1_zipCode_1-default
 COMPANY_NAME | _1_otherAddress | Company Name (optional) |  | _1_zipCode_1-default
diff --git a/components/test/data/autofill/heuristics/output/118_checkout_cvs.com.out b/components/test/data/autofill/heuristics/output/118_checkout_cvs.com.out
index 55c8eaa7..27073b7 100644
--- a/components/test/data/autofill/heuristics/output/118_checkout_cvs.com.out
+++ b/components/test/data/autofill/heuristics/output/118_checkout_cvs.com.out
@@ -9,32 +9,32 @@
 UNKNOWN_TYPE | orderConfirmation | Send order information to somebody@example.com. | on | fname_1-default
 EMAIL_ADDRESS | cemail | Specify a different email address: |  | fname_1-default
 UNKNOWN_TYPE | bopusPerson | ... will pick up order. | on | fname_1-default
-NAME_FIRST | bdfname | First Name |  | fname_1-default
-NAME_LAST | bdlname | Last Name |  | fname_1-default
-PHONE_HOME_WHOLE_NUMBER | bdphone | Phone Number |  | fname_1-default
-UNKNOWN_TYPE | bopusSMSagree | Text me information from CVS/pharmacy, including information about my order. I Agree to the Mobile Terms of Use. | on | fname_1-default
-UNKNOWN_TYPE | orderConfirmation1 | Send order information to . | on | fname_1-default
-EMAIL_ADDRESS | bdemail | Specify a different email address |  | fname_1-default
-UNKNOWN_TYPE | bopusSMSagree1 | Text me information from CVS/pharmacy�, including information about my order. | on | fname_1-default
-UNKNOWN_TYPE | fsaValue | I would like to apply $0.00 of eligible items in this order to my FSA Debit Card. | on | fname_1-default
-UNKNOWN_TYPE | fsaValue1 | I would like to apply $0.00 of eligible items in this order to my FSA Debit Card. | on | fname_1-default
+NAME_FIRST | bdfname | First Name |  | bdfname_1-default
+NAME_LAST | bdlname | Last Name |  | bdfname_1-default
+PHONE_HOME_WHOLE_NUMBER | bdphone | Phone Number |  | bdfname_1-default
+UNKNOWN_TYPE | bopusSMSagree | Text me information from CVS/pharmacy, including information about my order. I Agree to the Mobile Terms of Use. | on | bdfname_1-default
+UNKNOWN_TYPE | orderConfirmation1 | Send order information to . | on | bdfname_1-default
+EMAIL_ADDRESS | bdemail | Specify a different email address |  | bdfname_1-default
+UNKNOWN_TYPE | bopusSMSagree1 | Text me information from CVS/pharmacy�, including information about my order. | on | bdfname_1-default
+UNKNOWN_TYPE | fsaValue | I would like to apply $0.00 of eligible items in this order to my FSA Debit Card. | on | bdfname_1-default
+UNKNOWN_TYPE | fsaValue1 | I would like to apply $0.00 of eligible items in this order to my FSA Debit Card. | on | bdfname_1-default
 CREDIT_CARD_NUMBER | ccfield | FSA Card |  | credit-card-cc
-PHONE_HOME_WHOLE_NUMBER | expfield | First Name Last Name Street Address Apartment, Building, Floor, Etc City State ZIP Code Phone Number FSA Card Exp FSA Card Exp First Name Last Name Street Address Apartment, Building, Floor, Etc City State ZIP Code Phone Number Credit Card Exp Credit Card Exp First Name Last Name Street Address Apartment, Building, Floor, Etc City State ZIP Code Phone Number |  | fname_1-default
+PHONE_HOME_WHOLE_NUMBER | expfield | First Name Last Name Street Address Apartment, Building, Floor, Etc City State ZIP Code Phone Number FSA Card Exp FSA Card Exp First Name Last Name Street Address Apartment, Building, Floor, Etc City State ZIP Code Phone Number Credit Card Exp Credit Card Exp First Name Last Name Street Address Apartment, Building, Floor, Etc City State ZIP Code Phone Number |  | bdfname_1-default
 CREDIT_CARD_VERIFICATION_CODE | cvvfield | Specify a different email address: First Name Last Name Phone Number Specify a different email address CVV CVV CVV CVV |  | credit-card-cc
 CREDIT_CARD_VERIFICATION_CODE | cvvfield | | CVV |  | credit-card-cc
 CREDIT_CARD_NUMBER | ccfield | FSA Card |  | credit-card-cc
 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR | expfield | Exp |  | credit-card-cc
 CREDIT_CARD_VERIFICATION_CODE | cvvfield | CVV |  | credit-card-cc
 CREDIT_CARD_VERIFICATION_CODE | cvvfield | |CVV |  | credit-card-cc
-UNKNOWN_TYPE | chk1 | Use ... as Billing Address. | on | fname_1-default
-NAME_FIRST | ffname | First Name |  | fname_1-default
-NAME_LAST | flname | Last Name |  | fname_1-default
-ADDRESS_HOME_LINE1 | fstreetAddr | Street Address |  | fname_1-default
-ADDRESS_HOME_LINE2 | fstreetAddr1 | Apartment, Building, Floor, Etc |  | fname_1-default
-ADDRESS_HOME_CITY | fcity | City |  | fname_1-default
-ADDRESS_HOME_STATE | sstateName | State | 0 | fname_1-default
-ADDRESS_HOME_ZIP | fzip | ZIP Code |  | fname_1-default
-PHONE_HOME_WHOLE_NUMBER | fphone | Phone Number |  | fname_1-default
+UNKNOWN_TYPE | chk1 | Use ... as Billing Address. | on | bdfname_1-default
+NAME_FIRST | ffname | First Name |  | bdfname_1-default
+NAME_LAST | flname | Last Name |  | bdfname_1-default
+ADDRESS_HOME_LINE1 | fstreetAddr | Street Address |  | bdfname_1-default
+ADDRESS_HOME_LINE2 | fstreetAddr1 | Apartment, Building, Floor, Etc |  | bdfname_1-default
+ADDRESS_HOME_CITY | fcity | City |  | bdfname_1-default
+ADDRESS_HOME_STATE | sstateName | State | 0 | bdfname_1-default
+ADDRESS_HOME_ZIP | fzip | ZIP Code |  | bdfname_1-default
+PHONE_HOME_WHOLE_NUMBER | fphone | Phone Number |  | bdfname_1-default
 CREDIT_CARD_NUMBER | ccfield | Credit Card |  | credit-card-cc
 CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR | expfield | Exp |  | credit-card-cc
 CREDIT_CARD_VERIFICATION_CODE | cvvfield | CVV |  | credit-card-cc
@@ -45,11 +45,11 @@
 CREDIT_CARD_VERIFICATION_CODE | cvvfield | |CVV |  | credit-card-cc
 UNKNOWN_TYPE | billing | Use ... | on | fname_1-default
 UNKNOWN_TYPE | newaddress | Specify a Different Billing Address Specify a Billing Address: |  | fname_1-default
-NAME_FIRST | ufname | First Name |  | fname_1-default
-NAME_LAST | ulname | Last Name |  | fname_1-default
-ADDRESS_HOME_LINE1 | ustreetAddr | Street Address |  | fname_1-default
-ADDRESS_HOME_LINE2 | ustreetAddr1 | Apartment, Building, Floor, Etc |  | fname_1-default
-ADDRESS_HOME_CITY | ucity | City |  | fname_1-default
-ADDRESS_HOME_STATE | ustateName | State | 0 | fname_1-default
-ADDRESS_HOME_ZIP | uzip | ZIP Code |  | fname_1-default
-PHONE_HOME_WHOLE_NUMBER | uphone | Phone Number |  | fname_1-default
+NAME_FIRST | ufname | First Name |  | ufname_1-default
+NAME_LAST | ulname | Last Name |  | ufname_1-default
+ADDRESS_HOME_LINE1 | ustreetAddr | Street Address |  | ufname_1-default
+ADDRESS_HOME_LINE2 | ustreetAddr1 | Apartment, Building, Floor, Etc |  | ufname_1-default
+ADDRESS_HOME_CITY | ucity | City |  | ufname_1-default
+ADDRESS_HOME_STATE | ustateName | State | 0 | ufname_1-default
+ADDRESS_HOME_ZIP | uzip | ZIP Code |  | ufname_1-default
+PHONE_HOME_WHOLE_NUMBER | uphone | Phone Number |  | ufname_1-default
diff --git a/components/test/data/autofill/heuristics/output/127_bug_463986.out b/components/test/data/autofill/heuristics/output/127_bug_463986.out
index f057c88..88c35e9 100644
--- a/components/test/data/autofill/heuristics/output/127_bug_463986.out
+++ b/components/test/data/autofill/heuristics/output/127_bug_463986.out
@@ -30,28 +30,28 @@
 CREDIT_CARD_EXP_MONTH | accountExpiryMonth | Expiration Date | - | credit-card-cc
 CREDIT_CARD_EXP_4_DIGIT_YEAR | accountExpiryYear | Expiration Date | - | credit-card-cc
 CREDIT_CARD_VERIFICATION_CODE | accountVerification | Verification Number * |  | credit-card-cc
-ADDRESS_HOME_COUNTRY | accountCountry | Country |  | salutation_1-default
-UNKNOWN_TYPE | bankAccHolder | Account holder |  | salutation_1-default
-UNKNOWN_TYPE | accountNo | Account Number |  | salutation_1-default
-UNKNOWN_TYPE | accountClearing | Bank Clearing |  | salutation_1-default
-UNKNOWN_TYPE | accountBank | Bank Code |  | salutation_1-default
-UNKNOWN_TYPE | checkingAccountNumber | Bank Name |  | salutation_1-default
-UNKNOWN_TYPE | codeCIN | Code CIN |  | salutation_1-default
-UNKNOWN_TYPE | codeABI | Code ABI |  | salutation_1-default
-UNKNOWN_TYPE | codeCAB | Code CAB |  | salutation_1-default
-ADDRESS_HOME_ZIP | codigoEntidad | Codigo de Entidad |  | salutation_1-default
-ADDRESS_HOME_ZIP | codigoOficina | Codigo de Oficina |  | salutation_1-default
-UNKNOWN_TYPE | controlDigits | Digitos de Control |  | salutation_1-default
-UNKNOWN_TYPE | identificationPaper | Digitos de Control | IDCARD | salutation_1-default
-UNKNOWN_TYPE | identificationValue | Digitos de Control |  | salutation_1-default
-UNKNOWN_TYPE | virtualAccountBrand | Provider |  | salutation_1-default
-UNKNOWN_TYPE | virtualAccountId | Username / Id |  | salutation_1-default
-UNKNOWN_TYPE | userAccountBrand | Provider |  | salutation_1-default
-UNKNOWN_TYPE | userAccountId | Username / Id |  | salutation_1-default
-UNKNOWN_TYPE | userAccountPassword | Password |  | salutation_1-default
-UNKNOWN_TYPE | userAccountPasswordReType | Re-type password |  | salutation_1-default
-ADDRESS_HOME_COUNTRY | onlineTransferCountry | Country | US | salutation_1-default
-UNKNOWN_TYPE | onlineTransferInstitute | Bank | ACHSECUR | salutation_1-default
-UNKNOWN_TYPE | otAccountNumber | Account No. |  | salutation_1-default
-UNKNOWN_TYPE | otBankCode | Bank Code |  | salutation_1-default
+ADDRESS_HOME_COUNTRY | accountCountry | Country |  | accountCountry_1-default
+UNKNOWN_TYPE | bankAccHolder | Account holder |  | accountCountry_1-default
+UNKNOWN_TYPE | accountNo | Account Number |  | accountCountry_1-default
+UNKNOWN_TYPE | accountClearing | Bank Clearing |  | accountCountry_1-default
+UNKNOWN_TYPE | accountBank | Bank Code |  | accountCountry_1-default
+UNKNOWN_TYPE | checkingAccountNumber | Bank Name |  | accountCountry_1-default
+UNKNOWN_TYPE | codeCIN | Code CIN |  | accountCountry_1-default
+UNKNOWN_TYPE | codeABI | Code ABI |  | accountCountry_1-default
+UNKNOWN_TYPE | codeCAB | Code CAB |  | accountCountry_1-default
+ADDRESS_HOME_ZIP | codigoEntidad | Codigo de Entidad |  | accountCountry_1-default
+ADDRESS_HOME_ZIP | codigoOficina | Codigo de Oficina |  | accountCountry_1-default
+UNKNOWN_TYPE | controlDigits | Digitos de Control |  | accountCountry_1-default
+UNKNOWN_TYPE | identificationPaper | Digitos de Control | IDCARD | accountCountry_1-default
+UNKNOWN_TYPE | identificationValue | Digitos de Control |  | accountCountry_1-default
+UNKNOWN_TYPE | virtualAccountBrand | Provider |  | accountCountry_1-default
+UNKNOWN_TYPE | virtualAccountId | Username / Id |  | accountCountry_1-default
+UNKNOWN_TYPE | userAccountBrand | Provider |  | accountCountry_1-default
+UNKNOWN_TYPE | userAccountId | Username / Id |  | accountCountry_1-default
+UNKNOWN_TYPE | userAccountPassword | Password |  | accountCountry_1-default
+UNKNOWN_TYPE | userAccountPasswordReType | Re-type password |  | accountCountry_1-default
+ADDRESS_HOME_COUNTRY | onlineTransferCountry | Country | US | accountCountry_1-default
+UNKNOWN_TYPE | onlineTransferInstitute | Bank | ACHSECUR | accountCountry_1-default
+UNKNOWN_TYPE | otAccountNumber | Account No. |  | accountCountry_1-default
+UNKNOWN_TYPE | otBankCode | Bank Code |  | accountCountry_1-default
 UNKNOWN_TYPE | accept | I read and understood and I accept the terms in force in                                         IKEA | on | salutation_1-default
diff --git a/components/test/data/autofill/heuristics/output/140_checkout_nike.com.out b/components/test/data/autofill/heuristics/output/140_checkout_nike.com.out
index d63b1247..54f554fa 100644
--- a/components/test/data/autofill/heuristics/output/140_checkout_nike.com.out
+++ b/components/test/data/autofill/heuristics/output/140_checkout_nike.com.out
@@ -7,13 +7,13 @@
 ADDRESS_HOME_CITY | city | City * |  | selectAddressType_1-default
 ADDRESS_HOME_STATE | singleState | State * |  | selectAddressType_1-default
 ADDRESS_HOME_ZIP | postalCodeField | ZIP Code * |  | selectAddressType_1-default
-NAME_FIRST | fname | First Name * |  | selectAddressType_1-default
-NAME_LAST | lname | Last Name * |  | selectAddressType_1-default
-ADDRESS_HOME_LINE1 | address1Field | Address * |  | selectAddressType_1-default
-ADDRESS_HOME_LINE2 | address2Field | Enter the military command or organization name if applicable |  | selectAddressType_1-default
-ADDRESS_HOME_CITY | apoCity | APO/FPO * | APO | selectAddressType_1-default
-ADDRESS_HOME_STATE | apoState | Region * | AA | selectAddressType_1-default
-ADDRESS_HOME_ZIP | postalCodeField | ZIP Code * |  | selectAddressType_1-default
+NAME_FIRST | fname | First Name * |  | fname_2-default
+NAME_LAST | lname | Last Name * |  | fname_2-default
+ADDRESS_HOME_LINE1 | address1Field | Address * |  | fname_2-default
+ADDRESS_HOME_LINE2 | address2Field | Enter the military command or organization name if applicable |  | fname_2-default
+ADDRESS_HOME_CITY | apoCity | APO/FPO * | APO | fname_2-default
+ADDRESS_HOME_STATE | apoState | Region * | AA | fname_2-default
+ADDRESS_HOME_ZIP | postalCodeField | ZIP Code * |  | fname_2-default
 UNKNOWN_TYPE | shippingMethod_single | Standard (Arrives 2-4 Days) FREE | Ground Service | selectAddressType_1-default
 UNKNOWN_TYPE | shippingMethod_single | Standard (Arrives 2-4 Days) FREE | Two Day Air | selectAddressType_1-default
 UNKNOWN_TYPE | shippingMethod_single | Standard (Arrives 2-4 Days) FREE | Next Day Air | selectAddressType_1-default
diff --git a/components/test/data/autofill/heuristics/output/149_checkout_qvc.com_non_hidden.out b/components/test/data/autofill/heuristics/output/149_checkout_qvc.com_non_hidden.out
new file mode 100644
index 0000000..fded2eb7
--- /dev/null
+++ b/components/test/data/autofill/heuristics/output/149_checkout_qvc.com_non_hidden.out
@@ -0,0 +1,29 @@
+EMAIL_ADDRESS | EmailAddress | * E-mail Address: |  | EmailAddress_1-default
+EMAIL_ADDRESS | EmailAddressVerify | * Confirm E-mail Address: |  | EmailAddress_1-default
+UNKNOWN_TYPE | Pin | * PIN: |  | EmailAddress_1-default
+UNKNOWN_TYPE | PinVerify | * Verify Your PIN: |  | EmailAddress_1-default
+UNKNOWN_TYPE | Prefix | * Title: | 06 | EmailAddress_1-default
+NAME_FIRST | BilltoFirstName | * First Name: |  | EmailAddress_1-default
+NAME_LAST | BilltoLastName | * Last Name: |  | EmailAddress_1-default
+ADDRESS_HOME_LINE1 | BilltoAddress1 | * Address Line 1: |  | EmailAddress_1-default
+ADDRESS_HOME_LINE2 | BilltoAddress2 | Address Line 2: |  | EmailAddress_1-default
+ADDRESS_HOME_CITY | BilltoCity | City: |  | EmailAddress_1-default
+ADDRESS_HOME_STATE | BilltoState | State/Province: | AL | EmailAddress_1-default
+ADDRESS_HOME_ZIP | BilltoZipCode | * ZIP/Postal Code: |  | EmailAddress_1-default
+ADDRESS_HOME_COUNTRY | BilltoCountry | * Country: | US | EmailAddress_1-default
+PHONE_HOME_CITY_CODE | BilltoHpArea | * Home Phone: |  | EmailAddress_1-default
+PHONE_HOME_NUMBER | BilltoHpExchange | * Home Phone: |  | EmailAddress_1-default
+PHONE_HOME_EXTENSION | BilltoHpExt | * Home Phone: |  | EmailAddress_1-default
+PHONE_HOME_CITY_CODE | BilltoWpArea | Work Phone: |  | EmailAddress_1-default
+PHONE_HOME_NUMBER | BilltoWpExchange | Work Phone: |  | EmailAddress_1-default
+PHONE_HOME_EXTENSION | BilltoWpExt | Work Phone: |  | EmailAddress_1-default
+UNKNOWN_TYPE | SameAsBilltoCheckbox | Same as Bill-To: | 1 | EmailAddress_1-default
+UNKNOWN_TYPE | ShiptoFirstName | * Name: |  | EmailAddress_1-default
+ADDRESS_HOME_LINE1 | ShiptoAddress1 | * Address Line 1: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_LINE2 | ShiptoAddress2 | Address Line 2: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_CITY | ShiptoCity | City: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_STATE | ShiptoState | State/Province: | AL | ShiptoAddress1_1-default
+ADDRESS_HOME_ZIP | ShiptoZipCode | * Postal Code: |  | ShiptoAddress1_1-default
+ADDRESS_HOME_COUNTRY | ShiptoCountry | * Country: | US | ShiptoAddress1_1-default
+UNKNOWN_TYPE | ShiptoRadiobutton | This order only | ThisOrderOnly | ShiptoAddress1_1-default
+UNKNOWN_TYPE | ShiptoRadiobutton | (Permanent Ship-To)** All future orders | PermanentShipto | ShiptoAddress1_1-default
diff --git a/components/url_formatter/elide_url.cc b/components/url_formatter/elide_url.cc
index 9e9ba3d..77cd4dd0 100644
--- a/components/url_formatter/elide_url.cc
+++ b/components/url_formatter/elide_url.cc
@@ -142,85 +142,6 @@
       base::ASCIIToUTF16(host_in_puny) : host;
 }
 
-// Adjust the components of |parsed| to describe a portion of a previous URL.
-// |offset| and |length| describe the substring range.  Components that fall
-// completely outside the specified range are invalidated, while others are
-// clamped to fit.  If |offset| is non-zero, the start positions of all valid
-// components are reduced by this offset.
-void AdjustParsed(int length, int offset, url::Parsed* parsed) {
-  DCHECK_GE(length, 0);
-  DCHECK_GE(offset, 0);
-
-  const std::vector<url::Component*> components = {
-      &(parsed->scheme), &(parsed->username), &(parsed->password),
-      &(parsed->host),   &(parsed->port),     &(parsed->path),
-      &(parsed->query),  &(parsed->ref),
-  };
-
-  for (auto* component : components) {
-    if (!component->is_valid())
-      continue;
-    int begin = base::ClampToRange(component->begin - offset, 0, length);
-    int end = base::ClampToRange(component->end() - offset, 0, length);
-    component->begin = begin;
-    component->len = end - begin;
-    if (component->len == 0)
-      component->reset();
-  }
-}
-
-// Elide a URL string with ellipsis at either the head or tail end, and adjust
-// |parsed| accordingly. This allows a formatted URL to be elided while
-// maintaining a Parsed description of the result.
-base::string16 ElideParsedUrlString(const base::string16& original,
-                                    const gfx::FontList& font_list,
-                                    float available_pixel_width,
-                                    gfx::ElideBehavior behavior,
-                                    gfx::Typesetter typesetter,
-                                    url::Parsed* parsed) {
-  DCHECK(behavior == gfx::ELIDE_TAIL || behavior == gfx::ELIDE_HEAD);
-
-  base::string16 elided = gfx::ElideText(
-      original, font_list, available_pixel_width, behavior, typesetter);
-  if (elided == original)
-    return elided;
-
-  // If elision reduced the string to a tiny remaining fragment, standardize it.
-  if (elided == (base::string16(gfx::kEllipsisUTF16) + gfx::kEllipsisUTF16))
-    elided = base::string16(gfx::kEllipsisUTF16);
-
-  int offset =
-      (behavior == gfx::ELIDE_HEAD) ? original.size() - elided.size() : 0;
-  AdjustParsed(elided.size(), offset, parsed);
-  return elided;
-}
-
-// Elide the path and onward components of a URL string to fit a specified
-// width, if possible.  If trimming these components allows the URL to fit,
-// |url_string| and |parsed| are updated and the function returns true.
-// Otherwise, inputs are untouched and the function returns false.
-bool ElideAfterHost(base::string16* url_string,
-                    const gfx::FontList& font_list,
-                    float available_pixel_width,
-                    gfx::Typesetter typesetter,
-                    url::Parsed* parsed) {
-  DCHECK(parsed->host.is_nonempty());
-  DCHECK(parsed->path.is_nonempty() || parsed->query.is_nonempty() ||
-         parsed->ref.is_nonempty());
-
-  const base::string16 shortest = url_string->substr(0, parsed->host.end()) +
-                                  gfx::kForwardSlash +
-                                  base::string16(gfx::kEllipsisUTF16);
-  if (available_pixel_width >=
-      gfx::GetStringWidthF(shortest, font_list, typesetter)) {
-    *url_string =
-        ElideParsedUrlString(*url_string, font_list, available_pixel_width,
-                             gfx::ELIDE_TAIL, typesetter, parsed);
-    return true;
-  }
-  return false;
-}
-
 }  // namespace
 
 namespace url_formatter {
@@ -516,63 +437,4 @@
   return result;
 }
 
-base::string16 ElideUrlSimple(const GURL& url,
-                              const base::string16& unelided_url_string,
-                              const gfx::FontList& font_list,
-                              float available_pixel_width,
-                              url::Parsed* parsed) {
-  // Note the typesetter only matters for Mac, where this function is only used
-  // in tests. Using BROWSER keeps the behavior consistent with other tests.
-  const gfx::Typesetter typesetter = gfx::Typesetter::BROWSER;
-
-  DCHECK_NE(parsed, nullptr);
-  base::string16 url_string = unelided_url_string;
-
-  if (available_pixel_width <= 0 ||
-      available_pixel_width >=
-          gfx::GetStringWidthF(url_string, font_list, typesetter)) {
-    return url_string;
-  }
-
-  // If non-standard, a file, or there is no host, simply elide from the right.
-  if (!url.IsStandard() || url.SchemeIsFile() || !parsed->host.is_nonempty()) {
-    return ElideParsedUrlString(url_string, font_list, available_pixel_width,
-                                gfx::ELIDE_TAIL, typesetter, parsed);
-  }
-
-  bool has_path_ref_query = parsed->path.is_nonempty() ||
-                            parsed->query.is_nonempty() ||
-                            parsed->ref.is_nonempty();
-
-  // Try fitting the host with scheme preserved.
-  if (has_path_ref_query &&
-      ElideAfterHost(&url_string, font_list, available_pixel_width, typesetter,
-                     parsed)) {
-    return url_string;
-  }
-
-  // Remove the scheme and try fitting the host again.
-  if (parsed->host.begin > 0) {
-    url_string.erase(0, parsed->host.begin);
-    AdjustParsed(url_string.size(), parsed->host.begin, parsed);
-
-    if (has_path_ref_query &&
-        ElideAfterHost(&url_string, font_list, available_pixel_width,
-                       typesetter, parsed)) {
-      return url_string;
-    }
-  }
-
-  // Fully elide everything after the host, as none of it can fit.
-  if (has_path_ref_query) {
-    url_string = url_string.substr(0, parsed->host.end()) + gfx::kForwardSlash +
-                 base::string16(gfx::kEllipsisUTF16);
-    AdjustParsed(url_string.size(), 0, parsed);
-  }
-
-  // Only host remains, so elide from the left.
-  return ElideParsedUrlString(url_string, font_list, available_pixel_width,
-                              gfx::ELIDE_HEAD, typesetter, parsed);
-}
-
 }  // namespace url_formatter
diff --git a/components/url_formatter/elide_url.h b/components/url_formatter/elide_url.h
index d991b3cd..2971866 100644
--- a/components/url_formatter/elide_url.h
+++ b/components/url_formatter/elide_url.h
@@ -21,7 +21,6 @@
 
 namespace url {
 class Origin;
-struct Parsed;
 }
 
 namespace url_formatter {
@@ -56,30 +55,6 @@
                          gfx::Typesetter typesetter = gfx::Typesetter::DEFAULT);
 #endif  // !defined(OS_ANDROID)
 
-// Similar to ElideUrl, this function shortens a URL to fit a specified width,
-// but does so according to the origin presentation guidance at:
-// https://www.chromium.org/Home/chromium-security/enamel
-//
-// This method differs from ElideUrl in that:
-// - The method accepts a pre-formatted URL string, allowing arbitrary
-//   formatting of the URL.
-// - |parsed| is accepted and modified, allowing regions of the elided URL to be
-//   colored or styled. For example, if a path is completely elided to an
-//   ellipsis, the path component will describe the ellipsis. The input must be
-//   the Parsed structure originally generated during formatting.
-// - When necessary, the host portion is elided from the left, to preserve the
-//   TLD as long as possible. Subdomain is not treated specially.
-// - The path is elided from the right, with no special handling of the last
-//   path element, to avoid potentially long runtimes.
-//
-// This function should be merged with ElideUrl to have a single elision method.
-// See http://crbug.com/772476.
-base::string16 ElideUrlSimple(const GURL& url,
-                              const base::string16& url_string,
-                              const gfx::FontList& font_list,
-                              float available_pixel_width,
-                              url::Parsed* parsed);
-
 enum class SchemeDisplay {
   SHOW,
   OMIT_HTTP_AND_HTTPS,
diff --git a/components/url_formatter/elide_url_unittest.cc b/components/url_formatter/elide_url_unittest.cc
index 09d3746..e2fc441 100644
--- a/components/url_formatter/elide_url_unittest.cc
+++ b/components/url_formatter/elide_url_unittest.cc
@@ -22,11 +22,6 @@
 
 namespace {
 
-enum ElisionMethod {
-  kMethodOriginal,
-  kMethodSimple,
-};
-
 struct Testcase {
   const std::string input;
   const std::string output;
@@ -49,6 +44,8 @@
   const std::vector<UrlComponent> components;
 };
 
+#if !defined(OS_ANDROID)
+
 // Returns the width of a utf8 or utf16 string using the BROWSER typesetter and
 // default UI font, or the provided |font_list|.
 float GetWidth(const std::string& utf8,
@@ -61,64 +58,6 @@
   return gfx::GetStringWidthF(utf16, font_list, gfx::Typesetter::BROWSER);
 }
 
-base::string16 FormatAndElideUrlSimple(const GURL& url,
-                                       const gfx::FontList& font_list,
-                                       float available_pixel_width,
-                                       url::Parsed* parsed) {
-  const base::string16 url_string = url_formatter::FormatUrl(
-      url, url_formatter::kFormatUrlOmitDefaults, net::UnescapeRule::SPACES,
-      parsed, nullptr, nullptr);
-  return url_formatter::ElideUrlSimple(url, url_string, font_list,
-                                       available_pixel_width, parsed);
-}
-
-base::string16 Elide(const GURL& url,
-                     const gfx::FontList& font_list,
-                     float available_width,
-                     ElisionMethod method) {
-  switch (method) {
-    case kMethodSimple: {
-      url::Parsed parsed;
-      return FormatAndElideUrlSimple(url, font_list, available_width, &parsed);
-    }
-#if !defined(OS_ANDROID)
-    case kMethodOriginal:
-      // Test with the BROWSER typesetter, since that's what the only consumer
-      // on Mac wants (and it makes no difference on other platforms).
-      return url_formatter::ElideUrl(url, font_list, available_width,
-                                     gfx::Typesetter::BROWSER);
-#endif
-    default:
-      NOTREACHED();
-      return base::string16();
-  }
-}
-
-url::Component* GetComponent(url::Parsed* parsed,
-                             url::Parsed::ComponentType type) {
-  switch (type) {
-    case url::Parsed::SCHEME:
-      return &parsed->scheme;
-    case url::Parsed::USERNAME:
-      return &parsed->username;
-    case url::Parsed::PASSWORD:
-      return &parsed->password;
-    case url::Parsed::HOST:
-      return &parsed->host;
-    case url::Parsed::PORT:
-      return &parsed->port;
-    case url::Parsed::PATH:
-      return &parsed->path;
-    case url::Parsed::QUERY:
-      return &parsed->query;
-    case url::Parsed::REF:
-      return &parsed->ref;
-    default:
-      NOTREACHED();
-      return nullptr;
-  }
-}
-
 // Verify that one or more URLs passes through an explicit sequence of elided
 // strings as available space progressively decreases. This helps ensure that
 // transitional corner cases are handled properly. To be tolerant of
@@ -135,8 +74,7 @@
 // google.com/in...   <- Must match.
 //
 void RunProgressiveElisionTest(
-    const std::vector<ProgressiveTestcase>& testcases,
-    ElisionMethod method) {
+    const std::vector<ProgressiveTestcase>& testcases) {
   const gfx::FontList font_list;
   for (const auto& testcase : testcases) {
     SCOPED_TRACE("Eliding " + testcase.input);
@@ -159,7 +97,8 @@
     for (size_t i = 0; i < testcase.output.size(); i++) {
       const auto& expected = testcase.output[i];
       base::string16 expected_utf16 = base::UTF8ToUTF16(expected);
-      base::string16 elided = Elide(url, font_list, width, method);
+      base::string16 elided = url_formatter::ElideUrl(url, font_list, width,
+                                                      gfx::Typesetter::BROWSER);
       if (expected_utf16 != elided) {
         if (i > 0 && i < testcase.output.size() - 1 &&
             mismatches < kMaxConsecutiveMismatches) {
@@ -178,8 +117,6 @@
   }
 }
 
-#if !defined(OS_ANDROID)
-
 void RunElisionTest(const std::vector<Testcase>& testcases) {
   const gfx::FontList font_list;
   for (const auto& testcase : testcases) {
@@ -277,7 +214,7 @@
            /* clang-format on */
        }},
   };
-  RunProgressiveElisionTest(progressive_testcases, kMethodOriginal);
+  RunProgressiveElisionTest(progressive_testcases);
 }
 
 // When there is very little space available, the elision code will shorten
@@ -415,7 +352,7 @@
      }},
   };
 
-  RunProgressiveElisionTest(progressive_testcases, kMethodOriginal);
+  RunProgressiveElisionTest(progressive_testcases);
 
   const std::vector<Testcase> testcases = {
       // Eliding file URLs with nothing after the ':' shouldn't crash.
@@ -756,153 +693,4 @@
       << "Explicitly test the url::Origin which takes an empty, invalid URL";
 }
 
-TEST(TextEliderTest, TestSimpleElisionMethod) {
-  const std::string kEllipsisStr(gfx::kEllipsis);
-  const std::vector<ProgressiveTestcase> testcases = {
-      {"https://www.abc.com/def/",
-       {
-           /* clang-format off */
-           {"https://www.abc.com/def/"},
-           {"https://www.abc.com/d" + kEllipsisStr},
-           {"https://www.abc.com/" + kEllipsisStr},
-           {"www.abc.com/def/"},
-           {"www.abc.com/d" + kEllipsisStr},
-           {"www.abc.com/" + kEllipsisStr},
-           {kEllipsisStr + "ww.abc.com/" + kEllipsisStr},
-           {kEllipsisStr + "w.abc.com/" + kEllipsisStr},
-           {kEllipsisStr + ".abc.com/" + kEllipsisStr},
-           {kEllipsisStr + "abc.com/" + kEllipsisStr},
-           {kEllipsisStr + "bc.com/" + kEllipsisStr},
-           {kEllipsisStr + "c.com/" + kEllipsisStr},
-           {kEllipsisStr + ".com/" + kEllipsisStr},
-           {kEllipsisStr + "com/" + kEllipsisStr},
-           {kEllipsisStr + "om/" + kEllipsisStr},
-           {kEllipsisStr + "m/" + kEllipsisStr},
-           {kEllipsisStr + "/" + kEllipsisStr},
-           {kEllipsisStr},
-           {""},
-           /* clang-format on */
-       }},
-      {"file://fs/file",
-       {
-           /* clang-format off */
-           "file://fs/file",
-           "file://fs/fi" + kEllipsisStr,
-           "file://fs/f" + kEllipsisStr,
-           "file://fs/" + kEllipsisStr,
-           "file://fs" + kEllipsisStr,
-           "file://f" + kEllipsisStr,
-           "file://" + kEllipsisStr,
-           "file:/" + kEllipsisStr,
-           "file:" + kEllipsisStr,
-           "file" + kEllipsisStr,
-           "fil" + kEllipsisStr,
-           "fi" + kEllipsisStr,
-           "f" + kEllipsisStr,
-           kEllipsisStr,
-           "",
-           /* clang-format on */
-       }},
-  };
-  RunProgressiveElisionTest(testcases, kMethodSimple);
-}
-
-// Verify that the secure elision method returns URL component data that
-// correctly represents the elided URL.
-void RunElisionParsingTest(const std::vector<ParsingTestcase>& testcases) {
-  const gfx::FontList font_list;
-  for (const auto& testcase : testcases) {
-    SCOPED_TRACE(testcase.input + " to " + testcase.output);
-
-    const GURL url(testcase.input);
-    const float available_width = GetWidth(testcase.output, font_list);
-
-    url::Parsed parsed;
-    auto elided =
-        FormatAndElideUrlSimple(url, font_list, available_width, &parsed);
-    EXPECT_EQ(base::UTF8ToUTF16(testcase.output), elided);
-
-    // Build an expected Parsed struct from the sparse test expectations.
-    url::Parsed expected;
-    for (const auto& expectation : testcase.components) {
-      url::Component* component = GetComponent(&expected, expectation.type);
-      component->begin = expectation.begin;
-      component->len = expectation.len;
-    }
-
-    const std::vector<url::Parsed::ComponentType> kComponents = {
-        url::Parsed::SCHEME, url::Parsed::USERNAME, url::Parsed::PASSWORD,
-        url::Parsed::HOST,   url::Parsed::PORT,     url::Parsed::PATH,
-        url::Parsed::QUERY,  url::Parsed::REF,
-    };
-    for (const auto& type : kComponents) {
-      EXPECT_EQ(GetComponent(&expected, type)->begin,
-                GetComponent(&parsed, type)->begin)
-          << " in component " << type;
-      EXPECT_EQ(GetComponent(&expected, type)->len,
-                GetComponent(&parsed, type)->len)
-          << " in component " << type;
-    }
-  }
-}
-
-// Verify that during elision, the parsed URL components are properly modified.
-TEST(TextEliderTest, TestElisionParsingAdjustments) {
-  const std::string kEllipsisStr(gfx::kEllipsis);
-  const std::vector<ParsingTestcase> testcases = {
-      // HTTPS with path.
-      {"https://www.google.com/intl/en/ads/",
-       "https://www.google.com/intl/en/ads/",
-       {{url::Parsed::ComponentType::SCHEME, 0, 5},
-        {url::Parsed::ComponentType::HOST, 8, 14},
-        {url::Parsed::ComponentType::PATH, 22, 13}}},
-      {"https://www.google.com/intl/en/ads/",
-       "https://www.google.com/intl/en/a" + kEllipsisStr,
-       {{url::Parsed::ComponentType::SCHEME, 0, 5},
-        {url::Parsed::ComponentType::HOST, 8, 14},
-        {url::Parsed::ComponentType::PATH, 22, 11}}},
-      {"https://www.google.com/intl/en/ads/",
-       "https://www.google.com/" + kEllipsisStr,
-       {{url::Parsed::ComponentType::SCHEME, 0, 5},
-        {url::Parsed::ComponentType::HOST, 8, 14},
-        {url::Parsed::ComponentType::PATH, 22, 2}}},
-      {"https://www.google.com/intl/en/ads/",
-       kEllipsisStr + "google.com/" + kEllipsisStr,
-       {{url::Parsed::ComponentType::HOST, 0, 11},
-        {url::Parsed::ComponentType::PATH, 11, 2}}},
-      {"https://www.google.com/intl/en/ads/",
-       kEllipsisStr,
-       {{url::Parsed::ComponentType::PATH, 0, 1}}},
-      // HTTPS with no path.
-      {"https://www.google.com/",
-       "www.google.com",
-       {{url::Parsed::ComponentType::HOST, 0, 14}}},
-      {"https://www.google.com/",
-       kEllipsisStr,
-       {{url::Parsed::ComponentType::HOST, 0, 1}}},
-      // HTTP with no path.
-      {"http://www.google.com/",
-       "www.google.com",
-       {{url::Parsed::ComponentType::HOST, 0, 14}}},
-      // File URLs.
-      {"file:///C:/path1/path2",
-       "file:///C:/path1/" + kEllipsisStr,
-       {{url::Parsed::ComponentType::SCHEME, 0, 4},
-        {url::Parsed::ComponentType::PATH, 7, 11}}},
-      {"file:///C:/path1/path2",
-       "fi" + kEllipsisStr,
-       {{url::Parsed::ComponentType::SCHEME, 0, 3}}},
-      {"file:///C:/path1/path2",
-       kEllipsisStr,
-       {{url::Parsed::ComponentType::SCHEME, 0, 1}}},
-      // RTL URL.
-      {"http://127.0.0.1/ا/http://attack.com‬",
-       kEllipsisStr + "7.0.0.1/" + kEllipsisStr,
-       {{url::Parsed::ComponentType::HOST, 0, 8},
-        {url::Parsed::ComponentType::PATH, 8, 2}}},
-  };
-
-  RunElisionParsingTest(testcases);
-}
-
 }  // namespace
diff --git a/components/viz/common/resources/resource_settings.h b/components/viz/common/resources/resource_settings.h
index 2854205..434f960 100644
--- a/components/viz/common/resources/resource_settings.h
+++ b/components/viz/common/resources/resource_settings.h
@@ -20,7 +20,6 @@
   ResourceSettings& operator=(const ResourceSettings& other);
   ~ResourceSettings();
 
-  size_t texture_id_allocation_chunk_size = 64;
   bool use_gpu_memory_buffer_resources = false;
   bool high_bit_for_testing = false;
   // TODO(riju): Remove after r16 is used without the flag. crbug.com/759456
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 22dac453..bcce3dab 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -78,6 +78,7 @@
   "+third_party/WebKit/public/platform/WebGestureEvent.h",
   "+third_party/WebKit/public/platform/WebInputEvent.h",
   "+third_party/WebKit/public/platform/WebInsecureRequestPolicy.h",
+  "+third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h",
   "+third_party/WebKit/public/platform/WebKeyboardEvent.h",
   "+third_party/WebKit/public/platform/WebMixedContentContextType.h",
   "+third_party/WebKit/public/platform/WebMouseEvent.h",
diff --git a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
index 7933918..ef4abff 100644
--- a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
+++ b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
@@ -19,138 +19,133 @@
 const int CacheStorageBlobToDiskCache::kBufferSize = 1024 * 512;
 
 CacheStorageBlobToDiskCache::CacheStorageBlobToDiskCache()
-    : cache_entry_offset_(0),
-      disk_cache_body_index_(0),
-      buffer_(new net::IOBufferWithSize(kBufferSize)),
-      weak_ptr_factory_(this) {
-}
+    : handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+      client_binding_(this),
+      weak_ptr_factory_(this) {}
 
-CacheStorageBlobToDiskCache::~CacheStorageBlobToDiskCache() {
-  if (blob_request_)
-    request_context_getter_->RemoveObserver(this);
-}
+CacheStorageBlobToDiskCache::~CacheStorageBlobToDiskCache() = default;
 
 void CacheStorageBlobToDiskCache::StreamBlobToCache(
     disk_cache::ScopedEntryPtr entry,
     int disk_cache_body_index,
-    net::URLRequestContextGetter* request_context_getter,
-    std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
+    blink::mojom::BlobPtr blob,
     EntryAndBoolCallback callback) {
   DCHECK(entry);
   DCHECK_LE(0, disk_cache_body_index);
-  DCHECK(blob_data_handle);
-  DCHECK(!blob_request_);
-  DCHECK(request_context_getter);
+  DCHECK(blob);
+  DCHECK(!consumer_handle_.is_valid());
+  DCHECK(!pending_read_);
 
-  if (!request_context_getter->GetURLRequestContext()) {
+  mojo::ScopedDataPipeProducerHandle producer_handle;
+  MojoResult result =
+      CreateDataPipe(nullptr, &producer_handle, &consumer_handle_);
+  if (result != MOJO_RESULT_OK) {
     std::move(callback).Run(std::move(entry), false /* success */);
     return;
   }
 
   disk_cache_body_index_ = disk_cache_body_index;
-
   entry_ = std::move(entry);
   callback_ = std::move(callback);
-  request_context_getter_ = request_context_getter;
 
-  blob_request_ = storage::BlobProtocolHandler::CreateBlobRequest(
-      std::move(blob_data_handle),
-      request_context_getter->GetURLRequestContext(), this);
-  request_context_getter_->AddObserver(this);
-  blob_request_->Start();
-}
+  blink::mojom::BlobReaderClientPtr client;
+  client_binding_.Bind(MakeRequest(&client));
+  blob->ReadAll(std::move(producer_handle), std::move(client));
 
-void CacheStorageBlobToDiskCache::OnResponseStarted(net::URLRequest* request,
-                                                    int net_error) {
-  DCHECK_NE(net::ERR_IO_PENDING, net_error);
-
-  if (net_error != net::OK) {
-    RunCallbackAndRemoveObserver(false);
-    return;
-  }
-
+  handle_watcher_.Watch(
+      consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
+      base::BindRepeating(&CacheStorageBlobToDiskCache::OnDataPipeReadable,
+                          base::Unretained(this)));
   ReadFromBlob();
 }
 
-void CacheStorageBlobToDiskCache::OnReadCompleted(net::URLRequest* request,
-                                                  int bytes_read) {
-  if (bytes_read < 0) {
-    if (bytes_read != net::ERR_IO_PENDING) {
-      RunCallbackAndRemoveObserver(false);
-      return;
-    }
-  }
-
-  if (bytes_read == 0) {
-    RunCallbackAndRemoveObserver(true);
+void CacheStorageBlobToDiskCache::OnComplete(int32_t status,
+                                             uint64_t data_length) {
+  if (status != net::OK) {
+    RunCallback(false /* success */);
     return;
   }
 
-  net::CompletionCallback cache_write_callback =
-      base::AdaptCallbackForRepeating(
-          base::BindOnce(&CacheStorageBlobToDiskCache::DidWriteDataToEntry,
-                         weak_ptr_factory_.GetWeakPtr(), bytes_read));
-
-  int rv = entry_->WriteData(disk_cache_body_index_, cache_entry_offset_,
-                             buffer_.get(), bytes_read, cache_write_callback,
-                             true /* truncate */);
-  if (rv != net::ERR_IO_PENDING)
-    cache_write_callback.Run(rv);
-}
-
-void CacheStorageBlobToDiskCache::OnReceivedRedirect(
-    net::URLRequest* request,
-    const net::RedirectInfo& redirect_info,
-    bool* defer_redirect) {
-  NOTREACHED();
-}
-
-void CacheStorageBlobToDiskCache::OnAuthRequired(
-    net::URLRequest* request,
-    net::AuthChallengeInfo* auth_info) {
-  NOTREACHED();
-}
-void CacheStorageBlobToDiskCache::OnCertificateRequested(
-    net::URLRequest* request,
-    net::SSLCertRequestInfo* cert_request_info) {
-  NOTREACHED();
-}
-void CacheStorageBlobToDiskCache::OnSSLCertificateError(
-    net::URLRequest* request,
-    const net::SSLInfo& ssl_info,
-    bool fatal) {
-  NOTREACHED();
-}
-
-void CacheStorageBlobToDiskCache::OnContextShuttingDown() {
-  DCHECK(blob_request_);
-  RunCallbackAndRemoveObserver(false);
+  // OnComplete might get called before the last data is read from the data
+  // pipe, so make sure to not call the callback until all data is read.
+  received_on_complete_ = true;
+  expected_total_size_ = data_length;
+  if (data_pipe_closed_) {
+    RunCallback(static_cast<uint64_t>(cache_entry_offset_) ==
+                expected_total_size_);
+  }
 }
 
 void CacheStorageBlobToDiskCache::ReadFromBlob() {
-  int bytes_read = blob_request_->Read(buffer_.get(), buffer_->size());
-  if (bytes_read != net::ERR_IO_PENDING)
-    OnReadCompleted(blob_request_.get(), bytes_read);
+  handle_watcher_.ArmOrNotify();
 }
 
 void CacheStorageBlobToDiskCache::DidWriteDataToEntry(int expected_bytes,
                                                       int rv) {
   if (rv != expected_bytes) {
-    RunCallbackAndRemoveObserver(false);
+    RunCallback(false /* success */);
     return;
   }
   if (rv > 0)
     storage::RecordBytesWritten("DiskCache.CacheStorage", rv);
   cache_entry_offset_ += rv;
+
   ReadFromBlob();
 }
 
-void CacheStorageBlobToDiskCache::RunCallbackAndRemoveObserver(bool success) {
-  DCHECK(request_context_getter_);
+void CacheStorageBlobToDiskCache::RunCallback(bool success) {
+  if (callback_)
+    std::move(callback_).Run(std::move(entry_), success);
+}
 
-  request_context_getter_->RemoveObserver(this);
-  blob_request_.reset();
-  std::move(callback_).Run(std::move(entry_), success);
+void CacheStorageBlobToDiskCache::OnDataPipeReadable(MojoResult unused) {
+  // Get the handle_ from a previous read operation if we have one.
+  if (pending_read_) {
+    DCHECK(pending_read_->IsComplete());
+    consumer_handle_ = pending_read_->ReleaseHandle();
+    pending_read_ = nullptr;
+  }
+
+  uint32_t available = 0;
+
+  MojoResult result = network::MojoToNetPendingBuffer::BeginRead(
+      &consumer_handle_, &pending_read_, &available);
+
+  if (result == MOJO_RESULT_SHOULD_WAIT) {
+    handle_watcher_.ArmOrNotify();
+    return;
+  }
+
+  if (result == MOJO_RESULT_FAILED_PRECONDITION) {
+    // Done reading, but only signal success if OnComplete has also been called.
+    data_pipe_closed_ = true;
+    if (received_on_complete_) {
+      RunCallback(static_cast<uint64_t>(cache_entry_offset_) ==
+                  expected_total_size_);
+    }
+    return;
+  }
+
+  if (result != MOJO_RESULT_OK) {
+    RunCallback(false /* success */);
+    return;
+  }
+
+  int bytes_to_read = std::min<int>(kBufferSize, available);
+
+  auto buffer = base::MakeRefCounted<network::MojoToNetIOBuffer>(
+      pending_read_.get(), bytes_to_read);
+
+  net::CompletionCallback cache_write_callback =
+      base::AdaptCallbackForRepeating(
+          base::BindOnce(&CacheStorageBlobToDiskCache::DidWriteDataToEntry,
+                         weak_ptr_factory_.GetWeakPtr(), bytes_to_read));
+
+  int rv = entry_->WriteData(disk_cache_body_index_, cache_entry_offset_,
+                             buffer.get(), bytes_to_read, cache_write_callback,
+                             true /* truncate */);
+  if (rv != net::ERR_IO_PENDING)
+    cache_write_callback.Run(rv);
 }
 
 }  // namespace content
diff --git a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h
index 0a18a97..2af407e 100644
--- a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h
+++ b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.h
@@ -12,25 +12,16 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "net/disk_cache/disk_cache.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context_getter_observer.h"
-
-namespace net {
-class IOBufferWithSize;
-class URLRequestContextGetter;
-}
-
-namespace storage {
-class BlobDataHandle;
-}
+#include "services/network/public/cpp/net_adapters.h"
+#include "third_party/WebKit/common/blob/blob.mojom.h"
 
 namespace content {
 
 // Streams data from a blob and writes it to a given disk_cache::Entry.
 class CONTENT_EXPORT CacheStorageBlobToDiskCache
-    : public net::URLRequest::Delegate,
-      public net::URLRequestContextGetterObserver {
+    : public blink::mojom::BlobReaderClient {
  public:
   using EntryAndBoolCallback =
       base::OnceCallback<void(disk_cache::ScopedEntryPtr, bool)>;
@@ -41,34 +32,18 @@
   CacheStorageBlobToDiskCache();
   ~CacheStorageBlobToDiskCache() override;
 
-  // Writes the body of |blob_data_handle| to |entry| with index
+  // Writes the body of |blob| to |entry| with index
   // |disk_cache_body_index|. |entry| is passed to the callback once complete.
   // Only call this once per instantiation of CacheStorageBlobToDiskCache.
-  void StreamBlobToCache(
-      disk_cache::ScopedEntryPtr entry,
-      int disk_cache_body_index,
-      net::URLRequestContextGetter* request_context_getter,
-      std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
-      EntryAndBoolCallback callback);
+  void StreamBlobToCache(disk_cache::ScopedEntryPtr entry,
+                         int disk_cache_body_index,
+                         blink::mojom::BlobPtr blob,
+                         EntryAndBoolCallback callback);
 
-  // net::URLRequest::Delegate overrides for reading blobs.
-  void OnResponseStarted(net::URLRequest* request, int net_error) override;
-  void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
-  void OnReceivedRedirect(net::URLRequest* request,
-                          const net::RedirectInfo& redirect_info,
-                          bool* defer_redirect) override;
-  void OnAuthRequired(net::URLRequest* request,
-                      net::AuthChallengeInfo* auth_info) override;
-  void OnCertificateRequested(
-      net::URLRequest* request,
-      net::SSLCertRequestInfo* cert_request_info) override;
-  void OnSSLCertificateError(net::URLRequest* request,
-                             const net::SSLInfo& ssl_info,
-                             bool fatal) override;
-
-  // URLRequestContextGetterObserver override for canceling requests just
-  // before the URLRequestContext is destroyed.
-  void OnContextShuttingDown() override;
+  // BlobReaderClient:
+  void OnCalculatedSize(uint64_t total_size,
+                        uint64_t expected_content_size) override {}
+  void OnComplete(int32_t status, uint64_t data_length) override;
 
  protected:
   // Virtual for testing.
@@ -76,18 +51,24 @@
 
  private:
   void DidWriteDataToEntry(int expected_bytes, int rv);
-  void RunCallbackAndRemoveObserver(bool success);
+  void RunCallback(bool success);
 
-  int cache_entry_offset_;
+  void OnDataPipeReadable(MojoResult result);
+
+  int cache_entry_offset_ = 0;
   disk_cache::ScopedEntryPtr entry_;
 
-  // Owned by CacheStorageCache which owns this.
-  net::URLRequestContextGetter* request_context_getter_;
-
-  int disk_cache_body_index_;
-  std::unique_ptr<net::URLRequest> blob_request_;
+  int disk_cache_body_index_ = 0;
   EntryAndBoolCallback callback_;
-  scoped_refptr<net::IOBufferWithSize> buffer_;
+
+  mojo::ScopedDataPipeConsumerHandle consumer_handle_;
+  scoped_refptr<network::MojoToNetPendingBuffer> pending_read_;
+  mojo::SimpleWatcher handle_watcher_;
+  mojo::Binding<BlobReaderClient> client_binding_;
+
+  bool received_on_complete_ = false;
+  uint64_t expected_total_size_ = 0;
+  bool data_pipe_closed_ = false;
 
   base::WeakPtrFactory<CacheStorageBlobToDiskCache> weak_ptr_factory_;
 
diff --git a/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc b/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc
index e6fe660..d513bbbc7e 100644
--- a/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_blob_to_disk_cache_unittest.cc
@@ -26,6 +26,7 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "storage/browser/blob/blob_data_builder.h"
+#include "storage/browser/blob/blob_impl.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/blob/blob_url_request_job_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -166,12 +167,13 @@
   }
 
   bool Stream() {
-    std::unique_ptr<storage::BlobDataHandle> new_data_handle(
-        blob_storage_context_->GetBlobDataFromUUID(blob_handle_->uuid()));
+    blink::mojom::BlobPtr blob_ptr;
+    storage::BlobImpl::Create(
+        std::make_unique<storage::BlobDataHandle>(*blob_handle_),
+        MakeRequest(&blob_ptr));
 
     cache_storage_blob_to_disk_cache_->StreamBlobToCache(
-        std::move(disk_cache_entry_), kCacheEntryIndex,
-        url_request_context_getter_.get(), std::move(new_data_handle),
+        std::move(disk_cache_entry_), kCacheEntryIndex, std::move(blob_ptr),
         base::BindOnce(&CacheStorageBlobToDiskCacheTest::StreamCallback,
                        base::Unretained(this)));
 
@@ -245,29 +247,6 @@
   EXPECT_FALSE(callback_called_);
 }
 
-TEST_F(CacheStorageBlobToDiskCacheTest,
-       ShutdownGetterMidStreamDeletesURLRequest) {
-  cache_storage_blob_to_disk_cache_->set_delay_blob_reads(true);
-
-  // The operation should stall while reading from the blob.
-  EXPECT_FALSE(Stream());
-
-  // Shutting down the URLRequestContext mid-stream should result in a canceled
-  // operation.
-  cache_storage_blob_to_disk_cache_->OnContextShuttingDown();
-  url_request_context_getter_->GetURLRequestContext()->AssertNoURLRequests();
-
-  browser_context_.reset();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(callback_called_);
-  EXPECT_FALSE(callback_success_);
-}
-
-TEST_F(CacheStorageBlobToDiskCacheTest, StreamWithNullContextRequest) {
-  url_request_context_getter_ = new NullURLRequestContextGetter();
-  EXPECT_FALSE(Stream());
-}
-
 }  // namespace
 
 }  // namespace content
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index 5b09c8f..d333b66 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -344,23 +344,22 @@
 
 // The state needed to pass between CacheStorageCache::Put callbacks.
 struct CacheStorageCache::PutContext {
-  PutContext(
-      std::unique_ptr<ServiceWorkerFetchRequest> request,
-      std::unique_ptr<ServiceWorkerResponse> response,
-      std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
-      std::unique_ptr<storage::BlobDataHandle> side_data_blob_data_handle,
-      CacheStorageCache::ErrorCallback callback)
+  PutContext(std::unique_ptr<ServiceWorkerFetchRequest> request,
+             std::unique_ptr<ServiceWorkerResponse> response,
+             blink::mojom::BlobPtr blob,
+             blink::mojom::BlobPtr side_data_blob,
+             CacheStorageCache::ErrorCallback callback)
       : request(std::move(request)),
         response(std::move(response)),
-        blob_data_handle(std::move(blob_data_handle)),
-        side_data_blob_data_handle(std::move(side_data_blob_data_handle)),
+        blob(std::move(blob)),
+        side_data_blob(std::move(side_data_blob)),
         callback(std::move(callback)) {}
 
   // Input parameters to the Put function.
   std::unique_ptr<ServiceWorkerFetchRequest> request;
   std::unique_ptr<ServiceWorkerResponse> response;
-  std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
-  std::unique_ptr<storage::BlobDataHandle> side_data_blob_data_handle;
+  blink::mojom::BlobPtr blob;
+  blink::mojom::BlobPtr side_data_blob;
 
   CacheStorageCache::ErrorCallback callback;
   disk_cache::ScopedEntryPtr cache_entry;
@@ -1238,45 +1237,23 @@
 
   std::unique_ptr<ServiceWorkerResponse> response =
       std::make_unique<ServiceWorkerResponse>(operation.response);
-  std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
-  std::unique_ptr<storage::BlobDataHandle> side_data_blob_data_handle;
+  blink::mojom::BlobPtr blob;
+  blink::mojom::BlobPtr side_data_blob;
 
-  if (!response->blob_uuid.empty()) {
-    DCHECK(response->blob);
-    if (!blob_storage_context_) {
-      std::move(callback).Run(CacheStorageError::kErrorStorage);
-      return;
-    }
-    blob_data_handle =
-        blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid);
-    if (!blob_data_handle) {
-      std::move(callback).Run(CacheStorageError::kErrorStorage);
-      return;
-    }
-  }
-  if (!response->side_data_blob_uuid.empty()) {
-    DCHECK(response->side_data_blob);
-    if (!blob_storage_context_) {
-      std::move(callback).Run(CacheStorageError::kErrorStorage);
-      return;
-    }
-    side_data_blob_data_handle = blob_storage_context_->GetBlobDataFromUUID(
-        response->side_data_blob_uuid);
-    if (!side_data_blob_data_handle) {
-      std::move(callback).Run(CacheStorageError::kErrorStorage);
-      return;
-    }
-  }
+  if (response->blob)
+    blob = response->blob->Clone();
+  if (response->side_data_blob)
+    side_data_blob = response->side_data_blob->Clone();
 
   UMA_HISTOGRAM_ENUMERATION(
       "ServiceWorkerCache.Cache.AllWritesResponseType",
       operation.response.response_type,
       static_cast<int>(network::mojom::FetchResponseType::kLast) + 1);
 
-  std::unique_ptr<PutContext> put_context(new PutContext(
-      std::move(request), std::move(response), std::move(blob_data_handle),
-      std::move(side_data_blob_data_handle),
-      scheduler_->WrapCallbackToRunNext(std::move(callback))));
+  auto put_context = std::make_unique<PutContext>(
+      std::move(request), std::move(response), std::move(blob),
+      std::move(side_data_blob),
+      scheduler_->WrapCallbackToRunNext(std::move(callback)));
 
   scheduler_->ScheduleOperation(base::BindOnce(
       &CacheStorageCache::PutImpl, weak_ptr_factory_.GetWeakPtr(),
@@ -1447,11 +1424,10 @@
   DCHECK(disk_cache_body_index == INDEX_RESPONSE_BODY ||
          disk_cache_body_index == INDEX_SIDE_DATA);
 
-  std::unique_ptr<storage::BlobDataHandle> blob_data_handle =
-      disk_cache_body_index == INDEX_RESPONSE_BODY
-          ? std::move(put_context->blob_data_handle)
-          : std::move(put_context->side_data_blob_data_handle);
-  DCHECK(blob_data_handle);
+  blink::mojom::BlobPtr blob = disk_cache_body_index == INDEX_RESPONSE_BODY
+                                   ? std::move(put_context->blob)
+                                   : std::move(put_context->side_data_blob);
+  DCHECK(blob);
 
   disk_cache::ScopedEntryPtr entry(std::move(put_context->cache_entry));
   put_context->cache_entry = nullptr;
@@ -1462,8 +1438,7 @@
       active_blob_to_disk_cache_writers_.Add(std::move(blob_to_cache));
 
   blob_to_cache_raw->StreamBlobToCache(
-      std::move(entry), disk_cache_body_index, request_context_getter_.get(),
-      std::move(blob_data_handle),
+      std::move(entry), disk_cache_body_index, std::move(blob),
       base::BindOnce(&CacheStorageCache::PutDidWriteBlobToCache,
                      weak_ptr_factory_.GetWeakPtr(),
                      base::Passed(std::move(put_context)), blob_to_cache_key));
@@ -1485,7 +1460,7 @@
     return;
   }
 
-  if (put_context->side_data_blob_data_handle) {
+  if (put_context->side_data_blob) {
     PutWriteBlobToCache(std::move(put_context), INDEX_SIDE_DATA);
     return;
   }
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index 0e77070..0098ca6 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -110,6 +110,13 @@
       frame_proxy_in_parent_renderer_->GetRoutingID(), surface_info));
 }
 
+void CrossProcessFrameConnector::SendIntrinsicSizingInfoToParent(
+    const blink::WebIntrinsicSizingInfo& sizing_info) {
+  frame_proxy_in_parent_renderer_->Send(
+      new FrameMsg_IntrinsicSizingInfoOfChildChanged(
+          frame_proxy_in_parent_renderer_->GetRoutingID(), sizing_info));
+}
+
 void CrossProcessFrameConnector::UpdateCursor(const WebCursor& cursor) {
   RenderWidgetHostViewBase* root_view = GetRootRenderWidgetHostView();
   // UpdateCursor messages are ignored if the root view does not support
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index b6108dd..0ff90f0 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -77,6 +77,9 @@
   RenderWidgetHostViewBase* GetRootRenderWidgetHostView() override;
   void RenderProcessGone() override;
   void SetChildFrameSurface(const viz::SurfaceInfo& surface_info) override;
+  void SendIntrinsicSizingInfoToParent(
+      const blink::WebIntrinsicSizingInfo&) override;
+
   void UpdateCursor(const WebCursor& cursor) override;
   gfx::PointF TransformPointToRootCoordSpace(
       const gfx::PointF& point,
diff --git a/content/browser/gpu/DEPS b/content/browser/gpu/DEPS
index 4a508e0..24cf9495 100644
--- a/content/browser/gpu/DEPS
+++ b/content/browser/gpu/DEPS
@@ -7,9 +7,4 @@
   "gpu_process_host\.cc": [
     "+ui/ozone/public",
   ],
-  "in_process_gpu_thread_browsertests\.cc": [
-    # Let's move in_process_gpu_thread* to
-    # content/browser/gpu to avoid this rule.
-    "+content/gpu/in_process_gpu_thread.h"
-  ],
 }
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index df3efc8..a7b3ef7 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -150,11 +150,7 @@
         base::BindOnce(
             &BrowserGpuChannelHostFactory::EstablishRequest::RestartTimeout,
             this));
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(
-            &BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
-            this));
+    EstablishOnIO();
     return;
   }
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 029fc58f0..cb33385d 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -481,8 +481,6 @@
 
 GpuProcessHost::~GpuProcessHost() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (in_process_gpu_thread_)
-    DCHECK(process_);
 
   SendOutstandingReplies(EstablishChannelStatus::GPU_HOST_INVALID);
 
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 3b7e23d..5efa679 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -268,6 +268,8 @@
   bool swiftshader_rendering_;
   GpuProcessKind kind_;
 
+  std::unique_ptr<base::Thread> in_process_gpu_thread_;
+
   // Whether we actually launched a GPU process.
   bool process_launched_;
 
@@ -287,12 +289,7 @@
   static bool crashed_before_;
   static int swiftshader_crash_count_;
 
-  // Here the bottom-up destruction order matters:
-  // The GPU thread depends on its host so stop the host last.
-  // Otherwise, under rare timings when the thread is still in Init(),
-  // it could crash as it fails to find a message pipe to the host.
   std::unique_ptr<BrowserChildProcessHostImpl> process_;
-  std::unique_ptr<base::Thread> in_process_gpu_thread_;
 
   // Track the URLs of the pages which have live offscreen contexts,
   // assumed to be associated with untrusted content such as WebGL.
diff --git a/content/browser/gpu/in_process_gpu_thread_browsertests.cc b/content/browser/gpu/in_process_gpu_thread_browsertests.cc
deleted file mode 100644
index 029288b..0000000
--- a/content/browser/gpu/in_process_gpu_thread_browsertests.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/command_line.h"
-#include "base/run_loop.h"
-#include "content/browser/browser_main_loop.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/gpu/in_process_gpu_thread.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/test/content_browser_test.h"
-
-namespace {
-
-using content::InProcessGpuThread;
-using content::GpuProcessHost;
-
-class InProcessGpuTest : public content::ContentBrowserTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitch(switches::kInProcessGPU);
-    content::ContentBrowserTest::SetUpCommandLine(command_line);
-  }
-};
-
-void CreateGpuProcessHost() {
-  GpuProcessHost::Get();
-}
-
-void WaitUntilGpuProcessHostIsCreated() {
-  base::RunLoop run_loop;
-  content::BrowserThread::PostTaskAndReply(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&CreateGpuProcessHost), run_loop.QuitClosure());
-  run_loop.Run();
-}
-
-// Reproduces the race that could give crbug.com/799002's "hang until OOM" at
-// shutdown.
-IN_PROC_BROWSER_TEST_F(InProcessGpuTest, NoHangAtQuickLaunchAndShutDown) {
-  // ... then exit the browser.
-}
-
-// Tests crbug.com/799002 but with another timing.
-IN_PROC_BROWSER_TEST_F(InProcessGpuTest, NoCrashAtShutdown) {
-  WaitUntilGpuProcessHostIsCreated();
-  // ... then exit the browser.
-}
-
-}  // namespace
diff --git a/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc b/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc
index dea4d9a5..e3d3556 100644
--- a/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc
+++ b/content/browser/indexed_db/indexed_db_tombstone_sweeper.cc
@@ -132,58 +132,66 @@
   DCHECK(stop_reason || status);
   DCHECK(!stop_reason || !status);
 
-  std::string uma_prefix = kUmaPrefix;
+  // Metadata error statistics are recorded in the PreCloseTaskList.
+  if (stop_reason && stop_reason == StopReason::METADATA_ERROR)
+    return;
+
+  std::string uma_count_label = kUmaPrefix;
+  std::string uma_size_label = kUmaPrefix;
+
+  switch (mode_) {
+    case Mode::STATISTICS:
+      uma_count_label.append("NumTombstones.");
+      uma_size_label.append("TombstonesSize.");
+      break;
+    case Mode::DELETION:
+      uma_count_label.append("NumDeletedTombstones.");
+      uma_size_label.append("DeletedTombstonesSize.");
+      break;
+    default:
+      NOTREACHED();
+  }
 
   if (stop_reason) {
     switch (stop_reason.value()) {
       case StopReason::NEW_CONNECTION:
-        uma_prefix.append("ConnectionOpened.");
+        uma_count_label.append("ConnectionOpened");
+        uma_size_label.append("ConnectionOpened");
         break;
       case StopReason::TIMEOUT:
-        uma_prefix.append("TimeoutReached.");
+        uma_count_label.append("TimeoutReached");
+        uma_size_label.append("TimeoutReached");
         break;
       case StopReason::METADATA_ERROR:
-        // Metadata error statistics are recorded in the PreCloseTaskList.
-        return;
+        NOTREACHED();
+        break;
     }
   } else if (status) {
     switch (status.value()) {
       case Status::DONE_REACHED_MAX:
-        uma_prefix.append("MaxIterations.");
+        uma_count_label.append("MaxIterations");
+        uma_size_label.append("MaxIterations");
         break;
       case Status::DONE_ERROR:
-        LOCAL_HISTOGRAM_ENUMERATION(
+        UMA_HISTOGRAM_ENUMERATION(
             "WebCore.IndexedDB.TombstoneSweeper.SweepError",
             leveldb_env::GetLevelDBStatusUMAValue(leveldb_error),
             leveldb_env::LEVELDB_STATUS_MAX);
-        uma_prefix.append("SweepError.");
+        uma_count_label.append("SweepError");
+        uma_size_label.append("SweepError");
         break;
       case Status::DONE_COMPLETE:
-        uma_prefix.append("Complete.");
+        uma_count_label.append("Complete");
+        uma_size_label.append("Complete");
         break;
       case Status::SWEEPING:
         NOTREACHED();
+        break;
     }
   } else {
     NOTREACHED();
   }
 
-  std::string uma_count_label = uma_prefix;
-  std::string uma_size_label = std::move(uma_prefix);
-
-  switch (mode_) {
-    case Mode::STATISTICS:
-      uma_count_label.append("NumTombstones");
-      uma_size_label.append("TombstonesSize");
-      break;
-    case Mode::DELETION:
-      uma_count_label.append("NumDeletedTombstones");
-      uma_size_label.append("DeletedTombstonesSize");
-      break;
-    default:
-      NOTREACHED();
-  }
-
   // Some stats are only recorded for completed runs.
   if (status && status.value() == Status::DONE_COMPLETE) {
     if (start_time_) {
@@ -193,19 +201,19 @@
           start_time_.value();
       switch (mode_) {
         case Mode::STATISTICS:
-          LOCAL_HISTOGRAM_TIMES(
-              "WebCore.IndexedDB.TombstoneSweeper.Complete.StatsTotalTime",
+          UMA_HISTOGRAM_TIMES(
+              "WebCore.IndexedDB.TombstoneSweeper.StatsTotalTime.Complete",
               total_time);
           break;
         case Mode::DELETION:
-          LOCAL_HISTOGRAM_TIMES(
-              "WebCore.IndexedDB.TombstoneSweeper.Complete.DeletionTotalTime",
+          UMA_HISTOGRAM_TIMES(
+              "WebCore.IndexedDB.TombstoneSweeper.DeletionTotalTime.Complete",
               total_time);
           if (metrics_.seen_tombstones > 0) {
             // Only record deletion time if we do a deletion.
-            LOCAL_HISTOGRAM_TIMES(
-                "WebCore.IndexedDB.TombstoneSweeper.Complete."
-                "DeletionCommitTime",
+            UMA_HISTOGRAM_TIMES(
+                "WebCore.IndexedDB.TombstoneSweeper.DeletionCommitTime."
+                "Complete",
                 total_deletion_time_);
           }
           break;
@@ -216,9 +224,12 @@
   }
 
   base::HistogramBase* count_histogram = base::Histogram::FactoryGet(
-      uma_count_label, 1, 1000000, 50, base::HistogramBase::kNoFlags);
+      uma_count_label, 1, 1'000'000, 50,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  // Range of 1 byte to 100 MB.
   base::HistogramBase* size_histogram = base::Histogram::FactoryGet(
-      uma_size_label, 1, 1000000, 50, base::HistogramBase::kNoFlags);
+      uma_size_label, 1, 100'000'000, 50,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
 
   if (count_histogram)
     count_histogram->Add(metrics_.seen_tombstones);
@@ -228,7 +239,7 @@
   // We put our max at 20 instead of 100 to reduce the number of buckets.
   if (total_indices_ > 0) {
     const static int kIndexPercentageBucketCount = 20;
-    LOCAL_HISTOGRAM_ENUMERATION(
+    UMA_HISTOGRAM_ENUMERATION(
         "WebCore.IndexedDB.TombstoneSweeper.IndexScanPercent",
         indices_scanned_ * kIndexPercentageBucketCount / total_indices_,
         kIndexPercentageBucketCount + 1);
@@ -246,7 +257,7 @@
   has_writes_ = false;
 
   if (!status.ok()) {
-    LOCAL_HISTOGRAM_ENUMERATION(
+    UMA_HISTOGRAM_ENUMERATION(
         "WebCore.IndexedDB.TombstoneSweeper.DeletionWriteError",
         leveldb_env::GetLevelDBStatusUMAValue(status),
         leveldb_env::LEVELDB_STATUS_MAX);
diff --git a/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc b/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc
index 0376bb7..86be8f46 100644
--- a/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc
@@ -159,19 +159,18 @@
     std::string category = reached_max ? "MaxIterations" : "Complete";
     if (GetParam() == Mode::STATISTICS) {
       histogram_tester_.ExpectUniqueSample(
-          "WebCore.IndexedDB.TombstoneSweeper." + category + ".NumTombstones",
-          num, 1);
+          "WebCore.IndexedDB.TombstoneSweeper.NumTombstones." + category, num,
+          1);
       histogram_tester_.ExpectUniqueSample(
-          "WebCore.IndexedDB.TombstoneSweeper." + category + ".TombstonesSize",
-          size, 1);
+          "WebCore.IndexedDB.TombstoneSweeper.TombstonesSize." + category, size,
+          1);
     } else {
       histogram_tester_.ExpectUniqueSample(
-          "WebCore.IndexedDB.TombstoneSweeper." + category +
-              ".NumDeletedTombstones",
+          "WebCore.IndexedDB.TombstoneSweeper.NumDeletedTombstones." + category,
           num, 1);
       histogram_tester_.ExpectUniqueSample(
-          "WebCore.IndexedDB.TombstoneSweeper." + category +
-              ".DeletedTombstonesSize",
+          "WebCore.IndexedDB.TombstoneSweeper.DeletedTombstonesSize." +
+              category,
           size, 1);
     }
   }
@@ -179,11 +178,11 @@
   void ExpectTaskTimeRecorded() {
     if (GetParam() == Mode::STATISTICS) {
       histogram_tester_.ExpectTimeBucketCount(
-          "WebCore.IndexedDB.TombstoneSweeper.Complete.StatsTotalTime",
+          "WebCore.IndexedDB.TombstoneSweeper.StatsTotalTime.Complete",
           base::TimeDelta::FromSeconds(1), 1);
     } else {
       histogram_tester_.ExpectTimeBucketCount(
-          "WebCore.IndexedDB.TombstoneSweeper.Complete.DeletionTotalTime",
+          "WebCore.IndexedDB.TombstoneSweeper.DeletionTotalTime.Complete",
           base::TimeDelta::FromSeconds(1), 1);
     }
   }
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc
index 2a5f977..e9a3226 100644
--- a/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -529,8 +529,8 @@
   if (request()->initiator().has_value())
     initiator = request()->initiator().value();
 
-  // Don't block same-site documents.
-  if (CrossSiteDocumentClassifier::IsSameSite(initiator, url))
+  // Don't block same-origin documents.
+  if (CrossSiteDocumentClassifier::IsSameOrigin(initiator, url))
     return false;
 
   // Only block documents from HTTP(S) schemes.
diff --git a/content/browser/loader/cross_site_document_resource_handler_unittest.cc b/content/browser/loader/cross_site_document_resource_handler_unittest.cc
index aac0745a..1855409 100644
--- a/content/browser/loader/cross_site_document_resource_handler_unittest.cc
+++ b/content/browser/loader/cross_site_document_resource_handler_unittest.cc
@@ -204,11 +204,11 @@
         -1,                                         // verdict_packet
     },
     {
-        "Allowed: Same-site JSON with parser breaker and HTML mime type",
+        "Allowed: Same-origin JSON with parser breaker and HTML mime type",
         __LINE__,
         "http://www.a.com/resource.html",       // target_url
         RESOURCE_TYPE_XHR,                      // resource_type
-        "http://a.com/",                        // initiator_origin
+        "http://www.a.com/",                    // initiator_origin
         OriginHeader::kOmit,                    // cors_request
         "text/html",                            // response_mime_type
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
@@ -219,9 +219,9 @@
         -1,  // verdict_packet
     },
     {
-        "Allowed: Same-site JSON with parser breaker and JSON mime type",
+        "Allowed: Same-origin JSON with parser breaker and JSON mime type",
         __LINE__,
-        "http://a.com/resource.html",           // target_url
+        "http://www.a.com/resource.html",       // target_url
         RESOURCE_TYPE_XHR,                      // resource_type
         "http://www.a.com/",                    // initiator_origin
         OriginHeader::kOmit,                    // cors_request
@@ -614,6 +614,38 @@
         Verdict::kBlock,                        // verdict
         -1,                                     // verdict_packet
     },
+    {
+        "Blocked: Cross-origin, same-site XHR to nosniff HTML without CORS",
+        __LINE__,
+        "https://foo.site.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                          // resource_type
+        "https://bar.site.com/",                    // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        true,                                       // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kBlock,                            // verdict
+        -1,                                         // verdict_packet
+    },
+    {
+        "Blocked: Cross-origin XHR to HTML with wrong CORS (okay same-site)",
+        // Note that initiator_origin is cross-origin, but same-site in relation
+        // to the CORS response.
+        __LINE__,
+        "http://www.b.com/resource.html",    // target_url
+        RESOURCE_TYPE_XHR,                   // resource_type
+        "http://foo.example.com/",           // initiator_origin
+        OriginHeader::kInclude,              // cors_request
+        "text/html",                         // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,  // canonical_mime_type
+        false,                               // include_no_sniff_header
+        AccessControlAllowOriginHeader::kAllowExampleDotCom,  // cors_response
+        {"<hTmL><head>this should sniff as HTML"},            // packets
+        Verdict::kBlock,                                      // verdict
+        0,                                                    // verdict_packet
+    },
 
     {
         // This scenario is unusual, since there's no difference between
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index a388a96..ecab3580 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -190,13 +190,7 @@
 };
 
 // Verifies that in-process network service works.
-// http://crbug.com/804204: failed on several dbg builders.
-#if !defined(NDEBUG)
-#define MAYBE_Basic DISABLED_Basic
-#else
-#define MAYBE_Basic Basic
-#endif
-IN_PROC_BROWSER_TEST_F(NetworkServiceInProcessBrowserTest, MAYBE_Basic) {
+IN_PROC_BROWSER_TEST_F(NetworkServiceInProcessBrowserTest, Basic) {
   GURL test_url = embedded_test_server()->GetURL("foo.com", "/echo");
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 5adf3d1..848147aa 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -557,7 +557,6 @@
   }
   if (root_window_->GetLayer()) {
     subroot_layer_ = root_window_->GetLayer();
-    subroot_layer_->RemoveAllChildren();
     subroot_layer_->AddChild(root_layer);
   }
 }
diff --git a/content/browser/renderer_host/frame_connector_delegate.h b/content/browser/renderer_host/frame_connector_delegate.h
index eeb8fa8..95034aa 100644
--- a/content/browser/renderer_host/frame_connector_delegate.h
+++ b/content/browser/renderer_host/frame_connector_delegate.h
@@ -18,6 +18,7 @@
 
 namespace blink {
 class WebGestureEvent;
+struct WebIntrinsicSizingInfo;
 }
 
 namespace viz {
@@ -65,6 +66,11 @@
   // frames.
   virtual void SetChildFrameSurface(const viz::SurfaceInfo& surface_info) {}
 
+  // Sends the given intrinsic sizing information from a sub-frame to
+  // its corresponding remote frame in the parent frame's renderer.
+  virtual void SendIntrinsicSizingInfoToParent(
+      const blink::WebIntrinsicSizingInfo&) {}
+
   // Return the rect in DIP that the RenderWidgetHostViewChildFrame's content
   // will render into.
   const gfx::Rect& frame_rect_in_dip() { return frame_rect_in_dip_; }
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl.h b/content/browser/renderer_host/input/legacy_input_router_impl.h
index 239f363..b762f814 100644
--- a/content/browser/renderer_host/input/legacy_input_router_impl.h
+++ b/content/browser/renderer_host/input/legacy_input_router_impl.h
@@ -91,9 +91,9 @@
 
  private:
   friend class LegacyInputRouterImplTest;
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest,
                            SubframeTouchEventRouting);
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest,
                            MainframeTouchEventRouting);
 
   // Keeps track of last position of touch points and sets MovementXY for them.
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h
index 6799fbb..d96a297 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.h
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -267,13 +267,13 @@
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostInputEventRouter);
   friend class RenderWidgetHostInputEventRouterTest;
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest,
                            InputEventRouterGestureTargetMapTest);
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest,
                            InputEventRouterGesturePreventDefaultTargetMapTest);
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest,
                            InputEventRouterTouchpadGestureTargetTest);
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessMouseWheelBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessMouseWheelHitTestBrowserTest,
                            InputEventRouterWheelTargetTest);
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessMacBrowserTest,
                            InputEventRouterTouchpadGestureTargetTest);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 1bdeff85a..a106d1bf 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -405,7 +405,7 @@
                            DeviceScaleFactorChanges);
   FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraSurfaceSynchronizationTest,
                            HideThenShow);
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, PopupMenuTest);
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessHitTestBrowserTest, PopupMenuTest);
   FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest,
                            WebContentsViewReparent);
 
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index ad65cd9..bec7893b 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -187,6 +187,24 @@
 }
 #endif  // defined(USE_AURA)
 
+bool RenderWidgetHostViewChildFrame::OnMessageReceived(
+    const IPC::Message& msg) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewChildFrame, msg)
+    IPC_MESSAGE_HANDLER(ViewHostMsg_IntrinsicSizingInfoChanged,
+                        OnIntrinsicSizingInfoChanged)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+
+  return handled;
+}
+
+void RenderWidgetHostViewChildFrame::OnIntrinsicSizingInfoChanged(
+    blink::WebIntrinsicSizingInfo sizing_info) {
+  if (frame_connector_)
+    frame_connector_->SendIntrinsicSizingInfoToParent(sizing_info);
+}
+
 void RenderWidgetHostViewChildFrame::OnManagerWillDestroy(
     TouchSelectionControllerClientManager* manager) {
   // We get the manager via the observer callback instead of through the
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index 2ca8542..9cc3bda2 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -28,6 +28,7 @@
 #include "content/public/browser/touch_selection_controller_client_manager.h"
 #include "content/public/common/input_event_ack_state.h"
 #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
+#include "third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -68,6 +69,10 @@
   void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id);
 #endif  // defined(USE_AURA)
 
+  bool OnMessageReceived(const IPC::Message& msg) override;
+
+  void OnIntrinsicSizingInfoChanged(blink::WebIntrinsicSizingInfo);
+
   // This functions registers single-use callbacks that want to be notified when
   // the next frame is swapped. The callback is triggered by
   // ProcessCompositorFrame, which is the appropriate time to request pixel
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 2c89ef1..3746746 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -31,7 +31,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/bind_test_util.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -49,9 +48,7 @@
 #include "content/browser/frame_host/render_frame_proxy_host.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/renderer_host/cursor_manager.h"
 #include "content/browser/renderer_host/input/input_router.h"
-#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
@@ -59,7 +56,6 @@
 #include "content/browser/url_loader_factory_getter.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
-#include "content/common/input/synthetic_tap_gesture_params.h"
 #include "content/common/input_messages.h"
 #include "content/common/renderer.mojom.h"
 #include "content/common/view_messages.h"
@@ -85,7 +81,6 @@
 #include "content/shell/browser/shell.h"
 #include "content/shell/common/shell_switches.h"
 #include "content/test/content_browser_test_utils_internal.h"
-#include "content/test/mock_overscroll_observer.h"
 #include "ipc/constants.mojom.h"
 #include "ipc/ipc_security_test_util.h"
 #include "media/base/media_switches.h"
@@ -113,10 +108,7 @@
 #include "ui/native_theme/native_theme_features.h"
 
 #if defined(USE_AURA)
-#include "content/browser/renderer_host/overscroll_controller.h"
 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
-#include "content/public/browser/overscroll_configuration.h"
-#include "content/test/mock_overscroll_controller_delegate_aura.h"
 #endif
 
 #if defined(OS_MACOSX)
@@ -213,69 +205,6 @@
   return origin;
 }
 
-class RenderWidgetHostMouseEventMonitor {
- public:
-  explicit RenderWidgetHostMouseEventMonitor(RenderWidgetHost* host)
-      : host_(host), event_received_(false) {
-    mouse_callback_ =
-        base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
-                   base::Unretained(this));
-    host_->AddMouseEventCallback(mouse_callback_);
-  }
-  ~RenderWidgetHostMouseEventMonitor() {
-    host_->RemoveMouseEventCallback(mouse_callback_);
-  }
-  bool EventWasReceived() const { return event_received_; }
-  void ResetEventReceived() { event_received_ = false; }
-  const blink::WebMouseEvent& event() const { return event_; }
-
- private:
-  bool MouseEventCallback(const blink::WebMouseEvent& event) {
-    event_received_ = true;
-    event_ = event;
-    return false;
-  }
-  RenderWidgetHost::MouseEventCallback mouse_callback_;
-  RenderWidgetHost* host_;
-  bool event_received_;
-  blink::WebMouseEvent event_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostMouseEventMonitor);
-};
-
-class TestInputEventObserver : public RenderWidgetHost::InputEventObserver {
- public:
-  explicit TestInputEventObserver(RenderWidgetHost* host) : host_(host) {
-    host_->AddInputEventObserver(this);
-  }
-
-  ~TestInputEventObserver() override { host_->RemoveInputEventObserver(this); }
-
-  bool EventWasReceived() const { return !events_received_.empty(); }
-  void ResetEventsReceived() { events_received_.clear(); }
-  blink::WebInputEvent::Type EventType() const {
-    DCHECK(EventWasReceived());
-    return events_received_.front();
-  }
-  const std::vector<blink::WebInputEvent::Type>& events_received() {
-    return events_received_;
-  }
-
-  const blink::WebInputEvent& event() const { return *event_; }
-
-  void OnInputEvent(const blink::WebInputEvent& event) override {
-    events_received_.push_back(event.GetType());
-    event_ = ui::WebInputEventTraits::Clone(event);
-  };
-
- private:
-  RenderWidgetHost* host_;
-  std::vector<blink::WebInputEvent::Type> events_received_;
-  ui::WebScopedInputEvent event_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestInputEventObserver);
-};
-
 double GetFrameDeviceScaleFactor(const ToRenderFrameHost& adapter) {
   double device_scale_factor;
   const char kGetFrameDeviceScaleFactor[] =
@@ -295,248 +224,6 @@
       .page_scale_factor;
 }
 
-void RouteMouseEventAndWaitUntilDispatch(
-    RenderWidgetHostInputEventRouter* router,
-    RenderWidgetHostViewBase* root_view,
-    RenderWidgetHostViewBase* expected_target,
-    blink::WebMouseEvent* event) {
-  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
-                             event->GetType());
-  router->RouteMouseEvent(root_view, event, ui::LatencyInfo());
-  waiter.Wait();
-}
-
-void DispatchMouseEventAndWaitUntilDispatch(
-    WebContentsImpl* web_contents,
-    RenderWidgetHostViewBase* location_view,
-    const gfx::PointF& location,
-    RenderWidgetHostViewBase* expected_target,
-    const gfx::PointF& expected_location) {
-  auto* router = web_contents->GetInputEventRouter();
-
-  RenderWidgetHostMouseEventMonitor monitor(
-      expected_target->GetRenderWidgetHost());
-  gfx::PointF root_location =
-      location_view->TransformPointToRootCoordSpaceF(location);
-  blink::WebMouseEvent down_event(blink::WebInputEvent::kMouseDown,
-                                  blink::WebInputEvent::kNoModifiers,
-                                  blink::WebInputEvent::kTimeStampForTesting);
-  down_event.button = blink::WebPointerProperties::Button::kLeft;
-  down_event.SetPositionInWidget(root_location.x(), root_location.y());
-  down_event.click_count = 1;
-  FrameTreeNode* root = web_contents->GetFrameTree()->root();
-  auto* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RouteMouseEventAndWaitUntilDispatch(router, root_view, expected_target,
-                                      &down_event);
-  EXPECT_TRUE(monitor.EventWasReceived());
-  EXPECT_NEAR(expected_location.x(), monitor.event().PositionInWidget().x, 2);
-  EXPECT_NEAR(expected_location.y(), monitor.event().PositionInWidget().y, 2);
-}
-
-// Helper function that performs a surface hittest.
-void SurfaceHitTestTestHelper(
-    Shell* shell,
-    net::test_server::EmbeddedTestServer* embedded_test_server) {
-  GURL main_url(embedded_test_server->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell, main_url));
-  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
-                                         gfx::PointF(5, 5), rwhv_child,
-                                         gfx::PointF(5, 5));
-
-  DispatchMouseEventAndWaitUntilDispatch(
-      web_contents, rwhv_root, gfx::PointF(2, 2), rwhv_root, gfx::PointF(2, 2));
-}
-
-void OverlapSurfaceHitTestHelper(
-    Shell* shell,
-    net::test_server::EmbeddedTestServer* embedded_test_server) {
-  GURL main_url(embedded_test_server->GetURL(
-      "/frame_tree/page_with_content_overlap_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell, main_url));
-  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  gfx::PointF parent_location = gfx::PointF(5, 5);
-  parent_location =
-      rwhv_child->TransformPointToRootCoordSpaceF(parent_location);
-  DispatchMouseEventAndWaitUntilDispatch(
-      web_contents, rwhv_child, gfx::PointF(5, 5), rwhv_root, parent_location);
-
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
-                                         gfx::PointF(95, 95), rwhv_child,
-                                         gfx::PointF(95, 95));
-}
-
-// Helper function that performs a surface hittest in nested frame.
-void NestedSurfaceHitTestTestHelper(
-    Shell* shell,
-    net::test_server::EmbeddedTestServer* embedded_test_server) {
-  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
-  GURL main_url(embedded_test_server->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell, main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* parent_iframe_node = root->child_at(0);
-  GURL site_url(embedded_test_server->GetURL(
-      "a.com", "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_EQ(site_url, parent_iframe_node->current_url());
-  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
-            parent_iframe_node->current_frame_host()->GetSiteInstance());
-
-  FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
-  GURL nested_site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(nested_site_url, nested_iframe_node->current_url());
-  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
-            nested_iframe_node->current_frame_host()->GetSiteInstance());
-  EXPECT_NE(parent_iframe_node->current_frame_host()->GetSiteInstance(),
-            nested_iframe_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewBase* rwhv_nested =
-      static_cast<RenderWidgetHostViewBase*>(
-          nested_iframe_node->current_frame_host()
-              ->GetRenderWidgetHost()
-              ->GetView());
-
-  WaitForChildFrameSurfaceReady(nested_iframe_node->current_frame_host());
-
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_nested,
-                                         gfx::PointF(10, 10), rwhv_nested,
-                                         gfx::PointF(10, 10));
-}
-
-void HitTestLayerSquashing(
-    Shell* shell,
-    net::test_server::EmbeddedTestServer* embedded_test_server) {
-  GURL main_url(embedded_test_server->GetURL(
-      "/frame_tree/oopif_hit_test_layer_squashing.html"));
-  EXPECT_TRUE(NavigateToURL(shell, main_url));
-  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  gfx::Vector2dF child_offset = rwhv_child->GetViewBounds().origin() -
-                                rwhv_root->GetViewBounds().origin();
-  // Send a mouse-down on #B. The main-frame should receive it.
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
-                                         gfx::PointF(195, 11), rwhv_root,
-                                         gfx::PointF(195, 11));
-  // Send another event just below. The child-frame should receive it.
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
-                                         gfx::PointF(195, 30), rwhv_child,
-                                         gfx::PointF(195, 30) - child_offset);
-  // Send a mouse-down on #C.
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
-                                         gfx::PointF(35, 195), rwhv_root,
-                                         gfx::PointF(35, 195));
-  // Send a mouse-down to the right of #C so that it goes to the child frame.
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
-                                         gfx::PointF(55, 195), rwhv_child,
-                                         gfx::PointF(55, 195) - child_offset);
-  // Send a mouse-down to the right-bottom edge of the iframe.
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
-                                         gfx::PointF(195, 235), rwhv_child,
-                                         gfx::PointF(195, 235) - child_offset);
-}
-
-void HitTestWatermark(
-    Shell* shell,
-    net::test_server::EmbeddedTestServer* embedded_test_server) {
-  GURL main_url(embedded_test_server->GetURL(
-      "/frame_tree/oopif_hit_test_watermark.html"));
-  EXPECT_TRUE(NavigateToURL(shell, main_url));
-  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  gfx::Vector2dF child_offset = rwhv_child->GetViewBounds().origin() -
-                                rwhv_root->GetViewBounds().origin();
-  const gfx::PointF child_location(100, 120);
-  // Send a mouse-down at the center of the iframe. This should go to the
-  // main-frame (since there's a translucent div on top of it).
-  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
-                                         child_location, rwhv_root,
-                                         child_location + child_offset);
-
-  // Set 'pointer-events: none' on the div.
-  EXPECT_TRUE(ExecuteScript(web_contents, "W.style.pointerEvents = 'none';"));
-
-  // Dispatch another event at the same location. It should reach the oopif this
-  // time.
-  DispatchMouseEventAndWaitUntilDispatch(
-      web_contents, rwhv_child, child_location, rwhv_child, child_location);
-}
-
 class RedirectNotificationObserver : public NotificationObserver {
  public:
   // Register to listen for notifications of the given type from either a
@@ -788,7 +475,7 @@
   std::string GetHTMLContents() override { return "<p>Interstitial</p>"; }
 };
 
-#if defined(USE_AURA) || defined(OS_ANDROID)
+#if defined(OS_ANDROID)
 bool ConvertJSONToPoint(const std::string& str, gfx::PointF* point) {
   std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
   if (!value)
@@ -805,7 +492,7 @@
   point->set_y(y);
   return true;
 }
-#endif  // defined(USE_AURA) || defined (OS_ANDROID)
+#endif  // defined (OS_ANDROID)
 
 }  // namespace
 
@@ -839,7 +526,6 @@
 // SitePerProcessHighDPIBrowserTest
 //
 
-
 class SitePerProcessHighDPIBrowserTest : public SitePerProcessBrowserTest {
  public:
   const double kDeviceScaleFactor = 2.0;
@@ -855,26 +541,6 @@
   }
 };
 
-//
-// SitePerProcessNonIntegerScaleFactorBrowserTest
-//
-
-class SitePerProcessNonIntegerScaleFactorBrowserTest
-    : public SitePerProcessBrowserTest {
- public:
-  const double kDeviceScaleFactor = 1.5;
-
-  SitePerProcessNonIntegerScaleFactorBrowserTest() {}
-
- protected:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    SitePerProcessBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitchASCII(
-        switches::kForceDeviceScaleFactor,
-        base::StringPrintf("%f", kDeviceScaleFactor));
-  }
-};
-
 // SitePerProcessIgnoreCertErrorsBrowserTest
 
 class SitePerProcessIgnoreCertErrorsBrowserTest
@@ -1336,159 +1002,6 @@
   gesture_fling_start_ack_observer.Wait();
 }
 
-// Restrict to Aura to we can use routable MouseWheel event via
-// RenderWidgetHostViewAura::OnScrollEvent().
-#if defined(USE_AURA)
-class SitePerProcessInternalsBrowserTest : public SitePerProcessBrowserTest {
- public:
-  SitePerProcessInternalsBrowserTest() {}
-
- protected:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    SitePerProcessBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kExposeInternalsForTesting);
-    // Needed to guarantee the scrollable div we're testing with is not given
-    // its own compositing layer.
-    command_line->AppendSwitch(switches::kDisablePreferCompositingToLCDText);
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessInternalsBrowserTest,
-                       ScrollNestedLocalNonFastScrollableDiv) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* parent_iframe_node = root->child_at(0);
-
-  GURL site_url(embedded_test_server()->GetURL(
-      "b.com", "/tall_page_with_local_iframe.html"));
-  NavigateFrameToURL(parent_iframe_node, site_url);
-
-  FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
-  WaitForChildFrameSurfaceReady(nested_iframe_node->current_frame_host());
-
-  EXPECT_EQ(
-      " Site A ------------ proxies for B\n"
-      "   +--Site B ------- proxies for A\n"
-      "        +--Site B -- proxies for A\n"
-      "Where A = http://a.com/\n"
-      "      B = http://b.com/",
-      DepictFrameTree(root));
-
-  const char* get_element_location_script_fmt =
-      "var rect = "
-      "document.getElementById('%s').getBoundingClientRect();\n"
-      "var point = {\n"
-      "  x: rect.left,\n"
-      "  y: rect.top\n"
-      "};\n"
-      "window.domAutomationController.send(JSON.stringify(point));";
-
-  // Since the nested local b-frame shares the RenderWidgetHostViewChildFrame
-  // with the parent frame, we need to query element offsets in both documents
-  // before converting to root space coordinates for the wheel event.
-  std::string str;
-  EXPECT_TRUE(ExecuteScriptAndExtractString(
-      nested_iframe_node->current_frame_host(),
-      base::StringPrintf(get_element_location_script_fmt, "scrollable_div"),
-      &str));
-  gfx::PointF nested_point_f;
-  ConvertJSONToPoint(str, &nested_point_f);
-
-  EXPECT_TRUE(ExecuteScriptAndExtractString(
-      parent_iframe_node->current_frame_host(),
-      base::StringPrintf(get_element_location_script_fmt, "nested_frame"),
-      &str));
-  gfx::PointF parent_offset_f;
-  ConvertJSONToPoint(str, &parent_offset_f);
-
-  // Compute location for wheel event.
-  gfx::PointF point_f(parent_offset_f.x() + nested_point_f.x() + 5.f,
-                      parent_offset_f.y() + nested_point_f.y() + 5.f);
-
-  RenderWidgetHostViewChildFrame* rwhv_nested =
-      static_cast<RenderWidgetHostViewChildFrame*>(
-          nested_iframe_node->current_frame_host()
-              ->GetRenderWidgetHost()
-              ->GetView());
-  point_f = rwhv_nested->TransformPointToRootCoordSpaceF(point_f);
-
-  RenderWidgetHostViewAura* rwhv_root = static_cast<RenderWidgetHostViewAura*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  gfx::PointF nested_in_parent;
-  rwhv_root->TransformPointToCoordSpaceForView(
-      point_f,
-      parent_iframe_node->current_frame_host()
-          ->GetRenderWidgetHost()
-          ->GetView(),
-      &nested_in_parent);
-
-  // Get original scroll position.
-  int div_scroll_top_start;
-  EXPECT_TRUE(ExecuteScriptAndExtractInt(
-      nested_iframe_node->current_frame_host(),
-      "window.domAutomationController.send("
-      "document.getElementById('scrollable_div').scrollTop);",
-      &div_scroll_top_start));
-  EXPECT_EQ(0, div_scroll_top_start);
-
-  // Wait until renderer's compositor thread is synced. Otherwise the event
-  // handler won't be installed when the event arrives.
-  MainThreadFrameObserver observer(rwhv_root->GetRenderWidgetHost());
-  observer.Wait();
-  {
-    base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(),
-        // tiny_timeout() is too small to run without flakes, but
-        // action_timeout() is 100 times bigger, which is overkill. We use a
-        // custom delay here to achieve a balance.
-        base::TimeDelta::FromMilliseconds(1000));
-    run_loop.Run();
-  }
-
-  // Send a wheel to scroll the div.
-  gfx::Point location(point_f.x(), point_f.y());
-  ui::ScrollEvent scroll_event(ui::ET_SCROLL, location, ui::EventTimeForNow(),
-                               0, 0, -ui::MouseWheelEvent::kWheelDelta, 0,
-                               ui::MouseWheelEvent::kWheelDelta,
-                               2);  // This must be '2' or it gets silently
-                                    // dropped.
-  rwhv_root->OnScrollEvent(&scroll_event);
-
-  InputEventAckWaiter ack_observer(
-      parent_iframe_node->current_frame_host()->GetRenderWidgetHost(),
-      blink::WebInputEvent::kGestureScrollUpdate);
-  ack_observer.Wait();
-
-  // Check compositor layers.
-  EXPECT_TRUE(ExecuteScriptAndExtractString(
-      nested_iframe_node->current_frame_host(),
-      "window.domAutomationController.send("
-      "window.internals.layerTreeAsText(document));",
-      &str));
-  // We expect the nested OOPIF to not have any compositor layers.
-  EXPECT_EQ(std::string(), str);
-
-  // Verify the div scrolled.
-  int div_scroll_top = div_scroll_top_start;
-  EXPECT_TRUE(ExecuteScriptAndExtractInt(
-      nested_iframe_node->current_frame_host(),
-      "window.domAutomationController.send("
-      "document.getElementById('scrollable_div').scrollTop);",
-      &div_scroll_top));
-  EXPECT_NE(div_scroll_top_start, div_scroll_top);
-}
-#endif  // defined(USE_AURA)
-
 // Test that scrolling a nested out-of-process iframe bubbles unused scroll
 // delta to a parent frame.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ScrollBubblingFromOOPIFTest) {
@@ -1728,78 +1241,6 @@
   DCHECK_EQ(filter->last_rect().y(), 0);
 }
 
-// Tests that wheel scroll bubbling gets cancelled when the wheel target view
-// gets destroyed in the middle of a wheel scroll seqeunce. This happens in
-// cases like overscroll navigation from inside an oopif.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       CancelWheelScrollBubblingOnWheelTargetDeletion) {
-  ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
-      0);
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* iframe_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, iframe_node->current_url());
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
-      iframe_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  RenderWidgetHostInputEventRouter* router =
-      static_cast<WebContentsImpl*>(shell()->web_contents())
-          ->GetInputEventRouter();
-
-  WaitForChildFrameSurfaceReady(iframe_node->current_frame_host());
-
-  InputEventAckWaiter scroll_begin_observer(
-      root->current_frame_host()->GetRenderWidgetHost(),
-      blink::WebInputEvent::kGestureScrollBegin);
-  InputEventAckWaiter scroll_end_observer(
-      root->current_frame_host()->GetRenderWidgetHost(),
-      blink::WebInputEvent::kGestureScrollEnd);
-
-  // Scroll the iframe upward, scroll events get bubbled up to the root.
-  blink::WebMouseWheelEvent scroll_event(
-      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
-      blink::WebInputEvent::kTimeStampForTesting);
-  gfx::Rect bounds = child_rwhv->GetViewBounds();
-  float scale_factor = GetPageScaleFactor(shell());
-  scroll_event.SetPositionInWidget(
-      gfx::ToCeiledInt((bounds.x() - root_view->GetViewBounds().x() + 5) *
-                       scale_factor),
-      gfx::ToCeiledInt((bounds.y() - root_view->GetViewBounds().y() + 5) *
-                       scale_factor));
-  scroll_event.delta_x = 0.0f;
-  scroll_event.delta_y = 5.0f;
-  scroll_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
-  scroll_event.has_precise_scrolling_deltas = true;
-  router->RouteMouseWheelEvent(root_view, &scroll_event, ui::LatencyInfo());
-  scroll_begin_observer.Wait();
-
-  // Now destroy the child_rwhv, scroll bubbling stops and a GSE gets sent to
-  // the root_view.
-  RenderProcessHost* rph =
-      iframe_node->current_frame_host()->GetSiteInstance()->GetProcess();
-  RenderProcessHostWatcher crash_observer(
-      rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-  EXPECT_TRUE(rph->Shutdown(0, false));
-  crash_observer.Wait();
-  scroll_event.delta_y = 0.0f;
-  scroll_event.phase = blink::WebMouseWheelEvent::kPhaseEnded;
-  scroll_event.dispatch_type =
-      blink::WebInputEvent::DispatchType::kEventNonBlocking;
-  router->RouteMouseWheelEvent(root_view, &scroll_event, ui::LatencyInfo());
-  scroll_end_observer.Wait();
-}
-
 class ScrollObserver : public RenderWidgetHost::InputEventObserver {
  public:
   ScrollObserver(double delta_x, double delta_y) { Reset(delta_x, delta_y); }
@@ -2061,761 +1502,9 @@
   EXPECT_TRUE(main_frame->GetView()->GetViewBounds().Intersects(test_rect));
 }
 
-#if defined(USE_AURA) || defined(OS_ANDROID)
-
-// When unconsumed scrolls in a child bubble to the root and start an
-// overscroll gesture, the subsequent gesture scroll update events should be
-// consumed by the root. The child should not be able to scroll during the
-// overscroll gesture.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       RootConsumesScrollDuringOverscrollGesture) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b)"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-
-#if defined(USE_AURA)
-  // The child must be horizontally scrollable.
-  GURL child_url(embedded_test_server()->GetURL("b.com", "/wide_page.html"));
-#elif defined(OS_ANDROID)
-  // The child must be vertically scrollable.
-  GURL child_url(embedded_test_server()->GetURL("b.com", "/tall_page.html"));
-#endif
-  NavigateFrameToURL(child_node, child_url);
-
-  EXPECT_EQ(
-      " Site A ------------ proxies for B\n"
-      "   +--Site B ------- proxies for A\n"
-      "Where A = http://a.com/\n"
-      "      B = http://b.com/",
-      DepictFrameTree(root));
-
-  RenderWidgetHostViewChildFrame* rwhv_child =
-      static_cast<RenderWidgetHostViewChildFrame*>(
-          child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  ASSERT_EQ(gfx::Vector2dF(), rwhv_root->GetLastScrollOffset());
-  ASSERT_EQ(gfx::Vector2dF(), rwhv_child->GetLastScrollOffset());
-
-  RenderWidgetHostInputEventRouter* router =
-      static_cast<WebContentsImpl*>(shell()->web_contents())
-          ->GetInputEventRouter();
-
-  {
-    // Set up the RenderWidgetHostInputEventRouter to send the gesture stream
-    // to the child.
-    const gfx::Rect root_bounds = rwhv_root->GetViewBounds();
-    const gfx::Rect child_bounds = rwhv_child->GetViewBounds();
-    const float page_scale_factor = GetPageScaleFactor(shell());
-    const gfx::PointF point_in_child(
-        (child_bounds.x() - root_bounds.x() + 10) * page_scale_factor,
-        (child_bounds.y() - root_bounds.y() + 10) * page_scale_factor);
-    gfx::PointF dont_care;
-    ASSERT_EQ(rwhv_child->GetRenderWidgetHost(),
-              router->GetRenderWidgetHostAtPoint(rwhv_root, point_in_child,
-                                                 &dont_care));
-
-    blink::WebTouchEvent touch_event(
-        blink::WebInputEvent::kTouchStart, blink::WebInputEvent::kNoModifiers,
-        blink::WebInputEvent::kTimeStampForTesting);
-    touch_event.touches_length = 1;
-    touch_event.touches[0].state = blink::WebTouchPoint::kStatePressed;
-    touch_event.touches[0].SetPositionInWidget(point_in_child.x(),
-                                               point_in_child.y());
-    touch_event.unique_touch_event_id = 1;
-    InputEventAckWaiter waiter(rwhv_child->GetRenderWidgetHost(),
-                               blink::WebInputEvent::kTouchStart);
-    router->RouteTouchEvent(rwhv_root, &touch_event,
-                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
-    // With async hit testing, make sure the target for the initial TouchStart
-    // is resolved before sending the rest of the stream.
-    waiter.Wait();
-
-    blink::WebGestureEvent gesture_event(
-        blink::WebInputEvent::kGestureTapDown,
-        blink::WebInputEvent::kNoModifiers,
-        blink::WebInputEvent::kTimeStampForTesting);
-    gesture_event.source_device = blink::kWebGestureDeviceTouchscreen;
-    gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
-    router->RouteGestureEvent(rwhv_root, &gesture_event,
-                              ui::LatencyInfo(ui::SourceEventType::TOUCH));
-  }
-
-#if defined(USE_AURA)
-  RenderWidgetHostViewAura* rwhva =
-      static_cast<RenderWidgetHostViewAura*>(rwhv_root);
-  std::unique_ptr<MockOverscrollControllerDelegateAura>
-      mock_overscroll_delegate =
-          std::make_unique<MockOverscrollControllerDelegateAura>(rwhva);
-  rwhva->overscroll_controller()->set_delegate(mock_overscroll_delegate.get());
-  MockOverscrollObserver* mock_overscroll_observer =
-      mock_overscroll_delegate.get();
-#elif defined(OS_ANDROID)
-  RenderWidgetHostViewAndroid* rwhv_android =
-      static_cast<RenderWidgetHostViewAndroid*>(rwhv_root);
-  std::unique_ptr<MockOverscrollRefreshHandlerAndroid> mock_overscroll_handler =
-      std::make_unique<MockOverscrollRefreshHandlerAndroid>();
-  rwhv_android->SetOverscrollControllerForTesting(
-      mock_overscroll_handler.get());
-  MockOverscrollObserver* mock_overscroll_observer =
-      mock_overscroll_handler.get();
-#endif  // defined(USE_AURA)
-
-  InputEventAckWaiter gesture_begin_observer_child(
-      child_node->current_frame_host()->GetRenderWidgetHost(),
-      blink::WebInputEvent::kGestureScrollBegin);
-  InputEventAckWaiter gesture_end_observer_child(
-      child_node->current_frame_host()->GetRenderWidgetHost(),
-      blink::WebInputEvent::kGestureScrollEnd);
-
-#if defined(USE_AURA)
-  const float overscroll_threshold =
-      GetOverscrollConfig(OverscrollConfig::THRESHOLD_START_TOUCHSCREEN);
-#elif defined(OS_ANDROID)
-  const float overscroll_threshold = 0.f;
-#endif
-
-  // First we need our scroll to initiate an overscroll gesture in the root
-  // via unconsumed scrolls in the child.
-  blink::WebGestureEvent gesture_scroll_begin(
-      blink::WebGestureEvent::kGestureScrollBegin,
-      blink::WebInputEvent::kNoModifiers,
-      blink::WebInputEvent::kTimeStampForTesting);
-  gesture_scroll_begin.source_device = blink::kWebGestureDeviceTouchscreen;
-  gesture_scroll_begin.unique_touch_event_id = 1;
-  gesture_scroll_begin.data.scroll_begin.delta_hint_units =
-      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
-  gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
-  gesture_scroll_begin.data.scroll_begin.delta_y_hint = 0.f;
-#if defined(USE_AURA)
-  // For aura, we scroll horizontally to activate an overscroll navigation.
-  gesture_scroll_begin.data.scroll_begin.delta_x_hint =
-      overscroll_threshold + 1;
-#elif defined(OS_ANDROID)
-  // For android, we scroll vertically to activate pull-to-refresh.
-  gesture_scroll_begin.data.scroll_begin.delta_y_hint =
-      overscroll_threshold + 1;
-#endif
-  router->RouteGestureEvent(rwhv_root, &gesture_scroll_begin,
-                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
-
-  // Make sure the child is indeed receiving the gesture stream.
-  gesture_begin_observer_child.Wait();
-
-  blink::WebGestureEvent gesture_scroll_update(
-      blink::WebGestureEvent::kGestureScrollUpdate,
-      blink::WebInputEvent::kNoModifiers,
-      blink::WebInputEvent::kTimeStampForTesting);
-  gesture_scroll_update.source_device = blink::kWebGestureDeviceTouchscreen;
-  gesture_scroll_update.unique_touch_event_id = 1;
-  gesture_scroll_update.data.scroll_update.delta_units =
-      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
-  gesture_scroll_update.data.scroll_update.delta_x = 0.f;
-  gesture_scroll_update.data.scroll_update.delta_y = 0.f;
-#if defined(USE_AURA)
-  float* delta = &gesture_scroll_update.data.scroll_update.delta_x;
-#elif defined(OS_ANDROID)
-  float* delta = &gesture_scroll_update.data.scroll_update.delta_y;
-#endif
-  *delta = overscroll_threshold + 1;
-  mock_overscroll_observer->Reset();
-  // This will bring us into an overscroll gesture.
-  router->RouteGestureEvent(rwhv_root, &gesture_scroll_update,
-                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
-  // Note that in addition to verifying that we get the overscroll update, it
-  // is necessary to wait before sending the next event to prevent our multiple
-  // GestureScrollUpdates from being coalesced.
-  mock_overscroll_observer->WaitForUpdate();
-
-  // This scroll is in the same direction and so it will contribute to the
-  // overscroll.
-  *delta = 10.0f;
-  mock_overscroll_observer->Reset();
-  router->RouteGestureEvent(rwhv_root, &gesture_scroll_update,
-                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
-  mock_overscroll_observer->WaitForUpdate();
-
-  // Now we reverse direction. The child could scroll in this direction, but
-  // since we're in an overscroll gesture, the root should consume it.
-  *delta = -5.0f;
-  mock_overscroll_observer->Reset();
-  router->RouteGestureEvent(rwhv_root, &gesture_scroll_update,
-                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
-  mock_overscroll_observer->WaitForUpdate();
-
-  blink::WebGestureEvent gesture_scroll_end(
-      blink::WebGestureEvent::kGestureScrollEnd,
-      blink::WebInputEvent::kNoModifiers,
-      blink::WebInputEvent::kTimeStampForTesting);
-  gesture_scroll_end.source_device = blink::kWebGestureDeviceTouchscreen;
-  gesture_scroll_end.unique_touch_event_id = 1;
-  gesture_scroll_end.data.scroll_end.delta_units =
-      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
-  mock_overscroll_observer->Reset();
-  router->RouteGestureEvent(rwhv_root, &gesture_scroll_end,
-                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
-  mock_overscroll_observer->WaitForEnd();
-
-  // Ensure that the method of providing the child's scroll events to the root
-  // does not leave the child in an invalid state.
-  gesture_end_observer_child.Wait();
-}
-#endif  // defined(USE_AURA) || defined(OS_ANDROID)
-
-// Test that an ET_SCROLL event sent to an out-of-process iframe correctly
-// results in a scroll. This is only handled by RenderWidgetHostViewAura
-// and is needed for trackpad scrolling on Chromebooks.
-#if defined(USE_AURA)
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ScrollEventToOOPIF) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewAura* rwhv_parent =
-      static_cast<RenderWidgetHostViewAura*>(
-          root->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  // Create listener for input events.
-  TestInputEventObserver child_frame_monitor(
-      child_node->current_frame_host()->GetRenderWidgetHost());
-
-  // Send a ui::ScrollEvent that will hit test to the child frame.
-  InputEventAckWaiter waiter(
-      child_node->current_frame_host()->GetRenderWidgetHost(),
-      blink::WebInputEvent::kMouseWheel);
-  ui::ScrollEvent scroll_event(ui::ET_SCROLL, gfx::Point(75, 75),
-                               ui::EventTimeForNow(), ui::EF_NONE,
-                               0, 10,     // Offsets
-                               0, 10,  // Offset ordinals
-                               2);
-  rwhv_parent->OnScrollEvent(&scroll_event);
-  waiter.Wait();
-
-  // Verify that this a mouse wheel event was sent to the child frame renderer.
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-  EXPECT_EQ(child_frame_monitor.EventType(), blink::WebInputEvent::kMouseWheel);
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       InputEventRouterWheelCoalesceTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewAura* rwhv_parent =
-      static_cast<RenderWidgetHostViewAura*>(
-          root->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  RenderWidgetHostInputEventRouter* router =
-      web_contents()->GetInputEventRouter();
-
-  // Create listener for input events.
-  TestInputEventObserver child_frame_monitor(
-      child_node->current_frame_host()->GetRenderWidgetHost());
-  InputEventAckWaiter waiter(
-      child_node->current_frame_host()->GetRenderWidgetHost(),
-      blink::WebInputEvent::kMouseWheel);
-
-  // Send a mouse wheel event to child.
-  blink::WebMouseWheelEvent wheel_event(
-      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
-      blink::WebInputEvent::kTimeStampForTesting);
-  wheel_event.SetPositionInWidget(75, 75);
-  wheel_event.delta_x = 10;
-  wheel_event.delta_y = 20;
-  wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
-  router->RouteMouseWheelEvent(rwhv_parent, &wheel_event, ui::LatencyInfo());
-
-  // Send more mouse wheel events to the child. Since we are waiting for the
-  // async targeting on the first event, these new mouse wheel events should
-  // be coalesced properly.
-  blink::WebMouseWheelEvent wheel_event1(
-      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
-      blink::WebInputEvent::kTimeStampForTesting);
-  wheel_event1.SetPositionInWidget(70, 70);
-  wheel_event1.delta_x = 12;
-  wheel_event1.delta_y = 22;
-  wheel_event1.phase = blink::WebMouseWheelEvent::kPhaseChanged;
-  router->RouteMouseWheelEvent(rwhv_parent, &wheel_event1, ui::LatencyInfo());
-
-  blink::WebMouseWheelEvent wheel_event2(
-      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
-      blink::WebInputEvent::kTimeStampForTesting);
-  wheel_event2.SetPositionInWidget(65, 65);
-  wheel_event2.delta_x = 14;
-  wheel_event2.delta_y = 24;
-  wheel_event2.phase = blink::WebMouseWheelEvent::kPhaseChanged;
-  router->RouteMouseWheelEvent(rwhv_parent, &wheel_event2, ui::LatencyInfo());
-
-  // Since we are targeting child, event dispatch should not happen
-  // synchronously. Validate that the expected target does not receive the
-  // event immediately.
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-
-  waiter.Wait();
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-  EXPECT_EQ(child_frame_monitor.EventType(), blink::WebInputEvent::kMouseWheel);
-
-  // Check if the two mouse-wheel update events are coalesced correctly.
-  const auto& gesture_event =
-      static_cast<const blink::WebGestureEvent&>(child_frame_monitor.event());
-  EXPECT_EQ(26 /* wheel_event1.delta_x + wheel_event2.delta_x */,
-            gesture_event.data.scroll_update.delta_x);
-  EXPECT_EQ(46 /* wheel_event1.delta_y + wheel_event2.delta_y */,
-            gesture_event.data.scroll_update.delta_y);
-}
-#endif
-
-// Test that mouse events are being routed to the correct RenderWidgetHostView
-// based on coordinates.
-#if defined(THREAD_SANITIZER)
-// The test times out often on TSAN bot.
-// https://crbug.com/591170.
-#define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest
-#else
-#define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_SurfaceHitTestTest) {
-  SurfaceHitTestTestHelper(shell(), embedded_test_server());
-}
-
-// Same test as above, but runs in high-dpi mode.
-#if defined(OS_ANDROID) || defined(OS_WIN)
-// High DPI browser tests are not needed on Android, and confuse some of the
-// coordinate calculations. Android uses fixed device scale factor.
-// Windows is disabled because of https://crbug.com/545547.
-#define MAYBE_HighDPISurfaceHitTestTest DISABLED_SurfaceHitTestTest
-#else
-#define MAYBE_HighDPISurfaceHitTestTest SurfaceHitTestTest
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
-                       MAYBE_HighDPISurfaceHitTestTest) {
-  SurfaceHitTestTestHelper(shell(), embedded_test_server());
-}
-
-// Test that mouse events are being routed to the correct RenderWidgetHostView
-// when there are nested out-of-process iframes.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NestedSurfaceHitTestTest) {
-  NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
-                       NestedSurfaceHitTestTest) {
-  NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OverlapSurfaceHitTestTest) {
-  OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
-                       OverlapSurfaceHitTestTest) {
-  OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, HitTestLayerSquashing) {
-  HitTestLayerSquashing(shell(), embedded_test_server());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
-                       HitTestLayerSquashing) {
-  HitTestLayerSquashing(shell(), embedded_test_server());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, HitTestWatermark) {
-  HitTestWatermark(shell(), embedded_test_server());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest, HitTestWatermark) {
-  HitTestWatermark(shell(), embedded_test_server());
-}
-
-// This test tests that browser process hittesting ignores frames with
-// pointer-events: none.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       SurfaceHitTestPointerEventsNone) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_frame_pointer-events_none.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  // Create listeners for mouse events.
-  RenderWidgetHostMouseEventMonitor main_frame_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor child_frame_monitor(
-      child_node->current_frame_host()->GetRenderWidgetHost());
-
-  RenderWidgetHostInputEventRouter* router =
-      web_contents()->GetInputEventRouter();
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  // Target input event to child frame.
-  blink::WebMouseEvent child_event(blink::WebInputEvent::kMouseDown,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  child_event.button = blink::WebPointerProperties::Button::kLeft;
-  child_event.SetPositionInWidget(75, 75);
-  child_event.click_count = 1;
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  router->RouteMouseEvent(root_view, &child_event, ui::LatencyInfo());
-
-  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
-  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().x, 2);
-  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().y, 2);
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-}
-
-// Verify that an event is properly retargeted to the main frame when an
-// asynchronous hit test to the child frame times out.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       AsynchronousHitTestChildTimeout) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_busy_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-
-  // Create listeners for mouse events.
-  RenderWidgetHostMouseEventMonitor main_frame_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor child_frame_monitor(
-      child_node->current_frame_host()->GetRenderWidgetHost());
-
-  RenderWidgetHostInputEventRouter* router =
-      web_contents()->GetInputEventRouter();
-
-  // Shorten the timeout for purposes of this test.
-  router->GetRenderWidgetTargeterForTests()
-      ->set_async_hit_test_timeout_delay_for_testing(
-          TestTimeouts::tiny_timeout());
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  // Target input event to child frame. It should get delivered to the main
-  // frame instead because the child frame main thread is non-responsive.
-  blink::WebMouseEvent child_event(blink::WebInputEvent::kMouseDown,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  child_event.button = blink::WebPointerProperties::Button::kLeft;
-  child_event.SetPositionInWidget(75, 75);
-  child_event.click_count = 1;
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  RouteMouseEventAndWaitUntilDispatch(router, root_view, root_view,
-                                      &child_event);
-
-  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
-  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().x, 2);
-  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().y, 2);
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-}
-
-// This test verifies that MouseEnter and MouseLeave events fire correctly
-// when the mouse cursor moves between processes.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       CrossProcessMouseEnterAndLeaveTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b,c(d))"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-
-  EXPECT_EQ(
-      " Site A ------------ proxies for B C D\n"
-      "   |--Site B ------- proxies for A C D\n"
-      "   +--Site C ------- proxies for A B D\n"
-      "        +--Site D -- proxies for A B C\n"
-      "Where A = http://a.com/\n"
-      "      B = http://b.com/\n"
-      "      C = http://c.com/\n"
-      "      D = http://d.com/",
-      DepictFrameTree(root));
-
-  FrameTreeNode* b_node = root->child_at(0);
-  FrameTreeNode* c_node = root->child_at(1);
-  FrameTreeNode* d_node = c_node->child_at(0);
-
-  RenderWidgetHostViewBase* rwhv_a = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_b = static_cast<RenderWidgetHostViewBase*>(
-      b_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_d = static_cast<RenderWidgetHostViewBase*>(
-      d_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  // Verifying surfaces are ready in B and D are sufficient, since other
-  // surfaces contain at least one of them.
-  WaitForChildFrameSurfaceReady(b_node->current_frame_host());
-  WaitForChildFrameSurfaceReady(d_node->current_frame_host());
-
-  // Create listeners for mouse events. These are used to verify that the
-  // RenderWidgetHostInputEventRouter is generating MouseLeave, etc for
-  // the right renderers.
-  RenderWidgetHostMouseEventMonitor root_frame_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor a_frame_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor b_frame_monitor(
-      b_node->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor c_frame_monitor(
-      c_node->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor d_frame_monitor(
-      d_node->current_frame_host()->GetRenderWidgetHost());
-
-  float scale_factor = GetPageScaleFactor(shell());
-
-  // Get the view bounds of the child iframe, which should account for the
-  // relative offset of its direct parent within the root frame, for use in
-  // targeting the input event.
-  gfx::Rect a_bounds = rwhv_a->GetViewBounds();
-  gfx::Rect b_bounds = rwhv_b->GetViewBounds();
-  gfx::Rect d_bounds = rwhv_d->GetViewBounds();
-
-  gfx::Point point_in_a_frame(2, 2);
-  gfx::Point point_in_b_frame(
-      gfx::ToCeiledInt((b_bounds.x() - a_bounds.x() + 25) * scale_factor),
-      gfx::ToCeiledInt((b_bounds.y() - a_bounds.y() + 25) * scale_factor));
-  gfx::Point point_in_d_frame(
-      gfx::ToCeiledInt((d_bounds.x() - a_bounds.x() + 25) * scale_factor),
-      gfx::ToCeiledInt((d_bounds.y() - a_bounds.y() + 25) * scale_factor));
-
-  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseMove,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  mouse_event.SetPositionInWidget(point_in_a_frame.x(), point_in_a_frame.y());
-
-  // Send an initial MouseMove to the root view, which shouldn't affect the
-  // other renderers.
-  web_contents()->GetInputEventRouter()->RouteMouseEvent(rwhv_a, &mouse_event,
-                                                         ui::LatencyInfo());
-  EXPECT_TRUE(a_frame_monitor.EventWasReceived());
-  a_frame_monitor.ResetEventReceived();
-  EXPECT_FALSE(b_frame_monitor.EventWasReceived());
-  EXPECT_FALSE(c_frame_monitor.EventWasReceived());
-  EXPECT_FALSE(d_frame_monitor.EventWasReceived());
-
-  // Next send a MouseMove to B frame, which shouldn't affect C or D but
-  // A should receive a MouseMove event.
-  mouse_event.SetPositionInWidget(point_in_b_frame.x(), point_in_b_frame.y());
-  auto* router = web_contents()->GetInputEventRouter();
-  RouteMouseEventAndWaitUntilDispatch(router, rwhv_a, rwhv_b, &mouse_event);
-  EXPECT_TRUE(a_frame_monitor.EventWasReceived());
-  EXPECT_EQ(a_frame_monitor.event().GetType(),
-            blink::WebInputEvent::kMouseMove);
-  a_frame_monitor.ResetEventReceived();
-  EXPECT_TRUE(b_frame_monitor.EventWasReceived());
-  b_frame_monitor.ResetEventReceived();
-  EXPECT_FALSE(c_frame_monitor.EventWasReceived());
-  EXPECT_FALSE(d_frame_monitor.EventWasReceived());
-
-  // Next send a MouseMove to D frame, which should have side effects in every
-  // other RenderWidgetHostView.
-  mouse_event.SetPositionInWidget(point_in_d_frame.x(), point_in_d_frame.y());
-  RouteMouseEventAndWaitUntilDispatch(router, rwhv_a, rwhv_d, &mouse_event);
-  EXPECT_TRUE(a_frame_monitor.EventWasReceived());
-  EXPECT_EQ(a_frame_monitor.event().GetType(),
-            blink::WebInputEvent::kMouseMove);
-  EXPECT_TRUE(b_frame_monitor.EventWasReceived());
-  EXPECT_EQ(b_frame_monitor.event().GetType(),
-            blink::WebInputEvent::kMouseLeave);
-  EXPECT_TRUE(c_frame_monitor.EventWasReceived());
-  EXPECT_EQ(c_frame_monitor.event().GetType(),
-            blink::WebInputEvent::kMouseMove);
-  EXPECT_TRUE(d_frame_monitor.EventWasReceived());
-}
-
-// Verify that mouse capture works on a RenderWidgetHostView level, so that
-// dragging scroll bars and selecting text continues even when the mouse
-// cursor crosses over cross-process frame boundaries.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossProcessMouseCapture) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  // Create listeners for mouse events.
-  RenderWidgetHostMouseEventMonitor main_frame_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor child_frame_monitor(
-      child_node->current_frame_host()->GetRenderWidgetHost());
-
-  RenderWidgetHostInputEventRouter* router =
-      web_contents()->GetInputEventRouter();
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  float scale_factor = GetPageScaleFactor(shell());
-
-  // Get the view bounds of the child iframe, which should account for the
-  // relative offset of its direct parent within the root frame, for use in
-  // targeting the input event.
-  gfx::Rect bounds = rwhv_child->GetViewBounds();
-  int child_frame_target_x = gfx::ToCeiledInt(
-      (bounds.x() - root_view->GetViewBounds().x() + 5) * scale_factor);
-  int child_frame_target_y = gfx::ToCeiledInt(
-      (bounds.y() - root_view->GetViewBounds().y() + 5) * scale_factor);
-
-  // Target MouseDown to child frame.
-  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseDown,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  mouse_event.button = blink::WebPointerProperties::Button::kLeft;
-  mouse_event.SetPositionInWidget(child_frame_target_x, child_frame_target_y);
-  mouse_event.click_count = 1;
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
-                                      &mouse_event);
-
-  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-
-  // Target MouseMove to main frame. This should still be routed to the
-  // child frame because it is now capturing mouse input.
-  mouse_event.SetType(blink::WebInputEvent::kMouseMove);
-  mouse_event.SetModifiers(blink::WebInputEvent::kLeftButtonDown);
-  mouse_event.SetPositionInWidget(1, 1);
-  // Note that this event is sent twice, with the monitors cleared after
-  // the first time, because the first MouseMove to the child frame
-  // causes a MouseMove to be sent to the main frame also, which we
-  // need to ignore.
-  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  mouse_event.SetPositionInWidget(1, 5);
-  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
-                                      &mouse_event);
-
-  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-
-  // A MouseUp to the child frame should cancel the mouse capture.
-  mouse_event.SetType(blink::WebInputEvent::kMouseUp);
-  mouse_event.SetModifiers(blink::WebInputEvent::kNoModifiers);
-  mouse_event.SetPositionInWidget(child_frame_target_x, child_frame_target_y);
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
-                                      &mouse_event);
-
-  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-
-  // Subsequent MouseMove events targeted to the main frame should be routed
-  // to that frame.
-  mouse_event.SetType(blink::WebInputEvent::kMouseMove);
-  mouse_event.SetPositionInWidget(1, 10);
-  // Sending the MouseMove twice for the same reason as above.
-  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  mouse_event.SetPositionInWidget(1, 15);
-  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
-
-  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-
-  // Target MouseDown to the main frame to cause it to capture input.
-  mouse_event.SetType(blink::WebInputEvent::kMouseDown);
-  mouse_event.SetPositionInWidget(1, 20);
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
-
-  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-
-  // Sending a MouseMove to the child frame should still result in the main
-  // frame receiving the event.
-  mouse_event.SetType(blink::WebInputEvent::kMouseMove);
-  mouse_event.SetModifiers(blink::WebInputEvent::kLeftButtonDown);
-  mouse_event.SetPositionInWidget(child_frame_target_x, child_frame_target_y);
-  main_frame_monitor.ResetEventReceived();
-  child_frame_monitor.ResetEventReceived();
-  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
-
-  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-}
-
 // Tests OOPIF rendering by checking that the RWH of the iframe generates
 // OnSwapCompositorFrame message.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       CompositorFrameSwapped) {
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CompositorFrameSwapped) {
   GURL main_url(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(baz)"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -3209,8 +1898,7 @@
   EXPECT_EQ(site_b_url, node2->current_url());
 
   // Kill that cross-site renderer.
-  RenderProcessHost* child_process =
-      node2->current_frame_host()->GetProcess();
+  RenderProcessHost* child_process = node2->current_frame_host()->GetProcess();
   RenderProcessHostWatcher crash_observer(
       child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
   child_process->Shutdown(0, false);
@@ -3768,9 +2456,8 @@
   FrameTreeNode* root = web_contents()->GetFrameTree()->root();
   ASSERT_EQ(2U, root->child_count());
 
-  GURL site_b_url(
-      embedded_test_server()->GetURL(
-          "bar.com", "/frame_tree/page_with_one_frame.html"));
+  GURL site_b_url(embedded_test_server()->GetURL(
+      "bar.com", "/frame_tree/page_with_one_frame.html"));
   // We can't use a TestNavigationObserver to verify the URL here,
   // since the frame has children that may have clobbered it in the observer.
   EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
@@ -3854,8 +2541,7 @@
   RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
   {
     RenderProcessHostWatcher crash_observer(
-        child_process,
-        RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+        child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
     child_process->Shutdown(0, false);
     crash_observer.Wait();
   }
@@ -3879,8 +2565,7 @@
   // Now crash the top-level page to clear the child frame.
   {
     RenderProcessHostWatcher crash_observer(
-        root_process,
-        RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+        root_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
     root_process->Shutdown(0, false);
     crash_observer.Wait();
   }
@@ -3996,9 +2681,8 @@
         embedded_test_server()->GetURL("/client-redirect?" + https_url.spec()));
 
     RedirectNotificationObserver load_observer2(
-        NOTIFICATION_LOAD_STOP,
-        Source<NavigationController>(
-            &shell()->web_contents()->GetController()));
+        NOTIFICATION_LOAD_STOP, Source<NavigationController>(
+                                    &shell()->web_contents()->GetController()));
 
     EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
                                     client_redirect_http_url));
@@ -4030,9 +2714,8 @@
     GURL client_redirect_http_url(
         embedded_test_server()->GetURL("/client-redirect?" + http_url.spec()));
     RedirectNotificationObserver load_observer2(
-        NOTIFICATION_LOAD_STOP,
-        Source<NavigationController>(
-            &shell()->web_contents()->GetController()));
+        NOTIFICATION_LOAD_STOP, Source<NavigationController>(
+                                    &shell()->web_contents()->GetController()));
 
     EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
                                     client_redirect_http_url));
@@ -4073,9 +2756,8 @@
 
     // We should wait until second client redirect get cancelled.
     RedirectNotificationObserver load_observer2(
-        NOTIFICATION_LOAD_STOP,
-        Source<NavigationController>(
-            &shell()->web_contents()->GetController()));
+        NOTIFICATION_LOAD_STOP, Source<NavigationController>(
+                                    &shell()->web_contents()->GetController()));
 
     EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
                                     client_redirect_http_url));
@@ -4133,8 +2815,7 @@
 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
 // created in the FrameTree skipping the subtree of the navigating frame (but
 // not the navigating frame itself).
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       ProxyCreationSkipsSubtree) {
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ProxyCreationSkipsSubtree) {
   GURL main_url(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
@@ -4259,10 +2940,10 @@
 // Flaky on Linux. crbug.com/790929.
 #if defined(OS_ANDROID) || defined(OS_LINUX)
 #define MAYBE_FrameOwnerPropertiesPropagationScrolling \
-        DISABLED_FrameOwnerPropertiesPropagationScrolling
+  DISABLED_FrameOwnerPropertiesPropagationScrolling
 #else
 #define MAYBE_FrameOwnerPropertiesPropagationScrolling \
-        FrameOwnerPropertiesPropagationScrolling
+  FrameOwnerPropertiesPropagationScrolling
 #endif
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
                        MAYBE_FrameOwnerPropertiesPropagationScrolling) {
@@ -4292,8 +2973,8 @@
   // document will not work.
   auto has_scrollbar = [](RenderFrameHostImpl* rfh) {
     int client_width;
-    EXPECT_TRUE(ExecuteScriptAndExtractInt(rfh,
-        "window.domAutomationController.send(document.body.clientWidth);",
+    EXPECT_TRUE(ExecuteScriptAndExtractInt(
+        rfh, "window.domAutomationController.send(document.body.clientWidth);",
         &client_width));
     const int kFrameElementWidth = 200;
     return client_width < kFrameElementWidth;
@@ -4303,23 +2984,19 @@
                                    const std::string& value) {
     EXPECT_TRUE(ExecuteScript(
         parent_rfh,
-        base::StringPrintf(
-            "document.getElementById('child-1').setAttribute("
-            "    'scrolling', '%s');", value.c_str())));
+        base::StringPrintf("document.getElementById('child-1').setAttribute("
+                           "    'scrolling', '%s');",
+                           value.c_str())));
   };
 
   // Run the test over variety of parent/child cases.
-  GURL urls[] = {
-    // Remote to remote.
-    embedded_test_server()->GetURL("c.com", "/tall_page.html"),
-    // Remote to local.
-    embedded_test_server()->GetURL("a.com", "/tall_page.html"),
-    // Local to remote.
-    embedded_test_server()->GetURL("b.com", "/tall_page.html")
-  };
-  const std::string scrolling_values[] = {
-    "yes", "auto", "no"
-  };
+  GURL urls[] = {// Remote to remote.
+                 embedded_test_server()->GetURL("c.com", "/tall_page.html"),
+                 // Remote to local.
+                 embedded_test_server()->GetURL("a.com", "/tall_page.html"),
+                 // Local to remote.
+                 embedded_test_server()->GetURL("b.com", "/tall_page.html")};
+  const std::string scrolling_values[] = {"yes", "auto", "no"};
 
   for (size_t i = 0; i < arraysize(scrolling_values); ++i) {
     bool expect_scrollbar = scrolling_values[i] != "no";
@@ -4369,14 +3046,12 @@
   EXPECT_EQ("50", margin_height);
 
   // Run the test over variety of parent/child cases.
-  GURL urls[] = {
-    // Remote to remote.
-    embedded_test_server()->GetURL("c.com", "/title2.html"),
-    // Remote to local.
-    embedded_test_server()->GetURL("a.com", "/title1.html"),
-    // Local to remote.
-    embedded_test_server()->GetURL("b.com", "/title2.html")
-  };
+  GURL urls[] = {// Remote to remote.
+                 embedded_test_server()->GetURL("c.com", "/title2.html"),
+                 // Remote to local.
+                 embedded_test_server()->GetURL("a.com", "/title1.html"),
+                 // Local to remote.
+                 embedded_test_server()->GetURL("b.com", "/title2.html")};
 
   int current_margin_width = 15;
   int current_margin_height = 25;
@@ -4757,8 +3432,7 @@
 
   // Dynamically update sandbox flags for the first frame.
   EXPECT_TRUE(ExecuteScript(
-      shell(),
-      "document.querySelector('iframe').sandbox='allow-scripts';"));
+      shell(), "document.querySelector('iframe').sandbox='allow-scripts';"));
 
   // Check that updated sandbox flags are propagated to browser process.
   // The new flags should be reflected in pending_frame_policy().sandbox_flags,
@@ -5153,8 +3827,7 @@
   EXPECT_FALSE(success);
   // Change iframe's name to match the content window's name so that it can
   // reference the child frame by its new name in case of cross origin.
-  EXPECT_TRUE(
-      ExecuteScript(root, "window['3-1-id'].name = 'updated-name';"));
+  EXPECT_TRUE(ExecuteScript(root, "window['3-1-id'].name = 'updated-name';"));
   success = false;
   EXPECT_TRUE(
       ExecuteScriptAndExtractBool(shell(),
@@ -5381,8 +4054,7 @@
   // same-site; second frame should be cross-site.
   GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
   EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
-  GURL foo_url(embedded_test_server()->GetURL("foo.com",
-                                              "/post_message.html"));
+  GURL foo_url(embedded_test_server()->GetURL("foo.com", "/post_message.html"));
   EXPECT_EQ(foo_url, root->child_at(1)->current_url());
   EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
             root->child_at(1)->current_frame_host()->GetSiteInstance());
@@ -6208,8 +4880,7 @@
   // This would also be fine; however, the race in https://crbug.com/535246
   // still needs to be addressed and tested in that case.
   RenderProcessHostWatcher process_exit_observer(
-      rvh->GetProcess(),
-      RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+      rvh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
   process_exit_observer.Wait();
 
   // Verify that the RVH and RFH for A were cleaned up.
@@ -6307,8 +4978,8 @@
   EXPECT_EQ(root->child_at(0), root->frame_tree()->GetFocusedFrame());
 
   // Click on the root frame.
-  SimulateMouseClick(
-      shell()->web_contents()->GetRenderViewHost()->GetWidget(), 1, 1);
+  SimulateMouseClick(shell()->web_contents()->GetRenderViewHost()->GetWidget(),
+                     1, 1);
 
   // Check that the subframe lost focus and fired blur event on its
   // document's body.
@@ -6534,128 +5205,6 @@
   EXPECT_EQ("input", base::ToLowerASCII(activeTag));
 }
 
-// There are no cursors on Android.
-#if !defined(OS_ANDROID)
-class CursorMessageFilter : public content::BrowserMessageFilter {
- public:
-  CursorMessageFilter()
-      : content::BrowserMessageFilter(ViewMsgStart),
-        message_loop_runner_(new content::MessageLoopRunner),
-        last_set_cursor_routing_id_(MSG_ROUTING_NONE) {}
-
-  bool OnMessageReceived(const IPC::Message& message) override {
-    if (message.type() == ViewHostMsg_SetCursor::ID) {
-      content::BrowserThread::PostTask(
-          content::BrowserThread::UI, FROM_HERE,
-          base::BindOnce(&CursorMessageFilter::OnSetCursor, this,
-                         message.routing_id()));
-    }
-    return false;
-  }
-
-  void OnSetCursor(int routing_id) {
-    last_set_cursor_routing_id_ = routing_id;
-    message_loop_runner_->Quit();
-  }
-
-  int last_set_cursor_routing_id() const { return last_set_cursor_routing_id_; }
-
-  void Wait() {
-    // Do not reset the cursor, as the cursor may already have been set (and
-    // Quit() already called on |message_loop_runner_|).
-    message_loop_runner_->Run();
-  }
-
- private:
-  ~CursorMessageFilter() override {}
-
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-  int last_set_cursor_routing_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(CursorMessageFilter);
-};
-
-// Verify that we receive a mouse cursor update message when we mouse over
-// a text field contained in an out-of-process iframe.
-#if defined(OS_ANDROID)
-// Android does not have mouse cursors.
-#define MAYBE_CursorUpdateReceivedFromCrossSiteIframe \
-  DISABLED_CursorUpdateReceivedFromCrossSiteIframe
-#else
-#define MAYBE_CursorUpdateReceivedFromCrossSiteIframe \
-  CursorUpdateReceivedCrossSiteIframe
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       MAYBE_CursorUpdateReceivedFromCrossSiteIframe) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-
-  FrameTreeNode* child_node = root->child_at(0);
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  scoped_refptr<CursorMessageFilter> filter = new CursorMessageFilter();
-  child_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHost* rwh_child =
-      root->child_at(0)->current_frame_host()->GetRenderWidgetHost();
-  RenderWidgetHostViewBase* child_view =
-      static_cast<RenderWidgetHostViewBase*>(rwh_child->GetView());
-
-  // This should only return nullptr on Android.
-  EXPECT_TRUE(root_view->GetCursorManager());
-
-  WebCursor cursor;
-  EXPECT_FALSE(
-      root_view->GetCursorManager()->GetCursorForTesting(root_view, cursor));
-  EXPECT_FALSE(
-      root_view->GetCursorManager()->GetCursorForTesting(child_view, cursor));
-
-  // Send a MouseMove to the subframe. The frame contains text, and moving the
-  // mouse over it should cause the renderer to send a mouse cursor update.
-  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseMove,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  mouse_event.SetPositionInWidget(60, 60);
-  auto* router = web_contents()->GetInputEventRouter();
-  RouteMouseEventAndWaitUntilDispatch(router, root_view, child_view,
-                                      &mouse_event);
-
-  // CursorMessageFilter::Wait() implicitly tests whether we receive a
-  // ViewHostMsg_SetCursor message from the renderer process, because it does
-  // does not return otherwise.
-  filter->Wait();
-  EXPECT_EQ(filter->last_set_cursor_routing_id(), rwh_child->GetRoutingID());
-
-  // Yield to ensure that the SetCursor message is processed by its real
-  // handler.
-  {
-    base::RunLoop loop;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  loop.QuitClosure());
-    loop.Run();
-  }
-
-  // The |root_view| ends up getting a mouse-leave event, causing it to send an
-  // updated cursor for the view.
-  EXPECT_TRUE(
-      root_view->GetCursorManager()->GetCursorForTesting(root_view, cursor));
-  EXPECT_TRUE(
-      root_view->GetCursorManager()->GetCursorForTesting(child_view, cursor));
-  // Since this moused over a text box, this should not be the default cursor.
-  CursorInfo cursor_info;
-  cursor.GetCursorInfo(&cursor_info);
-  EXPECT_EQ(cursor_info.type, blink::WebCursorInfo::kTypeIBeam);
-}
-#endif
-
 // Tests that we are using the correct RenderFrameProxy when navigating an
 // opener window.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenerSetLocation) {
@@ -6677,1322 +5226,6 @@
   EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), cross_url);
 }
 
-#if defined(USE_AURA)
-// Browser process hit testing is not implemented on Android, and these tests
-// require Aura for RenderWidgetHostViewAura::OnTouchEvent().
-// https://crbug.com/491334
-
-// Ensure that scroll events can be cancelled with a wheel handler.
-// https://crbug.com/698195
-
-class SitePerProcessMouseWheelBrowserTest : public SitePerProcessBrowserTest {
- public:
-  SitePerProcessMouseWheelBrowserTest() : rwhv_root_(nullptr) {}
-
-  void SetupWheelAndScrollHandlers(content::RenderFrameHostImpl* rfh) {
-    // Set up event handlers. The wheel event handler calls prevent default on
-    // alternate events, so only every other wheel generates a scroll. The fact
-    // that any scroll events fire is dependent on the event going to the main
-    // thread, which requires the nonFastScrollableRegion be set correctly
-    // on the compositor.
-    std::string script =
-        "wheel_count = 0;"
-        "function wheel_handler(e) {"
-        "  wheel_count++;"
-        "  if (wheel_count % 2 == 0)"
-        "    e.preventDefault();\n"
-        "  domAutomationController.send('wheel: ' + wheel_count);"
-        "}"
-        "function scroll_handler(e) {"
-        "  domAutomationController.send('scroll: ' + wheel_count);"
-        "}"
-        "scroll_div = document.getElementById('scrollable_div');"
-        "scroll_div.addEventListener('wheel', wheel_handler);"
-        "scroll_div.addEventListener('scroll', scroll_handler);"
-        "document.body.style.background = 'black';";
-
-    content::DOMMessageQueue msg_queue;
-    std::string reply;
-    EXPECT_TRUE(ExecuteScript(rfh, script));
-
-    // Wait until renderer's compositor thread is synced. Otherwise the event
-    // handler won't be installed when the event arrives.
-    {
-      MainThreadFrameObserver observer(rfh->GetRenderWidgetHost());
-      observer.Wait();
-    }
-  }
-
-  void SendMouseWheel(gfx::Point location) {
-    DCHECK(rwhv_root_);
-    ui::ScrollEvent scroll_event(ui::ET_SCROLL, location, ui::EventTimeForNow(),
-                                 0, 0, -ui::MouseWheelEvent::kWheelDelta, 0,
-                                 ui::MouseWheelEvent::kWheelDelta,
-                                 2);  // This must be '2' or it gets silently
-                                      // dropped.
-    rwhv_root_->OnScrollEvent(&scroll_event);
-  }
-
-  void set_rwhv_root(RenderWidgetHostViewAura* rwhv_root) {
-    rwhv_root_ = rwhv_root;
-  }
-
-  void RunTest(gfx::Point pos, RenderWidgetHostViewBase* expected_target) {
-    content::DOMMessageQueue msg_queue;
-    std::string reply;
-
-    auto* rwhv_root = static_cast<RenderWidgetHostViewAura*>(
-        web_contents()->GetRenderWidgetHostView());
-    set_rwhv_root(rwhv_root);
-
-    InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
-                               blink::WebInputEvent::kMouseWheel);
-    SendMouseWheel(pos);
-    waiter.Wait();
-
-    // Expect both wheel and scroll handlers to fire.
-    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
-    EXPECT_EQ("\"wheel: 1\"", reply);
-    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
-    EXPECT_EQ("\"scroll: 1\"", reply);
-
-    SendMouseWheel(pos);
-
-    // If async_wheel_events is disabled, this time only the wheel handler
-    // fires, since even numbered scrolls are prevent-defaulted. If it is
-    // enabled, then this wheel event will be sent non-blockingly and won't be
-    // cancellable.
-    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
-    EXPECT_EQ("\"wheel: 2\"", reply);
-    if (base::FeatureList::IsEnabled(features::kAsyncWheelEvents) &&
-        base::FeatureList::IsEnabled(
-            features::kTouchpadAndWheelScrollLatching)) {
-      EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
-      EXPECT_EQ("\"scroll: 2\"", reply);
-    }
-
-    SendMouseWheel(pos);
-
-    // Odd number of wheels, expect both wheel and scroll handlers to fire
-    // again.
-    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
-    EXPECT_EQ("\"wheel: 3\"", reply);
-    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
-    EXPECT_EQ("\"scroll: 3\"", reply);
-  }
-
- private:
-  RenderWidgetHostViewAura* rwhv_root_;
-};
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessMouseWheelBrowserTest,
-                       SubframeWheelEventsOnMainThread) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  GURL frame_url(embedded_test_server()->GetURL(
-      "b.com", "/page_with_scrollable_div.html"));
-  NavigateFrameToURL(root->child_at(0), frame_url);
-
-  // Synchronize with the child and parent renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
-      root->child_at(0)->current_frame_host()->GetView());
-  WaitForChildFrameSurfaceReady(root->child_at(0)->current_frame_host());
-
-  content::RenderFrameHostImpl* child = root->child_at(0)->current_frame_host();
-  SetupWheelAndScrollHandlers(child);
-
-  gfx::Rect bounds = child_rwhv->GetViewBounds();
-  gfx::Point pos(bounds.x() + 10, bounds.y() + 10);
-
-  RunTest(pos, child_rwhv);
-}
-
-// Verifies that test in SubframeWheelEventsOnMainThread also makes sense for
-// the same page loaded in the mainframe.
-IN_PROC_BROWSER_TEST_F(SitePerProcessMouseWheelBrowserTest,
-                       MainframeWheelEventsOnMainThread) {
-  GURL main_url(
-      embedded_test_server()->GetURL("/page_with_scrollable_div.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  content::RenderFrameHostImpl* rfhi = root->current_frame_host();
-  SetupWheelAndScrollHandlers(rfhi);
-
-  gfx::Point pos(10, 10);
-
-  RunTest(pos, rfhi->GetRenderWidgetHost()->GetView());
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessMouseWheelBrowserTest,
-                       InputEventRouterWheelTargetTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-  auto* rwhv_root = static_cast<RenderWidgetHostViewAura*>(
-      web_contents()->GetRenderWidgetHostView());
-  set_rwhv_root(rwhv_root);
-
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  GURL frame_url(embedded_test_server()->GetURL(
-      "b.com", "/page_with_scrollable_div.html"));
-  NavigateFrameToURL(root->child_at(0), frame_url);
-
-  // Synchronize with the child and parent renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
-      root->child_at(0)->current_frame_host()->GetView());
-  WaitForChildFrameSurfaceReady(root->child_at(0)->current_frame_host());
-
-  RenderWidgetHostInputEventRouter* router =
-      web_contents()->GetInputEventRouter();
-
-  // Send a mouse wheel event to child.
-  gfx::Rect bounds = child_rwhv->GetViewBounds();
-  gfx::Point pos(bounds.x() + 10, bounds.y() + 10);
-  InputEventAckWaiter waiter(child_rwhv->GetRenderWidgetHost(),
-                             blink::WebInputEvent::kMouseWheel);
-  SendMouseWheel(pos);
-  waiter.Wait();
-
-  if (child_rwhv->wheel_scroll_latching_enabled())
-    EXPECT_EQ(child_rwhv, router->wheel_target_.target);
-  else
-    EXPECT_EQ(nullptr, router->wheel_target_.target);
-
-  // Send a mouse wheel event to the main frame. If wheel scroll latching is
-  // enabled it will be still routed to child till the end of current scrolling
-  // sequence. Since wheel scroll latching is enabled by default, we always do
-  // sync targeting so InputEventAckWaiter is not needed here.
-  TestInputEventObserver child_frame_monitor(child_rwhv->GetRenderWidgetHost());
-  SendMouseWheel(pos);
-  if (child_rwhv->wheel_scroll_latching_enabled())
-    EXPECT_EQ(child_rwhv, router->wheel_target_.target);
-  else
-    EXPECT_EQ(nullptr, router->wheel_target_.target);
-  // Verify that this a mouse wheel event was sent to the child frame renderer.
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-  EXPECT_EQ(child_frame_monitor.EventType(), blink::WebInputEvent::kMouseWheel);
-
-  // Kill the wheel target view process. This must reset the wheel_target_.
-  RenderProcessHost* child_process =
-      root->child_at(0)->current_frame_host()->GetProcess();
-  RenderProcessHostWatcher crash_observer(
-      child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-  child_process->Shutdown(0, false);
-  crash_observer.Wait();
-  EXPECT_EQ(nullptr, router->wheel_target_.target);
-}
-
-// Ensure that a cross-process subframe with a touch-handler can receive touch
-// events.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframeTouchEventRouting) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  WebContentsImpl* contents = web_contents();
-  FrameTreeNode* root = contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  GURL frame_url(
-      embedded_test_server()->GetURL("b.com", "/page_with_touch_handler.html"));
-  NavigateFrameToURL(root->child_at(0), frame_url);
-
-  // Synchronize with the child and parent renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  WaitForChildFrameSurfaceReady(root->child_at(0)->current_frame_host());
-
-  // There's no intrinsic reason the following values can't be equal, but they
-  // aren't at present, and if they become the same this test will need to be
-  // updated to accommodate.
-  EXPECT_NE(cc::kTouchActionAuto, cc::kTouchActionNone);
-
-  // Verify the child's input router is initially set for kTouchActionAuto. The
-  // TouchStart event will trigger kTouchActionNone being sent back to the
-  // browser.
-  RenderWidgetHostImpl* child_render_widget_host =
-      root->child_at(0)->current_frame_host()->GetRenderWidgetHost();
-  EXPECT_EQ(cc::kTouchActionAuto,
-            child_render_widget_host->input_router()->AllowedTouchAction());
-
-  InputEventAckWaiter waiter(child_render_widget_host,
-                             blink::WebInputEvent::kTouchStart);
-
-  // Simulate touch event to sub-frame.
-  gfx::Point child_center(150, 150);
-  auto* rwhv = static_cast<RenderWidgetHostViewAura*>(
-      contents->GetRenderWidgetHostView());
-
-  // Wait until renderer's compositor thread is synced.
-  {
-    MainThreadFrameObserver observer(child_render_widget_host);
-    observer.Wait();
-  }
-
-  ui::TouchEvent touch_event(
-      ui::ET_TOUCH_PRESSED, child_center, ui::EventTimeForNow(),
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
-                         /* pointer_id*/ 0,
-                         /* radius_x */ 30.0f,
-                         /* radius_y */ 30.0f,
-                         /* force */ 0.0f));
-  rwhv->OnTouchEvent(&touch_event);
-  waiter.Wait();
-  {
-    MainThreadFrameObserver observer(child_render_widget_host);
-    observer.Wait();
-  }
-
-  // Verify touch handler in subframe was invoked.
-  std::string result;
-  EXPECT_TRUE(ExecuteScriptAndExtractString(
-      root->child_at(0),
-      "window.domAutomationController.send(getLastTouchEvent());", &result));
-  EXPECT_EQ("touchstart", result);
-
-  // Verify the presence of the touch handler in the child frame correctly
-  // propagates touch-action:none information back to the child's input router.
-  EXPECT_EQ(cc::kTouchActionNone,
-            child_render_widget_host->input_router()->AllowedTouchAction());
-}
-
-// This test verifies that the test in
-// SitePerProcessBrowserTest.SubframeTouchEventRouting also works properly for
-// the main frame. Prior to the CL in which this test is introduced, use of
-// MainThreadFrameObserver in SubframeTouchEventRouting was not necessary since
-// the touch events were handled on the main thread. Now they are handled on the
-// compositor thread, hence the need to synchronize.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       MainframeTouchEventRouting) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/page_with_touch_handler.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  WebContentsImpl* contents = web_contents();
-  FrameTreeNode* root = contents->GetFrameTree()->root();
-
-  // Synchronize with the renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  auto* rwhv = static_cast<RenderWidgetHostViewAura*>(
-      contents->GetRenderWidgetHostView());
-
-  // There's no intrinsic reason the following values can't be equal, but they
-  // aren't at present, and if they become the same this test will need to be
-  // updated to accommodate.
-  EXPECT_NE(cc::kTouchActionAuto, cc::kTouchActionNone);
-
-  // Verify the main frame's input router is initially set for
-  // kTouchActionAuto. The
-  // TouchStart event will trigger kTouchActionNone being sent back to the
-  // browser.
-  RenderWidgetHostImpl* render_widget_host =
-      root->current_frame_host()->GetRenderWidgetHost();
-  EXPECT_EQ(cc::kTouchActionAuto,
-            render_widget_host->input_router()->AllowedTouchAction());
-
-  // Simulate touch event to sub-frame.
-  gfx::Point frame_center(150, 150);
-
-  // Wait until renderer's compositor thread is synced.
-  {
-    auto observer =
-        std::make_unique<MainThreadFrameObserver>(render_widget_host);
-    observer->Wait();
-  }
-
-  ui::TouchEvent touch_event(
-      ui::ET_TOUCH_PRESSED, frame_center, ui::EventTimeForNow(),
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
-                         /* pointer_id*/ 0,
-                         /* radius_x */ 30.0f,
-                         /* radius_y */ 30.0f,
-                         /* force */ 0.0f));
-  rwhv->OnTouchEvent(&touch_event);
-  {
-    auto observer =
-        std::make_unique<MainThreadFrameObserver>(render_widget_host);
-    observer->Wait();
-  }
-
-  // Verify touch handler in subframe was invoked.
-  std::string result;
-  EXPECT_TRUE(ExecuteScriptAndExtractString(
-      root, "window.domAutomationController.send(getLastTouchEvent());",
-      &result));
-  EXPECT_EQ("touchstart", result);
-
-  // Verify the presence of the touch handler in the child frame correctly
-  // propagates touch-action:none information back to the child's input router.
-  EXPECT_EQ(cc::kTouchActionNone,
-            render_widget_host->input_router()->AllowedTouchAction());
-}
-
-namespace {
-
-// Declared here to be close to the SubframeGestureEventRouting test.
-void OnSyntheticGestureCompleted(scoped_refptr<MessageLoopRunner> runner,
-                                 SyntheticGesture::Result result) {
-  EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
-  runner->Quit();
-}
-
-}  // anonymous namespace
-
-// https://crbug.com/592320
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       DISABLED_SubframeGestureEventRouting) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  GURL frame_url(
-      embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
-  NavigateFrameToURL(root->child_at(0), frame_url);
-  auto* child_frame_host = root->child_at(0)->current_frame_host();
-
-  // Synchronize with the child and parent renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  WaitForChildFrameSurfaceReady(child_frame_host);
-
-  // There have been no GestureTaps sent yet.
-  {
-    std::string result;
-    EXPECT_TRUE(ExecuteScriptAndExtractString(
-        child_frame_host,
-        "window.domAutomationController.send(getClickStatus());", &result));
-    EXPECT_EQ("0 clicks received", result);
-  }
-
-  // Simulate touch sequence to send GestureTap to sub-frame.
-  SyntheticTapGestureParams params;
-  params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
-  gfx::Point center(150, 150);
-  params.position = gfx::PointF(center.x(), center.y());
-  params.duration_ms = 100;
-  std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params));
-
-  scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner();
-
-  RenderWidgetHostImpl* render_widget_host =
-      root->current_frame_host()->GetRenderWidgetHost();
-  // TODO(wjmaclean): Convert the call to base::Bind() to a lambda someday.
-  render_widget_host->QueueSyntheticGesture(
-      std::move(gesture), base::BindOnce(OnSyntheticGestureCompleted, runner));
-
-  // We need to run the message loop while we wait for the synthetic gesture
-  // to be processed; the callback registered above will get us out of the
-  // message loop when that happens.
-  runner->Run();
-  runner = nullptr;
-
-  // Verify click handler in subframe was invoked
-  {
-    std::string result;
-    EXPECT_TRUE(ExecuteScriptAndExtractString(
-        child_frame_host,
-        "window.domAutomationController.send(getClickStatus());", &result));
-    EXPECT_EQ("1 click received", result);
-  }
-}
-
-namespace {
-
-// Defined here to be close to
-// SitePerProcessBrowserTest.InputEventRouterGestureTargetQueueTest.
-// Will wait for RenderWidgetHost's compositor thread to sync if one is given.
-// Returns the unique_touch_id of the TouchStart.
-uint32_t SendTouchTapWithExpectedTarget(
-    RenderWidgetHostViewBase* root_view,
-    const gfx::Point& touch_point,
-    RenderWidgetHostViewBase*& router_touch_target,
-    const RenderWidgetHostViewBase* expected_target,
-    RenderWidgetHostImpl* child_render_widget_host) {
-  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
-  if (child_render_widget_host != nullptr) {
-    MainThreadFrameObserver observer(child_render_widget_host);
-    observer.Wait();
-  }
-  ui::TouchEvent touch_event_pressed(
-      ui::ET_TOUCH_PRESSED, touch_point, ui::EventTimeForNow(),
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
-                         /* pointer_id*/ 0,
-                         /* radius_x */ 30.0f,
-                         /* radius_y */ 30.0f,
-                         /* force */ 0.0f));
-  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
-                             blink::WebInputEvent::kTouchStart);
-  root_view_aura->OnTouchEvent(&touch_event_pressed);
-  if (child_render_widget_host != nullptr) {
-    MainThreadFrameObserver observer(child_render_widget_host);
-    observer.Wait();
-  }
-  waiter.Wait();
-  EXPECT_EQ(expected_target, router_touch_target);
-  ui::TouchEvent touch_event_released(
-      ui::ET_TOUCH_RELEASED, touch_point, ui::EventTimeForNow(),
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
-                         /* pointer_id*/ 0,
-                         /* radius_x */ 30.0f,
-                         /* radius_y */ 30.0f,
-                         /* force */ 0.0f));
-  root_view_aura->OnTouchEvent(&touch_event_released);
-  if (child_render_widget_host != nullptr) {
-    MainThreadFrameObserver observer(child_render_widget_host);
-    observer.Wait();
-  }
-  EXPECT_EQ(nullptr, router_touch_target);
-  return touch_event_pressed.unique_event_id();
-}
-
-void SendGestureTapSequenceWithExpectedTarget(
-    RenderWidgetHostViewBase* root_view,
-    const gfx::Point& gesture_point,
-    RenderWidgetHostViewBase*& router_gesture_target,
-    const RenderWidgetHostViewBase* old_expected_target,
-    const RenderWidgetHostViewBase* expected_target,
-    const uint32_t unique_touch_event_id) {
-  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
-
-  ui::GestureEventDetails gesture_begin_details(ui::ET_GESTURE_BEGIN);
-  gesture_begin_details.set_device_type(
-      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-  ui::GestureEvent gesture_begin_event(
-      gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
-      gesture_begin_details, unique_touch_event_id);
-  root_view_aura->OnGestureEvent(&gesture_begin_event);
-  // We expect to still have the old gesture target in place for the
-  // GestureFlingCancel that will be inserted before GestureTapDown.
-  // Note: the GestureFlingCancel is inserted by RenderWidgetHostViewAura::
-  // OnGestureEvent() when it sees ui::ET_GESTURE_TAP_DOWN, so we don't
-  // explicitly add it here.
-  EXPECT_EQ(old_expected_target, router_gesture_target);
-
-  ui::GestureEventDetails gesture_tap_down_details(ui::ET_GESTURE_TAP_DOWN);
-  gesture_tap_down_details.set_device_type(
-      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-  ui::GestureEvent gesture_tap_down_event(
-      gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
-      gesture_tap_down_details, unique_touch_event_id);
-  root_view_aura->OnGestureEvent(&gesture_tap_down_event);
-  EXPECT_EQ(expected_target, router_gesture_target);
-
-  ui::GestureEventDetails gesture_show_press_details(ui::ET_GESTURE_SHOW_PRESS);
-  gesture_show_press_details.set_device_type(
-      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-  ui::GestureEvent gesture_show_press_event(
-      gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
-      gesture_show_press_details, unique_touch_event_id);
-  root_view_aura->OnGestureEvent(&gesture_show_press_event);
-  EXPECT_EQ(expected_target, router_gesture_target);
-
-  ui::GestureEventDetails gesture_tap_details(ui::ET_GESTURE_TAP);
-  gesture_tap_details.set_device_type(
-      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-  gesture_tap_details.set_tap_count(1);
-  ui::GestureEvent gesture_tap_event(gesture_point.x(), gesture_point.y(), 0,
-                                     ui::EventTimeForNow(), gesture_tap_details,
-                                     unique_touch_event_id);
-  root_view_aura->OnGestureEvent(&gesture_tap_event);
-  EXPECT_EQ(expected_target, router_gesture_target);
-
-  ui::GestureEventDetails gesture_end_details(ui::ET_GESTURE_END);
-  gesture_end_details.set_device_type(
-      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-  ui::GestureEvent gesture_end_event(gesture_point.x(), gesture_point.y(), 0,
-                                     ui::EventTimeForNow(), gesture_end_details,
-                                     unique_touch_event_id);
-  root_view_aura->OnGestureEvent(&gesture_end_event);
-  EXPECT_EQ(expected_target, router_gesture_target);
-}
-
-void SendTouchpadPinchSequenceWithExpectedTarget(
-    RenderWidgetHostViewBase* root_view,
-    const gfx::Point& gesture_point,
-    RenderWidgetHostViewBase*& router_touchpad_gesture_target,
-    RenderWidgetHostViewBase* expected_target) {
-  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
-
-  ui::GestureEventDetails pinch_begin_details(ui::ET_GESTURE_PINCH_BEGIN);
-  pinch_begin_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
-  ui::GestureEvent pinch_begin(gesture_point.x(), gesture_point.y(), 0,
-                               ui::EventTimeForNow(), pinch_begin_details);
-  TestInputEventObserver target_monitor(expected_target->GetRenderWidgetHost());
-  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
-                             blink::WebInputEvent::kGesturePinchBegin);
-  root_view_aura->OnGestureEvent(&pinch_begin);
-  // If the expected target is not the root, then we should be doing async
-  // targeting first. So event dispatch should not happen synchronously.
-  // Validate that the expected target does not receive the event immediately in
-  // such cases.
-  if (root_view != expected_target)
-    EXPECT_FALSE(target_monitor.EventWasReceived());
-  waiter.Wait();
-  EXPECT_TRUE(target_monitor.EventWasReceived());
-  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
-  target_monitor.ResetEventsReceived();
-
-  ui::GestureEventDetails pinch_update_details(ui::ET_GESTURE_PINCH_UPDATE);
-  pinch_update_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
-  ui::GestureEvent pinch_update(gesture_point.x(), gesture_point.y(), 0,
-                                ui::EventTimeForNow(), pinch_update_details);
-  root_view_aura->OnGestureEvent(&pinch_update);
-  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
-  EXPECT_TRUE(target_monitor.EventWasReceived());
-  EXPECT_EQ(target_monitor.EventType(),
-            blink::WebInputEvent::kGesturePinchUpdate);
-  target_monitor.ResetEventsReceived();
-
-  ui::GestureEventDetails pinch_end_details(ui::ET_GESTURE_PINCH_END);
-  pinch_end_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
-  ui::GestureEvent pinch_end(gesture_point.x(), gesture_point.y(), 0,
-                             ui::EventTimeForNow(), pinch_end_details);
-  root_view_aura->OnGestureEvent(&pinch_end);
-  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
-  EXPECT_TRUE(target_monitor.EventWasReceived());
-  EXPECT_EQ(target_monitor.EventType(), blink::WebInputEvent::kGesturePinchEnd);
-}
-
-#if !defined(OS_WIN)
-// Sending touchpad fling events is not supported on Windows.
-void SendTouchpadFlingSequenceWithExpectedTarget(
-    RenderWidgetHostViewBase* root_view,
-    const gfx::Point& gesture_point,
-    RenderWidgetHostViewBase*& router_touchpad_gesture_target,
-    RenderWidgetHostViewBase* expected_target) {
-  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
-
-  if (root_view_aura->wheel_scroll_latching_enabled()) {
-    // Touchpad Fling must be sent inside a gesture scroll seqeunce.
-    blink::WebGestureEvent gesture_event(
-        blink::WebGestureEvent::kGestureScrollBegin,
-        blink::WebInputEvent::kNoModifiers,
-        blink::WebInputEvent::kTimeStampForTesting);
-    gesture_event.source_device = blink::kWebGestureDeviceTouchpad;
-    gesture_event.x = gesture_point.x();
-    gesture_event.y = gesture_point.y();
-    gesture_event.data.scroll_begin.delta_x_hint = 0.0f;
-    gesture_event.data.scroll_begin.delta_y_hint = 1.0f;
-    expected_target->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event);
-  }
-
-  ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gesture_point,
-                              ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1);
-  TestInputEventObserver target_monitor(expected_target->GetRenderWidgetHost());
-  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
-                             blink::WebInputEvent::kGestureFlingStart);
-  root_view_aura->OnScrollEvent(&fling_start);
-  // If the expected target is not the root, then we should be doing async
-  // targeting first. So event dispatch should not happen synchronously.
-  // Validate that the expected target does not receive the event immediately in
-  // such cases.
-  if (root_view != expected_target)
-    EXPECT_FALSE(target_monitor.EventWasReceived());
-  waiter.Wait();
-  EXPECT_TRUE(target_monitor.EventWasReceived());
-  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
-  target_monitor.ResetEventsReceived();
-
-  ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, gesture_point,
-                               ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1);
-  root_view_aura->OnScrollEvent(&fling_cancel);
-  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
-  EXPECT_TRUE(target_monitor.EventWasReceived());
-  EXPECT_EQ(target_monitor.EventType(),
-            blink::WebInputEvent::kGestureFlingCancel);
-
-  if (root_view_aura->wheel_scroll_latching_enabled()) {
-    blink::WebGestureEvent gesture_event(
-        blink::WebGestureEvent::kGestureScrollEnd,
-        blink::WebInputEvent::kNoModifiers,
-        blink::WebInputEvent::kTimeStampForTesting);
-    gesture_event.source_device = blink::kWebGestureDeviceTouchpad;
-    gesture_event.x = gesture_point.x();
-    gesture_event.y = gesture_point.y();
-    expected_target->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event);
-  }
-}
-#endif
-
-}  // anonymous namespace
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       InputEventRouterGestureTargetMapTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  WebContentsImpl* contents = web_contents();
-  FrameTreeNode* root = contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  GURL frame_url(
-      embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
-  NavigateFrameToURL(root->child_at(0), frame_url);
-  auto* child_frame_host = root->child_at(0)->current_frame_host();
-  auto* rwhv_child =
-      static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView());
-
-  // Synchronize with the child and parent renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  WaitForChildFrameSurfaceReady(child_frame_host);
-
-  // All touches & gestures are sent to the main frame's view, and should be
-  // routed appropriately from there.
-  auto* rwhv_parent = static_cast<RenderWidgetHostViewBase*>(
-      contents->GetRenderWidgetHostView());
-
-  RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
-  EXPECT_TRUE(router->touchscreen_gesture_target_map_.empty());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send touch sequence to main-frame.
-  gfx::Point main_frame_point(25, 25);
-  uint32_t firstId = SendTouchTapWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
-      nullptr);
-  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send touch sequence to child.
-  gfx::Point child_center(150, 150);
-  uint32_t secondId = SendTouchTapWithExpectedTarget(
-      rwhv_parent, child_center, router->touch_target_.target, rwhv_child,
-      nullptr);
-  EXPECT_EQ(2u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send another touch sequence to main frame.
-  uint32_t thirdId = SendTouchTapWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
-      nullptr);
-  EXPECT_EQ(3u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send Gestures to clear GestureTargetQueue.
-
-  // The first touch sequence should generate a GestureTapDown, sent to the
-  // main frame.
-  SendGestureTapSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
-      nullptr, rwhv_parent, firstId);
-  EXPECT_EQ(2u, router->touchscreen_gesture_target_map_.size());
-  // Note: rwhv_parent is the target used for GestureFlingCancel sent by
-  // RenderWidgetHostViewAura::OnGestureEvent() at the start of the next gesture
-  // sequence; the sequence itself goes to rwhv_child.
-  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
-
-  // The second touch sequence should generate a GestureTapDown, sent to the
-  // child frame.
-  SendGestureTapSequenceWithExpectedTarget(
-      rwhv_parent, child_center, router->touchscreen_gesture_target_.target,
-      rwhv_parent, rwhv_child, secondId);
-  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(rwhv_child, router->touchscreen_gesture_target_.target);
-
-  // The third touch sequence should generate a GestureTapDown, sent to the
-  // main frame.
-  SendGestureTapSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
-      rwhv_child, rwhv_parent, thirdId);
-  EXPECT_EQ(0u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
-}
-
-// TODO: Flaking test crbug.com/802827
-#if defined(OS_WIN)
-#define MAYBE_InputEventRouterGesturePreventDefaultTargetMapTest \
-  DISABLED_InputEventRouterGesturePreventDefaultTargetMapTest
-#else
-#define MAYBE_InputEventRouterGesturePreventDefaultTargetMapTest \
-  InputEventRouterGesturePreventDefaultTargetMapTest
-#endif
-#if defined(USE_AURA) || defined(OS_ANDROID)
-IN_PROC_BROWSER_TEST_F(
-    SitePerProcessBrowserTest,
-    MAYBE_InputEventRouterGesturePreventDefaultTargetMapTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  WebContentsImpl* contents = web_contents();
-  FrameTreeNode* root = contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  GURL frame_url(embedded_test_server()->GetURL(
-      "b.com", "/page_with_touch_start_default_prevented.html"));
-  NavigateFrameToURL(root->child_at(0), frame_url);
-
-  auto* child_frame_host = root->child_at(0)->current_frame_host();
-  RenderWidgetHostImpl* child_render_widget_host =
-      child_frame_host->GetRenderWidgetHost();
-  auto* rwhv_child =
-      static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView());
-
-  // Synchronize with the child and parent renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  WaitForChildFrameSurfaceReady(child_frame_host);
-
-  // All touches & gestures are sent to the main frame's view, and should be
-  // routed appropriately from there.
-  auto* rwhv_parent = static_cast<RenderWidgetHostViewBase*>(
-      contents->GetRenderWidgetHostView());
-
-  RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
-  EXPECT_TRUE(router->touchscreen_gesture_target_map_.empty());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send touch sequence to main-frame.
-  gfx::Point main_frame_point(25, 25);
-  uint32_t firstId = SendTouchTapWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
-      child_render_widget_host);
-  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send touch sequence to child.
-  gfx::Point child_center(150, 150);
-  SendTouchTapWithExpectedTarget(rwhv_parent, child_center,
-                                 router->touch_target_.target, rwhv_child,
-                                 child_render_widget_host);
-  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send another touch sequence to main frame.
-  uint32_t thirdId = SendTouchTapWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
-      child_render_widget_host);
-  EXPECT_EQ(2u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
-
-  // Send Gestures to clear GestureTargetQueue.
-
-  // The first touch sequence should generate a GestureTapDown, sent to the
-  // main frame.
-  SendGestureTapSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
-      nullptr, rwhv_parent, firstId);
-  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
-  // Note: rwhv_parent is the target used for GestureFlingCancel sent by
-  // RenderWidgetHostViewAura::OnGestureEvent() at the start of the next gesture
-  // sequence; the sequence itself goes to rwhv_child.
-  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
-
-  // The third touch sequence should generate a GestureTapDown, sent to the
-  // main frame.
-  SendGestureTapSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
-      rwhv_parent, rwhv_parent, thirdId);
-  EXPECT_EQ(0u, router->touchscreen_gesture_target_map_.size());
-  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
-}
-#endif
-
-// Disabled for flakiness: https://crbug.com/802085.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       DISABLED_InputEventRouterTouchpadGestureTargetTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  WebContentsImpl* contents = web_contents();
-  FrameTreeNode* root = contents->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  GURL frame_url(
-      embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
-  NavigateFrameToURL(root->child_at(0), frame_url);
-  auto* child_frame_host = root->child_at(0)->current_frame_host();
-
-  // Synchronize with the child and parent renderers to guarantee that the
-  // surface information required for event hit testing is ready.
-  auto* rwhv_child =
-      static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView());
-  WaitForChildFrameSurfaceReady(child_frame_host);
-
-  // All touches & gestures are sent to the main frame's view, and should be
-  // routed appropriately from there.
-  auto* rwhv_parent = static_cast<RenderWidgetHostViewBase*>(
-      contents->GetRenderWidgetHostView());
-
-  RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
-  EXPECT_EQ(nullptr, router->touchpad_gesture_target_.target);
-
-  gfx::Point main_frame_point(25, 25);
-  gfx::Point child_center(150, 150);
-
-  // Send touchpad pinch sequence to main-frame.
-  SendTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
-      rwhv_parent);
-
-  // Send touchpad pinch sequence to child.
-  SendTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, child_center, router->touchpad_gesture_target_.target,
-      rwhv_child);
-
-  // Send another touchpad pinch sequence to main frame.
-  SendTouchpadPinchSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
-      rwhv_parent);
-
-#if !defined(OS_WIN)
-  // Sending touchpad fling events is not supported on Windows.
-
-  // Send touchpad fling sequence to main-frame.
-  SendTouchpadFlingSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
-      rwhv_parent);
-
-  // Send touchpad fling sequence to child.
-  SendTouchpadFlingSequenceWithExpectedTarget(
-      rwhv_parent, child_center, router->touchpad_gesture_target_.target,
-      rwhv_child);
-
-  // Send another touchpad fling sequence to main frame.
-  SendTouchpadFlingSequenceWithExpectedTarget(
-      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
-      rwhv_parent);
-#endif
-}
-#endif  // defined(USE_AURA)
-
-// A WebContentsDelegate to capture ContextMenu creation events.
-class ContextMenuObserverDelegate : public WebContentsDelegate {
- public:
-  ContextMenuObserverDelegate()
-      : context_menu_created_(false),
-        message_loop_runner_(new MessageLoopRunner) {}
-
-  ~ContextMenuObserverDelegate() override {}
-
-  bool HandleContextMenu(const content::ContextMenuParams& params) override {
-    context_menu_created_ = true;
-    menu_params_ = params;
-    message_loop_runner_->Quit();
-    return true;
-  }
-
-  ContextMenuParams getParams() { return menu_params_; }
-
-  void Wait() {
-    if (!context_menu_created_)
-      message_loop_runner_->Run();
-    context_menu_created_ = false;
-  }
-
- private:
-  bool context_menu_created_;
-  ContextMenuParams menu_params_;
-
-  // The MessageLoopRunner used to spin the message loop.
-  scoped_refptr<MessageLoopRunner> message_loop_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContextMenuObserverDelegate);
-};
-
-// Helper function to run the CreateContextMenuTest in either normal
-// or high DPI mode.
-void CreateContextMenuTestHelper(
-    Shell* shell,
-    net::test_server::EmbeddedTestServer* embedded_test_server) {
-  GURL main_url(embedded_test_server->GetURL(
-      "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_TRUE(NavigateToURL(shell, main_url));
-
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(site_url, child_node->current_url());
-  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  // Ensure that the child process renderer is ready to have input events
-  // routed to it. This happens when the browser process has received
-  // updated compositor surfaces from both renderer processes.
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  // A WebContentsDelegate to listen for the ShowContextMenu message.
-  ContextMenuObserverDelegate context_menu_delegate;
-  shell->web_contents()->SetDelegate(&context_menu_delegate);
-
-  RenderWidgetHostInputEventRouter* router =
-      static_cast<WebContentsImpl*>(shell->web_contents())
-          ->GetInputEventRouter();
-
-  float scale_factor = GetPageScaleFactor(shell);
-
-  gfx::Rect root_bounds = root_view->GetViewBounds();
-  gfx::Rect bounds = rwhv_child->GetViewBounds();
-
-  gfx::Point point(
-      gfx::ToCeiledInt((bounds.x() - root_bounds.x() + 5) * scale_factor),
-      gfx::ToCeiledInt((bounds.y() - root_bounds.y() + 5) * scale_factor));
-
-  // Target right-click event to child frame.
-  blink::WebMouseEvent click_event(blink::WebInputEvent::kMouseDown,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  click_event.button = blink::WebPointerProperties::Button::kRight;
-  click_event.SetPositionInWidget(point.x(), point.y());
-  click_event.click_count = 1;
-  router->RouteMouseEvent(root_view, &click_event, ui::LatencyInfo());
-
-  // We also need a MouseUp event, needed by Windows.
-  click_event.SetType(blink::WebInputEvent::kMouseUp);
-  click_event.SetPositionInWidget(point.x(), point.y());
-  router->RouteMouseEvent(root_view, &click_event, ui::LatencyInfo());
-
-  context_menu_delegate.Wait();
-
-  ContextMenuParams params = context_menu_delegate.getParams();
-
-  EXPECT_NEAR(point.x(), params.x, 2);
-  EXPECT_NEAR(point.y(), params.y, 2);
-}
-
-// Test that a mouse right-click to an out-of-process iframe causes a context
-// menu to be generated with the correct screen position.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateContextMenuTest) {
-  CreateContextMenuTestHelper(shell(), embedded_test_server());
-}
-
-// Test that a mouse right-click to an out-of-process iframe causes a context
-// menu to be generated with the correct screen position on a screen with
-// non-default scale factor.
-#if defined(OS_ANDROID) || defined(OS_WIN)
-// High DPI tests don't work properly on Android, which has fixed scale factor.
-// Windows is disabled because of https://crbug.com/545547.
-#define MAYBE_HighDPICreateContextMenuTest DISABLED_HighDPICreateContextMenuTest
-#else
-#define MAYBE_HighDPICreateContextMenuTest HighDPICreateContextMenuTest
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
-                       MAYBE_HighDPICreateContextMenuTest) {
-  CreateContextMenuTestHelper(shell(), embedded_test_server());
-}
-
-class ShowWidgetMessageFilter : public content::BrowserMessageFilter {
- public:
-  ShowWidgetMessageFilter()
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-      : content::BrowserMessageFilter(FrameMsgStart),
-#else
-      : content::BrowserMessageFilter(ViewMsgStart),
-#endif
-        message_loop_runner_(new content::MessageLoopRunner) {
-  }
-
-  bool OnMessageReceived(const IPC::Message& message) override {
-    IPC_BEGIN_MESSAGE_MAP(ShowWidgetMessageFilter, message)
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-      IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
-#else
-      IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
-#endif
-    IPC_END_MESSAGE_MAP()
-    return false;
-  }
-
-  gfx::Rect last_initial_rect() const { return initial_rect_; }
-
-  int last_routing_id() const { return routing_id_; }
-
-  void Wait() {
-    initial_rect_ = gfx::Rect();
-    routing_id_ = MSG_ROUTING_NONE;
-    message_loop_runner_->Run();
-  }
-
-  void Reset() {
-    initial_rect_ = gfx::Rect();
-    routing_id_ = MSG_ROUTING_NONE;
-    message_loop_runner_ = new content::MessageLoopRunner;
-  }
-
- private:
-  ~ShowWidgetMessageFilter() override {}
-
-  void OnShowWidget(int route_id, const gfx::Rect& initial_rect) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::BindOnce(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
-                       route_id, initial_rect));
-  }
-
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-  void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
-                   MSG_ROUTING_NONE, params.bounds));
-  }
-#endif
-
-  void OnShowWidgetOnUI(int route_id, const gfx::Rect& initial_rect) {
-    initial_rect_ = initial_rect;
-    routing_id_ = route_id;
-    message_loop_runner_->Quit();
-  }
-
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-  gfx::Rect initial_rect_;
-  int routing_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShowWidgetMessageFilter);
-};
-
-// Test that clicking a select element in an out-of-process iframe creates
-// a popup menu in the correct position.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, PopupMenuTest) {
-  GURL main_url(
-      embedded_test_server()->GetURL("/cross_site_iframe_factory.html?a(a)"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-
-#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
-  // Unused variable on Mac and Android.
-  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-#endif
-
-  FrameTreeNode* child_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL(
-      "baz.com", "/site_isolation/page-with-select.html"));
-  NavigateFrameToURL(child_node, site_url);
-
-  web_contents()->SendScreenRects();
-
-  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            child_node->current_frame_host()->GetSiteInstance());
-
-  scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter();
-  child_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
-
-  // Target left-click event to child frame.
-  blink::WebMouseEvent click_event(blink::WebInputEvent::kMouseDown,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  click_event.button = blink::WebPointerProperties::Button::kLeft;
-  click_event.SetPositionInWidget(15, 15);
-  click_event.click_count = 1;
-  rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo());
-
-  // Dismiss the popup.
-  click_event.SetPositionInWidget(1, 1);
-  rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo());
-
-  filter->Wait();
-  gfx::Rect popup_rect = filter->last_initial_rect();
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-  // On Mac and Android we receive the coordinates before they are transformed,
-  // so they are still relative to the out-of-process iframe origin.
-  EXPECT_EQ(popup_rect.x(), 9);
-  EXPECT_EQ(popup_rect.y(), 9);
-#else
-  EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
-  EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 94);
-#endif
-
-#if defined(OS_LINUX)
-  // Verify click-and-drag selection of popups still works on Linux with
-  // OOPIFs enabled. This is only necessary to test on Aura because Mac and
-  // Android use native widgets. Windows does not support this as UI
-  // convention (it requires separate clicks to open the menu and select an
-  // option). See https://crbug.com/703191.
-  int process_id = child_node->current_frame_host()->GetProcess()->GetID();
-  filter->Reset();
-  RenderWidgetHostInputEventRouter* router =
-      static_cast<WebContentsImpl*>(shell()->web_contents())
-          ->GetInputEventRouter();
-  // Re-open the select element.
-  click_event.SetPositionInWidget(360, 90);
-  click_event.click_count = 1;
-  router->RouteMouseEvent(rwhv_root, &click_event, ui::LatencyInfo());
-
-  filter->Wait();
-
-  RenderWidgetHostViewAura* popup_view = static_cast<RenderWidgetHostViewAura*>(
-      RenderWidgetHost::FromID(process_id, filter->last_routing_id())
-          ->GetView());
-  // The IO thread posts to ViewMsg_ShowWidget handlers in both the message
-  // filter above and the WebContents, which initializes the popup's view.
-  // It is possible for this code to execute before the WebContents handler,
-  // in which case OnMouseEvent would be called on an uninitialized RWHVA.
-  // This loop ensures that the initialization completes before proceeding.
-  while (!popup_view->window()) {
-    base::RunLoop loop;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  loop.QuitClosure());
-    loop.Run();
-  }
-
-  RenderWidgetHostMouseEventMonitor popup_monitor(
-      popup_view->GetRenderWidgetHost());
-
-  // Next send a mouse up directly targeting the first option, simulating a
-  // drag. This requires a ui::MouseEvent because it tests behavior that is
-  // above RWH input event routing.
-  ui::MouseEvent mouse_up_event(ui::ET_MOUSE_RELEASED, gfx::Point(10, 5),
-                                gfx::Point(10, 5), ui::EventTimeForNow(),
-                                ui::EF_LEFT_MOUSE_BUTTON,
-                                ui::EF_LEFT_MOUSE_BUTTON);
-  popup_view->OnMouseEvent(&mouse_up_event);
-
-  // This verifies that the popup actually received the event, and it wasn't
-  // diverted to a different RenderWidgetHostView due to mouse capture.
-  EXPECT_TRUE(popup_monitor.EventWasReceived());
-#endif
-}
-
-// Test that clicking a select element in a nested out-of-process iframe creates
-// a popup menu in the correct position, even if the top-level page repositions
-// its out-of-process iframe. This verifies that screen positioning information
-// is propagating down the frame tree correctly.
-#if defined(OS_ANDROID)
-// Surface-based hit testing and coordinate translation is not yet avaiable on
-// Android.
-#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
-#else
-// Times out frequently. https://crbug.com/599730.
-#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_NestedPopupMenuTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/cross_site_iframe_factory.html?a(b(c))"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-
-#if !defined(OS_MACOSX)
-  // Undefined variable on Mac.
-  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-#endif
-  web_contents()->SendScreenRects();
-
-  // For clarity, we are labeling the frame tree nodes as:
-  //  - root_node
-  //   \-> b_node (out-of-process from root and c_node)
-  //     \-> c_node (out-of-process from root and b_node)
-
-  content::TestNavigationObserver navigation_observer(shell()->web_contents());
-  FrameTreeNode* b_node = root->child_at(0);
-  FrameTreeNode* c_node = b_node->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL(
-      "baz.com", "/site_isolation/page-with-select.html"));
-  NavigateFrameToURL(c_node, site_url);
-
-  RenderWidgetHostViewBase* rwhv_c_node =
-      static_cast<RenderWidgetHostViewBase*>(
-          c_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            c_node->current_frame_host()->GetSiteInstance());
-
-  scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter();
-  c_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
-
-  // Target left-click event to child frame.
-  blink::WebMouseEvent click_event(blink::WebInputEvent::kMouseDown,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  click_event.button = blink::WebPointerProperties::Button::kLeft;
-  click_event.SetPositionInWidget(15, 15);
-  click_event.click_count = 1;
-  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
-
-  // Prompt the WebContents to dismiss the popup by clicking elsewhere.
-  click_event.SetPositionInWidget(1, 1);
-  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
-
-  filter->Wait();
-
-  gfx::Rect popup_rect = filter->last_initial_rect();
-
-#if defined(OS_MACOSX)
-  EXPECT_EQ(popup_rect.x(), 9);
-  EXPECT_EQ(popup_rect.y(), 9);
-#else
-  EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
-  EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 154);
-#endif
-
-  // Save the screen rect for b_node. Since it updates asynchronously from
-  // the script command that changes it, we need to wait for it to change
-  // before attempting to create the popup widget again.
-  gfx::Rect last_b_node_bounds_rect =
-      b_node->current_frame_host()->GetView()->GetViewBounds();
-
-  std::string script =
-      "var iframe = document.querySelector('iframe');"
-      "iframe.style.position = 'absolute';"
-      "iframe.style.left = 150;"
-      "iframe.style.top = 150;";
-  EXPECT_TRUE(ExecuteScript(root, script));
-
-  filter->Reset();
-
-  // Busy loop to wait for b_node's screen rect to get updated. There
-  // doesn't seem to be any better way to find out when this happens.
-  while (last_b_node_bounds_rect.x() ==
-             b_node->current_frame_host()->GetView()->GetViewBounds().x() &&
-         last_b_node_bounds_rect.y() ==
-             b_node->current_frame_host()->GetView()->GetViewBounds().y()) {
-    base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
-    run_loop.Run();
-  }
-
-  click_event.button = blink::WebPointerProperties::Button::kLeft;
-  click_event.SetPositionInWidget(15, 15);
-  click_event.click_count = 1;
-  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
-
-  click_event.SetPositionInWidget(1, 1);
-  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
-
-  filter->Wait();
-
-  popup_rect = filter->last_initial_rect();
-
-#if defined(OS_MACOSX)
-  EXPECT_EQ(popup_rect.x(), 9);
-  EXPECT_EQ(popup_rect.y(), 9);
-#else
-  EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 203);
-  EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 248);
-#endif
-}
-
 // Test for https://crbug.com/526304, where a parent frame executes a
 // remote-to-local navigation on a child frame and immediately removes the same
 // child frame.  This test exercises the path where the detach happens before
@@ -10137,197 +7370,6 @@
   EXPECT_EQ(2, event_fired);
 }
 
-#if defined(USE_AURA)
-class SitePerProcessGestureBrowserTest : public SitePerProcessBrowserTest {
- public:
-  SitePerProcessGestureBrowserTest() {}
-
-  // This functions simulates a sequence of events that are typical of a
-  // gesture pinch at |position|. We need this since machinery in the event
-  // codepath will require GesturePinch* to be enclosed in
-  // GestureScrollBegin/End, and since RenderWidgetHostInputEventRouter needs
-  // both the preceding touch events, as well as GestureTapDown, in order to
-  // correctly target the subsequent gesture event stream. The minimum stream
-  // required to trigger the correct behaviours is represented here, but could
-  // be expanded to include additional events such as one or more
-  // GestureScrollUpdate and GesturePinchUpdate events.
-  void SendPinchBeginEndSequence(RenderWidgetHostViewAura* rwhva,
-                                 const gfx::Point& position,
-                                 RenderWidgetHost* expected_target_rwh) {
-    DCHECK(rwhva);
-    // Use full version of constructor with radius, angle and force since it
-    // will crash in the renderer otherwise.
-    ui::TouchEvent touch_pressed(
-        ui::ET_TOUCH_PRESSED, position, ui::EventTimeForNow(),
-        ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
-                           /* pointer_id*/ 0,
-                           /* radius_x */ 1.0f,
-                           /* radius_y */ 1.0f,
-                           /* force */ 1.0f));
-    InputEventAckWaiter waiter(expected_target_rwh,
-                               blink::WebInputEvent::kTouchStart);
-    rwhva->OnTouchEvent(&touch_pressed);
-    waiter.Wait();
-    ui::TouchEvent touch_released(
-        ui::ET_TOUCH_RELEASED, position, ui::EventTimeForNow(),
-        ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
-                           /* pointer_id*/ 0,
-                           /* radius_x */ 1.0f,
-                           /* radius_y */ 1.0f,
-                           /* force */ 1.0f));
-    rwhva->OnTouchEvent(&touch_released);
-
-    ui::GestureEventDetails gesture_tap_down_details(ui::ET_GESTURE_TAP_DOWN);
-    gesture_tap_down_details.set_device_type(
-        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-    ui::GestureEvent gesture_tap_down(
-        position.x(), position.y(), 0, ui::EventTimeForNow(),
-        gesture_tap_down_details, touch_pressed.unique_event_id());
-    rwhva->OnGestureEvent(&gesture_tap_down);
-
-    ui::GestureEventDetails gesture_scroll_begin_details(
-        ui::ET_GESTURE_SCROLL_BEGIN);
-    gesture_scroll_begin_details.set_device_type(
-        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-    ui::GestureEvent gesture_scroll_begin(
-        position.x(), position.y(), 0, ui::EventTimeForNow(),
-        gesture_scroll_begin_details, touch_pressed.unique_event_id());
-    rwhva->OnGestureEvent(&gesture_scroll_begin);
-
-    ui::GestureEventDetails gesture_pinch_begin_details(
-        ui::ET_GESTURE_PINCH_BEGIN);
-    gesture_pinch_begin_details.set_device_type(
-        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-    ui::GestureEvent gesture_pinch_begin(
-        position.x(), position.y(), 0, ui::EventTimeForNow(),
-        gesture_pinch_begin_details, touch_pressed.unique_event_id());
-    rwhva->OnGestureEvent(&gesture_pinch_begin);
-
-    ui::GestureEventDetails gesture_pinch_end_details(ui::ET_GESTURE_PINCH_END);
-    gesture_pinch_end_details.set_device_type(
-        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-    ui::GestureEvent gesture_pinch_end(
-        position.x(), position.y(), 0, ui::EventTimeForNow(),
-        gesture_pinch_end_details, touch_pressed.unique_event_id());
-    rwhva->OnGestureEvent(&gesture_pinch_end);
-
-    ui::GestureEventDetails gesture_scroll_end_details(
-        ui::ET_GESTURE_SCROLL_END);
-    gesture_scroll_end_details.set_device_type(
-        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
-    ui::GestureEvent gesture_scroll_end(
-        position.x(), position.y(), 0, ui::EventTimeForNow(),
-        gesture_scroll_end_details, touch_pressed.unique_event_id());
-    rwhva->OnGestureEvent(&gesture_scroll_end);
-  }
-
-  void SetupRootAndChild() {
-    GURL main_url(embedded_test_server()->GetURL(
-        "a.com", "/cross_site_iframe_factory.html?a(b)"));
-    EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-    FrameTreeNode* root_node =
-        static_cast<WebContentsImpl*>(shell()->web_contents())
-            ->GetFrameTree()
-            ->root();
-    FrameTreeNode* child_node = root_node->child_at(0);
-
-    rwhv_child_ = static_cast<RenderWidgetHostViewBase*>(
-        child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-    rwhva_root_ = static_cast<RenderWidgetHostViewAura*>(
-        shell()->web_contents()->GetRenderWidgetHostView());
-
-    WaitForChildFrameSurfaceReady(child_node->current_frame_host());
-
-    rwhi_child_ = child_node->current_frame_host()->GetRenderWidgetHost();
-    rwhi_root_ = root_node->current_frame_host()->GetRenderWidgetHost();
-  }
-
- protected:
-  RenderWidgetHostViewBase* rwhv_child_;
-  RenderWidgetHostViewAura* rwhva_root_;
-  RenderWidgetHostImpl* rwhi_child_;
-  RenderWidgetHostImpl* rwhi_root_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SitePerProcessGestureBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessGestureBrowserTest,
-                       SubframeGesturePinchGoesToMainFrame) {
-  SetupRootAndChild();
-
-  TestInputEventObserver root_frame_monitor(rwhi_root_);
-  TestInputEventObserver child_frame_monitor(rwhi_child_);
-
-  // Need child rect in main frame coords.
-  gfx::Rect bounds = rwhv_child_->GetViewBounds();
-  bounds.Offset(gfx::Point() - rwhva_root_->GetViewBounds().origin());
-  SendPinchBeginEndSequence(rwhva_root_, bounds.CenterPoint(), rwhi_child_);
-
-  // Verify root-RWHI gets GSB/GPB/GPE/GSE.
-  EXPECT_TRUE(root_frame_monitor.EventWasReceived());
-  EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
-            root_frame_monitor.events_received()[0]);
-  EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin,
-            root_frame_monitor.events_received()[1]);
-  EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd,
-            root_frame_monitor.events_received()[2]);
-  EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
-            root_frame_monitor.events_received()[3]);
-
-  // Verify child-RWHI gets TS/TE, GTD/GSB/GSE.
-  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
-  EXPECT_EQ(blink::WebInputEvent::kTouchStart,
-            child_frame_monitor.events_received()[0]);
-  EXPECT_EQ(blink::WebInputEvent::kTouchEnd,
-            child_frame_monitor.events_received()[1]);
-  EXPECT_EQ(blink::WebInputEvent::kGestureTapDown,
-            child_frame_monitor.events_received()[2]);
-  EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
-            child_frame_monitor.events_received()[3]);
-  EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
-            child_frame_monitor.events_received()[4]);
-}
-
-IN_PROC_BROWSER_TEST_F(SitePerProcessGestureBrowserTest,
-                       MainframeGesturePinchGoesToMainFrame) {
-  SetupRootAndChild();
-
-  TestInputEventObserver root_frame_monitor(rwhi_root_);
-  TestInputEventObserver child_frame_monitor(rwhi_child_);
-
-  // Need child rect in main frame coords.
-  gfx::Rect bounds = rwhv_child_->GetViewBounds();
-  bounds.Offset(gfx::Point() - rwhva_root_->GetViewBounds().origin());
-
-  gfx::Point main_frame_point(bounds.origin());
-  main_frame_point += gfx::Vector2d(-5, -5);
-  SendPinchBeginEndSequence(rwhva_root_, main_frame_point, rwhi_root_);
-
-  // Verify root-RWHI gets TS/TE/GTD/GSB/GPB/GPE/GSE.
-  EXPECT_TRUE(root_frame_monitor.EventWasReceived());
-  EXPECT_EQ(blink::WebInputEvent::kTouchStart,
-            root_frame_monitor.events_received()[0]);
-  EXPECT_EQ(blink::WebInputEvent::kTouchEnd,
-            root_frame_monitor.events_received()[1]);
-  EXPECT_EQ(blink::WebInputEvent::kGestureTapDown,
-            root_frame_monitor.events_received()[2]);
-  EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
-            root_frame_monitor.events_received()[3]);
-  EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin,
-            root_frame_monitor.events_received()[4]);
-  EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd,
-            root_frame_monitor.events_received()[5]);
-  EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
-            root_frame_monitor.events_received()[6]);
-
-  // Verify child-RWHI gets no events.
-  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
-}
-#endif
-
 // Test that the pending RenderFrameHost is canceled and destroyed when its
 // process dies. Previously, reusing a top-level pending RFH which
 // is not live was hitting a CHECK in CreateRenderView due to having neither a
@@ -11113,61 +8155,6 @@
             child->current_frame_host()->GetProcess());
 }
 
-// Test that MouseDown and MouseUp to the same coordinates do not result in
-// different coordinates after routing. See bug https://crbug.com/670253.
-#if defined(OS_ANDROID)
-// Android uses fixed scale factor, which makes this test unnecessary.
-#define MAYBE_MouseClickWithNonIntegerScaleFactor \
-  DISABLED_MouseClickWithNonIntegerScaleFactor
-#else
-#define MAYBE_MouseClickWithNonIntegerScaleFactor \
-  MouseClickWithNonIntegerScaleFactor
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessNonIntegerScaleFactorBrowserTest,
-                       MAYBE_MouseClickWithNonIntegerScaleFactor) {
-  GURL initial_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), initial_url));
-
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-
-  RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-
-  RenderWidgetHostInputEventRouter* router =
-      static_cast<WebContentsImpl*>(shell()->web_contents())
-          ->GetInputEventRouter();
-
-  // Create listener for input events.
-  RenderWidgetHostMouseEventMonitor event_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-
-  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseDown,
-                                   blink::WebInputEvent::kNoModifiers,
-                                   blink::WebInputEvent::kTimeStampForTesting);
-  mouse_event.button = blink::WebPointerProperties::Button::kLeft;
-  mouse_event.SetPositionInWidget(75, 75);
-  mouse_event.click_count = 1;
-  event_monitor.ResetEventReceived();
-  router->RouteMouseEvent(rwhv, &mouse_event, ui::LatencyInfo());
-
-  EXPECT_TRUE(event_monitor.EventWasReceived());
-  gfx::Point mouse_down_coords =
-      gfx::Point(event_monitor.event().PositionInWidget().x,
-                 event_monitor.event().PositionInWidget().y);
-  event_monitor.ResetEventReceived();
-
-  mouse_event.SetType(blink::WebInputEvent::kMouseUp);
-  mouse_event.SetPositionInWidget(75, 75);
-  router->RouteMouseEvent(rwhv, &mouse_event, ui::LatencyInfo());
-
-  EXPECT_TRUE(event_monitor.EventWasReceived());
-  EXPECT_EQ(mouse_down_coords,
-            gfx::Point(event_monitor.event().PositionInWidget().x,
-                       event_monitor.event().PositionInWidget().y));
-}
-
 // Verify that a remote-to-local navigation in a crashed subframe works.  See
 // https://crbug.com/487872.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
@@ -13201,81 +10188,4 @@
   EXPECT_NE(third_shell_instance->GetProcess(), bar_process);
 }
 
-// Verify InputTargetClient works within an OOPIF process.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, HitTestNestedFrames) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
-
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  EXPECT_EQ(
-      " Site A ------------ proxies for B C\n"
-      "   +--Site B ------- proxies for A C\n"
-      "        +--Site C -- proxies for A B\n"
-      "Where A = http://127.0.0.1/\n"
-      "      B = http://a.com/\n"
-      "      C = http://baz.com/",
-      DepictFrameTree(root));
-
-  FrameTreeNode* child_node = root->child_at(0);
-  FrameTreeNode* grandchild_node = child_node->child_at(0);
-  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
-      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_grandchild =
-      static_cast<RenderWidgetHostViewBase*>(
-          grandchild_node->current_frame_host()
-              ->GetRenderWidgetHost()
-              ->GetView());
-
-  WaitForChildFrameSurfaceReady(grandchild_node->current_frame_host());
-
-  // Create two points to hit test: One in the child of the main frame, and
-  // one in the frame nested within that. The hit test request is sent to the
-  // child's renderer.
-  gfx::Point point_in_child(1, 1);
-  gfx::PointF point_in_nested_child(5, 5);
-  rwhv_grandchild->TransformPointToCoordSpaceForView(
-      point_in_nested_child, rwhv_child, &point_in_nested_child);
-
-  {
-    base::RunLoop run_loop;
-    viz::FrameSinkId received_frame_sink_id;
-    base::Closure quit_closure =
-        content::GetDeferredQuitTaskForRunLoop(&run_loop);
-    DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
-              nullptr);
-    child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
-        point_in_child,
-        base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
-          received_frame_sink_id = id;
-          quit_closure.Run();
-        }));
-    content::RunThisRunLoop(&run_loop);
-    // |point_in_child| should hit test to the view for |child_node|.
-    ASSERT_EQ(rwhv_child->GetFrameSinkId(), received_frame_sink_id);
-  }
-
-  {
-    base::RunLoop run_loop;
-    viz::FrameSinkId received_frame_sink_id;
-    base::Closure quit_closure =
-        content::GetDeferredQuitTaskForRunLoop(&run_loop);
-    DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
-              nullptr);
-    child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
-        gfx::ToCeiledPoint(point_in_nested_child),
-        base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
-          received_frame_sink_id = id;
-          quit_closure.Run();
-        }));
-    content::RunThisRunLoop(&run_loop);
-    // |point_in_nested_child| should hit test to |rwhv_grandchild|.
-    ASSERT_EQ(rwhv_grandchild->GetFrameSinkId(), received_frame_sink_id);
-  }
-}
-
 }  // namespace content
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
new file mode 100644
index 0000000..7c62bf6
--- /dev/null
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -0,0 +1,3169 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/site_per_process_browsertest.h"
+
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/json/json_reader.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/test_timeouts.h"
+#include "build/build_config.h"
+#include "components/viz/common/switches.h"
+#include "content/browser/renderer_host/cursor_manager.h"
+#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
+#include "content/common/frame_messages.h"
+#include "content/common/view_messages.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/common/shell_switches.h"
+#include "content/test/mock_overscroll_observer.h"
+#include "ui/display/display_switches.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+
+#if defined(USE_AURA)
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include "content/public/browser/overscroll_configuration.h"
+#include "content/test/mock_overscroll_controller_delegate_aura.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "ui/base/test/scoped_preferred_scroller_style_mac.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "content/browser/renderer_host/render_widget_host_view_android.h"
+#include "content/test/mock_overscroll_refresh_handler_android.h"
+#endif
+
+namespace content {
+
+namespace {
+
+class RenderWidgetHostMouseEventMonitor {
+ public:
+  explicit RenderWidgetHostMouseEventMonitor(RenderWidgetHost* host)
+      : host_(host), event_received_(false) {
+    mouse_callback_ =
+        base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
+                   base::Unretained(this));
+    host_->AddMouseEventCallback(mouse_callback_);
+  }
+  ~RenderWidgetHostMouseEventMonitor() {
+    host_->RemoveMouseEventCallback(mouse_callback_);
+  }
+  bool EventWasReceived() const { return event_received_; }
+  void ResetEventReceived() { event_received_ = false; }
+  const blink::WebMouseEvent& event() const { return event_; }
+
+ private:
+  bool MouseEventCallback(const blink::WebMouseEvent& event) {
+    event_received_ = true;
+    event_ = event;
+    return false;
+  }
+  RenderWidgetHost::MouseEventCallback mouse_callback_;
+  RenderWidgetHost* host_;
+  bool event_received_;
+  blink::WebMouseEvent event_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostMouseEventMonitor);
+};
+
+class TestInputEventObserver : public RenderWidgetHost::InputEventObserver {
+ public:
+  explicit TestInputEventObserver(RenderWidgetHost* host) : host_(host) {
+    host_->AddInputEventObserver(this);
+  }
+
+  ~TestInputEventObserver() override { host_->RemoveInputEventObserver(this); }
+
+  bool EventWasReceived() const { return !events_received_.empty(); }
+  void ResetEventsReceived() { events_received_.clear(); }
+  blink::WebInputEvent::Type EventType() const {
+    DCHECK(EventWasReceived());
+    return events_received_.front();
+  }
+  const std::vector<blink::WebInputEvent::Type>& events_received() {
+    return events_received_;
+  }
+
+  const blink::WebInputEvent& event() const { return *event_; }
+
+  void OnInputEvent(const blink::WebInputEvent& event) override {
+    events_received_.push_back(event.GetType());
+    event_ = ui::WebInputEventTraits::Clone(event);
+  };
+
+ private:
+  RenderWidgetHost* host_;
+  std::vector<blink::WebInputEvent::Type> events_received_;
+  ui::WebScopedInputEvent event_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInputEventObserver);
+};
+
+void RouteMouseEventAndWaitUntilDispatch(
+    RenderWidgetHostInputEventRouter* router,
+    RenderWidgetHostViewBase* root_view,
+    RenderWidgetHostViewBase* expected_target,
+    blink::WebMouseEvent* event) {
+  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
+                             event->GetType());
+  router->RouteMouseEvent(root_view, event, ui::LatencyInfo());
+  waiter.Wait();
+}
+
+void DispatchMouseEventAndWaitUntilDispatch(
+    WebContentsImpl* web_contents,
+    RenderWidgetHostViewBase* location_view,
+    const gfx::PointF& location,
+    RenderWidgetHostViewBase* expected_target,
+    const gfx::PointF& expected_location) {
+  auto* router = web_contents->GetInputEventRouter();
+
+  RenderWidgetHostMouseEventMonitor monitor(
+      expected_target->GetRenderWidgetHost());
+  gfx::PointF root_location =
+      location_view->TransformPointToRootCoordSpaceF(location);
+  blink::WebMouseEvent down_event(blink::WebInputEvent::kMouseDown,
+                                  blink::WebInputEvent::kNoModifiers,
+                                  blink::WebInputEvent::kTimeStampForTesting);
+  down_event.button = blink::WebPointerProperties::Button::kLeft;
+  down_event.SetPositionInWidget(root_location.x(), root_location.y());
+  down_event.click_count = 1;
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  auto* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, expected_target,
+                                      &down_event);
+  EXPECT_TRUE(monitor.EventWasReceived());
+  EXPECT_NEAR(expected_location.x(), monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(expected_location.y(), monitor.event().PositionInWidget().y, 2);
+}
+
+// Helper function that performs a surface hittest.
+void SurfaceHitTestTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
+                                         gfx::PointF(5, 5), rwhv_child,
+                                         gfx::PointF(5, 5));
+
+  DispatchMouseEventAndWaitUntilDispatch(
+      web_contents, rwhv_root, gfx::PointF(2, 2), rwhv_root, gfx::PointF(2, 2));
+}
+
+void OverlapSurfaceHitTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_content_overlap_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  gfx::PointF parent_location = gfx::PointF(5, 5);
+  parent_location =
+      rwhv_child->TransformPointToRootCoordSpaceF(parent_location);
+  DispatchMouseEventAndWaitUntilDispatch(
+      web_contents, rwhv_child, gfx::PointF(5, 5), rwhv_root, parent_location);
+
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
+                                         gfx::PointF(95, 95), rwhv_child,
+                                         gfx::PointF(95, 95));
+}
+
+// Helper function that performs a surface hittest in nested frame.
+void NestedSurfaceHitTestTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* parent_iframe_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL(
+      "a.com", "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_EQ(site_url, parent_iframe_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            parent_iframe_node->current_frame_host()->GetSiteInstance());
+
+  FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
+  GURL nested_site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(nested_site_url, nested_iframe_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            nested_iframe_node->current_frame_host()->GetSiteInstance());
+  EXPECT_NE(parent_iframe_node->current_frame_host()->GetSiteInstance(),
+            nested_iframe_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* rwhv_nested =
+      static_cast<RenderWidgetHostViewBase*>(
+          nested_iframe_node->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetView());
+
+  WaitForChildFrameSurfaceReady(nested_iframe_node->current_frame_host());
+
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_nested,
+                                         gfx::PointF(10, 10), rwhv_nested,
+                                         gfx::PointF(10, 10));
+}
+
+void HitTestLayerSquashing(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/oopif_hit_test_layer_squashing.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  gfx::Vector2dF child_offset = rwhv_child->GetViewBounds().origin() -
+                                rwhv_root->GetViewBounds().origin();
+  // Send a mouse-down on #B. The main-frame should receive it.
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
+                                         gfx::PointF(195, 11), rwhv_root,
+                                         gfx::PointF(195, 11));
+  // Send another event just below. The child-frame should receive it.
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
+                                         gfx::PointF(195, 30), rwhv_child,
+                                         gfx::PointF(195, 30) - child_offset);
+  // Send a mouse-down on #C.
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
+                                         gfx::PointF(35, 195), rwhv_root,
+                                         gfx::PointF(35, 195));
+  // Send a mouse-down to the right of #C so that it goes to the child frame.
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
+                                         gfx::PointF(55, 195), rwhv_child,
+                                         gfx::PointF(55, 195) - child_offset);
+  // Send a mouse-down to the right-bottom edge of the iframe.
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_root,
+                                         gfx::PointF(195, 235), rwhv_child,
+                                         gfx::PointF(195, 235) - child_offset);
+}
+
+void HitTestWatermark(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/oopif_hit_test_watermark.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  gfx::Vector2dF child_offset = rwhv_child->GetViewBounds().origin() -
+                                rwhv_root->GetViewBounds().origin();
+  const gfx::PointF child_location(100, 120);
+  // Send a mouse-down at the center of the iframe. This should go to the
+  // main-frame (since there's a translucent div on top of it).
+  DispatchMouseEventAndWaitUntilDispatch(web_contents, rwhv_child,
+                                         child_location, rwhv_root,
+                                         child_location + child_offset);
+
+  // Set 'pointer-events: none' on the div.
+  EXPECT_TRUE(ExecuteScript(web_contents, "W.style.pointerEvents = 'none';"));
+
+  // Dispatch another event at the same location. It should reach the oopif this
+  // time.
+  DispatchMouseEventAndWaitUntilDispatch(
+      web_contents, rwhv_child, child_location, rwhv_child, child_location);
+}
+
+// This helper accounts for Android devices which use page scale factor
+// different from 1.0. Coordinate targeting needs to be adjusted before
+// hit testing.
+double GetPageScaleFactor(Shell* shell) {
+  return RenderWidgetHostImpl::From(
+             shell->web_contents()->GetRenderViewHost()->GetWidget())
+      ->last_frame_metadata()
+      .page_scale_factor;
+}
+
+#if defined(USE_AURA)
+bool ConvertJSONToPoint(const std::string& str, gfx::PointF* point) {
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(str);
+  if (!value)
+    return false;
+  base::DictionaryValue* root;
+  if (!value->GetAsDictionary(&root))
+    return false;
+  double x, y;
+  if (!root->GetDouble("x", &x))
+    return false;
+  if (!root->GetDouble("y", &y))
+    return false;
+  point->set_x(x);
+  point->set_y(y);
+  return true;
+}
+#endif  // defined(USE_AURA)
+
+}  // namespace
+
+using SitePerProcessHitTestBrowserTest = SitePerProcessBrowserTest;
+
+//
+// SitePerProcessHighDPIHitTestBrowserTest
+//
+
+class SitePerProcessHighDPIHitTestBrowserTest
+    : public SitePerProcessBrowserTest {
+ public:
+  const double kDeviceScaleFactor = 2.0;
+
+  SitePerProcessHighDPIHitTestBrowserTest() {}
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    SitePerProcessBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(
+        switches::kForceDeviceScaleFactor,
+        base::StringPrintf("%f", kDeviceScaleFactor));
+  }
+};
+
+//
+// SitePerProcessNonIntegerScaleFactorHitTestBrowserTest
+//
+
+class SitePerProcessNonIntegerScaleFactorHitTestBrowserTest
+    : public SitePerProcessBrowserTest {
+ public:
+  const double kDeviceScaleFactor = 1.5;
+
+  SitePerProcessNonIntegerScaleFactorHitTestBrowserTest() {}
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    SitePerProcessBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(
+        switches::kForceDeviceScaleFactor,
+        base::StringPrintf("%f", kDeviceScaleFactor));
+  }
+};
+
+// Restrict to Aura to we can use routable MouseWheel event via
+// RenderWidgetHostViewAura::OnScrollEvent().
+#if defined(USE_AURA)
+class SitePerProcessInternalsHitTestBrowserTest
+    : public SitePerProcessBrowserTest {
+ public:
+  SitePerProcessInternalsHitTestBrowserTest() {}
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    SitePerProcessBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kExposeInternalsForTesting);
+    // Needed to guarantee the scrollable div we're testing with is not given
+    // its own compositing layer.
+    command_line->AppendSwitch(switches::kDisablePreferCompositingToLCDText);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessInternalsHitTestBrowserTest,
+                       ScrollNestedLocalNonFastScrollableDiv) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* parent_iframe_node = root->child_at(0);
+
+  GURL site_url(embedded_test_server()->GetURL(
+      "b.com", "/tall_page_with_local_iframe.html"));
+  NavigateFrameToURL(parent_iframe_node, site_url);
+
+  FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
+  WaitForChildFrameSurfaceReady(nested_iframe_node->current_frame_host());
+
+  EXPECT_EQ(
+      " Site A ------------ proxies for B\n"
+      "   +--Site B ------- proxies for A\n"
+      "        +--Site B -- proxies for A\n"
+      "Where A = http://a.com/\n"
+      "      B = http://b.com/",
+      DepictFrameTree(root));
+
+  const char* get_element_location_script_fmt =
+      "var rect = "
+      "document.getElementById('%s').getBoundingClientRect();\n"
+      "var point = {\n"
+      "  x: rect.left,\n"
+      "  y: rect.top\n"
+      "};\n"
+      "window.domAutomationController.send(JSON.stringify(point));";
+
+  // Since the nested local b-frame shares the RenderWidgetHostViewChildFrame
+  // with the parent frame, we need to query element offsets in both documents
+  // before converting to root space coordinates for the wheel event.
+  std::string str;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      nested_iframe_node->current_frame_host(),
+      base::StringPrintf(get_element_location_script_fmt, "scrollable_div"),
+      &str));
+  gfx::PointF nested_point_f;
+  ConvertJSONToPoint(str, &nested_point_f);
+
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      parent_iframe_node->current_frame_host(),
+      base::StringPrintf(get_element_location_script_fmt, "nested_frame"),
+      &str));
+  gfx::PointF parent_offset_f;
+  ConvertJSONToPoint(str, &parent_offset_f);
+
+  // Compute location for wheel event.
+  gfx::PointF point_f(parent_offset_f.x() + nested_point_f.x() + 5.f,
+                      parent_offset_f.y() + nested_point_f.y() + 5.f);
+
+  RenderWidgetHostViewChildFrame* rwhv_nested =
+      static_cast<RenderWidgetHostViewChildFrame*>(
+          nested_iframe_node->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetView());
+  point_f = rwhv_nested->TransformPointToRootCoordSpaceF(point_f);
+
+  RenderWidgetHostViewAura* rwhv_root = static_cast<RenderWidgetHostViewAura*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  gfx::PointF nested_in_parent;
+  rwhv_root->TransformPointToCoordSpaceForView(
+      point_f,
+      parent_iframe_node->current_frame_host()
+          ->GetRenderWidgetHost()
+          ->GetView(),
+      &nested_in_parent);
+
+  // Get original scroll position.
+  int div_scroll_top_start;
+  EXPECT_TRUE(ExecuteScriptAndExtractInt(
+      nested_iframe_node->current_frame_host(),
+      "window.domAutomationController.send("
+      "document.getElementById('scrollable_div').scrollTop);",
+      &div_scroll_top_start));
+  EXPECT_EQ(0, div_scroll_top_start);
+
+  // Wait until renderer's compositor thread is synced. Otherwise the event
+  // handler won't be installed when the event arrives.
+  MainThreadFrameObserver observer(rwhv_root->GetRenderWidgetHost());
+  observer.Wait();
+  {
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(),
+        // tiny_timeout() is too small to run without flakes, but
+        // action_timeout() is 100 times bigger, which is overkill. We use a
+        // custom delay here to achieve a balance.
+        base::TimeDelta::FromMilliseconds(1000));
+    run_loop.Run();
+  }
+
+  // Send a wheel to scroll the div.
+  gfx::Point location(point_f.x(), point_f.y());
+  ui::ScrollEvent scroll_event(ui::ET_SCROLL, location, ui::EventTimeForNow(),
+                               0, 0, -ui::MouseWheelEvent::kWheelDelta, 0,
+                               ui::MouseWheelEvent::kWheelDelta,
+                               2);  // This must be '2' or it gets silently
+                                    // dropped.
+  rwhv_root->OnScrollEvent(&scroll_event);
+
+  InputEventAckWaiter ack_observer(
+      parent_iframe_node->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kGestureScrollUpdate);
+  ack_observer.Wait();
+
+  // Check compositor layers.
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      nested_iframe_node->current_frame_host(),
+      "window.domAutomationController.send("
+      "window.internals.layerTreeAsText(document));",
+      &str));
+  // We expect the nested OOPIF to not have any compositor layers.
+  EXPECT_EQ(std::string(), str);
+
+  // Verify the div scrolled.
+  int div_scroll_top = div_scroll_top_start;
+  EXPECT_TRUE(ExecuteScriptAndExtractInt(
+      nested_iframe_node->current_frame_host(),
+      "window.domAutomationController.send("
+      "document.getElementById('scrollable_div').scrollTop);",
+      &div_scroll_top));
+  EXPECT_NE(div_scroll_top_start, div_scroll_top);
+}
+#endif  // defined(USE_AURA)
+
+// Tests that wheel scroll bubbling gets cancelled when the wheel target view
+// gets destroyed in the middle of a wheel scroll seqeunce. This happens in
+// cases like overscroll navigation from inside an oopif.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       CancelWheelScrollBubblingOnWheelTargetDeletion) {
+  ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
+      0);
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* iframe_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, iframe_node->current_url());
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
+      iframe_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  RenderWidgetHostInputEventRouter* router =
+      static_cast<WebContentsImpl*>(shell()->web_contents())
+          ->GetInputEventRouter();
+
+  WaitForChildFrameSurfaceReady(iframe_node->current_frame_host());
+
+  InputEventAckWaiter scroll_begin_observer(
+      root->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kGestureScrollBegin);
+  InputEventAckWaiter scroll_end_observer(
+      root->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kGestureScrollEnd);
+
+  // Scroll the iframe upward, scroll events get bubbled up to the root.
+  blink::WebMouseWheelEvent scroll_event(
+      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  gfx::Rect bounds = child_rwhv->GetViewBounds();
+  float scale_factor = GetPageScaleFactor(shell());
+  scroll_event.SetPositionInWidget(
+      gfx::ToCeiledInt((bounds.x() - root_view->GetViewBounds().x() + 5) *
+                       scale_factor),
+      gfx::ToCeiledInt((bounds.y() - root_view->GetViewBounds().y() + 5) *
+                       scale_factor));
+  scroll_event.delta_x = 0.0f;
+  scroll_event.delta_y = 5.0f;
+  scroll_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+  scroll_event.has_precise_scrolling_deltas = true;
+  router->RouteMouseWheelEvent(root_view, &scroll_event, ui::LatencyInfo());
+  scroll_begin_observer.Wait();
+
+  // Now destroy the child_rwhv, scroll bubbling stops and a GSE gets sent to
+  // the root_view.
+  RenderProcessHost* rph =
+      iframe_node->current_frame_host()->GetSiteInstance()->GetProcess();
+  RenderProcessHostWatcher crash_observer(
+      rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  EXPECT_TRUE(rph->Shutdown(0, false));
+  crash_observer.Wait();
+  scroll_event.delta_y = 0.0f;
+  scroll_event.phase = blink::WebMouseWheelEvent::kPhaseEnded;
+  scroll_event.dispatch_type =
+      blink::WebInputEvent::DispatchType::kEventNonBlocking;
+  router->RouteMouseWheelEvent(root_view, &scroll_event, ui::LatencyInfo());
+  scroll_end_observer.Wait();
+}
+
+#if defined(USE_AURA) || defined(OS_ANDROID)
+
+// When unconsumed scrolls in a child bubble to the root and start an
+// overscroll gesture, the subsequent gesture scroll update events should be
+// consumed by the root. The child should not be able to scroll during the
+// overscroll gesture.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       RootConsumesScrollDuringOverscrollGesture) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+
+#if defined(USE_AURA)
+  // The child must be horizontally scrollable.
+  GURL child_url(embedded_test_server()->GetURL("b.com", "/wide_page.html"));
+#elif defined(OS_ANDROID)
+  // The child must be vertically scrollable.
+  GURL child_url(embedded_test_server()->GetURL("b.com", "/tall_page.html"));
+#endif
+  NavigateFrameToURL(child_node, child_url);
+
+  EXPECT_EQ(
+      " Site A ------------ proxies for B\n"
+      "   +--Site B ------- proxies for A\n"
+      "Where A = http://a.com/\n"
+      "      B = http://b.com/",
+      DepictFrameTree(root));
+
+  RenderWidgetHostViewChildFrame* rwhv_child =
+      static_cast<RenderWidgetHostViewChildFrame*>(
+          child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  ASSERT_EQ(gfx::Vector2dF(), rwhv_root->GetLastScrollOffset());
+  ASSERT_EQ(gfx::Vector2dF(), rwhv_child->GetLastScrollOffset());
+
+  RenderWidgetHostInputEventRouter* router =
+      static_cast<WebContentsImpl*>(shell()->web_contents())
+          ->GetInputEventRouter();
+
+  {
+    // Set up the RenderWidgetHostInputEventRouter to send the gesture stream
+    // to the child.
+    const gfx::Rect root_bounds = rwhv_root->GetViewBounds();
+    const gfx::Rect child_bounds = rwhv_child->GetViewBounds();
+    const float page_scale_factor = GetPageScaleFactor(shell());
+    const gfx::PointF point_in_child(
+        (child_bounds.x() - root_bounds.x() + 10) * page_scale_factor,
+        (child_bounds.y() - root_bounds.y() + 10) * page_scale_factor);
+    gfx::PointF dont_care;
+    ASSERT_EQ(rwhv_child->GetRenderWidgetHost(),
+              router->GetRenderWidgetHostAtPoint(rwhv_root, point_in_child,
+                                                 &dont_care));
+
+    blink::WebTouchEvent touch_event(
+        blink::WebInputEvent::kTouchStart, blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::kTimeStampForTesting);
+    touch_event.touches_length = 1;
+    touch_event.touches[0].state = blink::WebTouchPoint::kStatePressed;
+    touch_event.touches[0].SetPositionInWidget(point_in_child.x(),
+                                               point_in_child.y());
+    touch_event.unique_touch_event_id = 1;
+    InputEventAckWaiter waiter(rwhv_child->GetRenderWidgetHost(),
+                               blink::WebInputEvent::kTouchStart);
+    router->RouteTouchEvent(rwhv_root, &touch_event,
+                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
+    // With async hit testing, make sure the target for the initial TouchStart
+    // is resolved before sending the rest of the stream.
+    waiter.Wait();
+
+    blink::WebGestureEvent gesture_event(
+        blink::WebInputEvent::kGestureTapDown,
+        blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::kTimeStampForTesting);
+    gesture_event.source_device = blink::kWebGestureDeviceTouchscreen;
+    gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id;
+    router->RouteGestureEvent(rwhv_root, &gesture_event,
+                              ui::LatencyInfo(ui::SourceEventType::TOUCH));
+  }
+
+#if defined(USE_AURA)
+  RenderWidgetHostViewAura* rwhva =
+      static_cast<RenderWidgetHostViewAura*>(rwhv_root);
+  std::unique_ptr<MockOverscrollControllerDelegateAura>
+      mock_overscroll_delegate =
+          std::make_unique<MockOverscrollControllerDelegateAura>(rwhva);
+  rwhva->overscroll_controller()->set_delegate(mock_overscroll_delegate.get());
+  MockOverscrollObserver* mock_overscroll_observer =
+      mock_overscroll_delegate.get();
+#elif defined(OS_ANDROID)
+  RenderWidgetHostViewAndroid* rwhv_android =
+      static_cast<RenderWidgetHostViewAndroid*>(rwhv_root);
+  std::unique_ptr<MockOverscrollRefreshHandlerAndroid> mock_overscroll_handler =
+      std::make_unique<MockOverscrollRefreshHandlerAndroid>();
+  rwhv_android->SetOverscrollControllerForTesting(
+      mock_overscroll_handler.get());
+  MockOverscrollObserver* mock_overscroll_observer =
+      mock_overscroll_handler.get();
+#endif  // defined(USE_AURA)
+
+  InputEventAckWaiter gesture_begin_observer_child(
+      child_node->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kGestureScrollBegin);
+  InputEventAckWaiter gesture_end_observer_child(
+      child_node->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kGestureScrollEnd);
+
+#if defined(USE_AURA)
+  const float overscroll_threshold =
+      GetOverscrollConfig(OverscrollConfig::THRESHOLD_START_TOUCHSCREEN);
+#elif defined(OS_ANDROID)
+  const float overscroll_threshold = 0.f;
+#endif
+
+  // First we need our scroll to initiate an overscroll gesture in the root
+  // via unconsumed scrolls in the child.
+  blink::WebGestureEvent gesture_scroll_begin(
+      blink::WebGestureEvent::kGestureScrollBegin,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  gesture_scroll_begin.source_device = blink::kWebGestureDeviceTouchscreen;
+  gesture_scroll_begin.unique_touch_event_id = 1;
+  gesture_scroll_begin.data.scroll_begin.delta_hint_units =
+      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+  gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
+  gesture_scroll_begin.data.scroll_begin.delta_y_hint = 0.f;
+#if defined(USE_AURA)
+  // For aura, we scroll horizontally to activate an overscroll navigation.
+  gesture_scroll_begin.data.scroll_begin.delta_x_hint =
+      overscroll_threshold + 1;
+#elif defined(OS_ANDROID)
+  // For android, we scroll vertically to activate pull-to-refresh.
+  gesture_scroll_begin.data.scroll_begin.delta_y_hint =
+      overscroll_threshold + 1;
+#endif
+  router->RouteGestureEvent(rwhv_root, &gesture_scroll_begin,
+                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
+
+  // Make sure the child is indeed receiving the gesture stream.
+  gesture_begin_observer_child.Wait();
+
+  blink::WebGestureEvent gesture_scroll_update(
+      blink::WebGestureEvent::kGestureScrollUpdate,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  gesture_scroll_update.source_device = blink::kWebGestureDeviceTouchscreen;
+  gesture_scroll_update.unique_touch_event_id = 1;
+  gesture_scroll_update.data.scroll_update.delta_units =
+      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+  gesture_scroll_update.data.scroll_update.delta_x = 0.f;
+  gesture_scroll_update.data.scroll_update.delta_y = 0.f;
+#if defined(USE_AURA)
+  float* delta = &gesture_scroll_update.data.scroll_update.delta_x;
+#elif defined(OS_ANDROID)
+  float* delta = &gesture_scroll_update.data.scroll_update.delta_y;
+#endif
+  *delta = overscroll_threshold + 1;
+  mock_overscroll_observer->Reset();
+  // This will bring us into an overscroll gesture.
+  router->RouteGestureEvent(rwhv_root, &gesture_scroll_update,
+                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
+  // Note that in addition to verifying that we get the overscroll update, it
+  // is necessary to wait before sending the next event to prevent our multiple
+  // GestureScrollUpdates from being coalesced.
+  mock_overscroll_observer->WaitForUpdate();
+
+  // This scroll is in the same direction and so it will contribute to the
+  // overscroll.
+  *delta = 10.0f;
+  mock_overscroll_observer->Reset();
+  router->RouteGestureEvent(rwhv_root, &gesture_scroll_update,
+                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
+  mock_overscroll_observer->WaitForUpdate();
+
+  // Now we reverse direction. The child could scroll in this direction, but
+  // since we're in an overscroll gesture, the root should consume it.
+  *delta = -5.0f;
+  mock_overscroll_observer->Reset();
+  router->RouteGestureEvent(rwhv_root, &gesture_scroll_update,
+                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
+  mock_overscroll_observer->WaitForUpdate();
+
+  blink::WebGestureEvent gesture_scroll_end(
+      blink::WebGestureEvent::kGestureScrollEnd,
+      blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  gesture_scroll_end.source_device = blink::kWebGestureDeviceTouchscreen;
+  gesture_scroll_end.unique_touch_event_id = 1;
+  gesture_scroll_end.data.scroll_end.delta_units =
+      blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+  mock_overscroll_observer->Reset();
+  router->RouteGestureEvent(rwhv_root, &gesture_scroll_end,
+                            ui::LatencyInfo(ui::SourceEventType::TOUCH));
+  mock_overscroll_observer->WaitForEnd();
+
+  // Ensure that the method of providing the child's scroll events to the root
+  // does not leave the child in an invalid state.
+  gesture_end_observer_child.Wait();
+}
+#endif  // defined(USE_AURA) || defined(OS_ANDROID)
+
+// Test that an ET_SCROLL event sent to an out-of-process iframe correctly
+// results in a scroll. This is only handled by RenderWidgetHostViewAura
+// and is needed for trackpad scrolling on Chromebooks.
+#if defined(USE_AURA)
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest, ScrollEventToOOPIF) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewAura* rwhv_parent =
+      static_cast<RenderWidgetHostViewAura*>(
+          root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  // Create listener for input events.
+  TestInputEventObserver child_frame_monitor(
+      child_node->current_frame_host()->GetRenderWidgetHost());
+
+  // Send a ui::ScrollEvent that will hit test to the child frame.
+  InputEventAckWaiter waiter(
+      child_node->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kMouseWheel);
+  ui::ScrollEvent scroll_event(ui::ET_SCROLL, gfx::Point(75, 75),
+                               ui::EventTimeForNow(), ui::EF_NONE, 0,
+                               10,     // Offsets
+                               0, 10,  // Offset ordinals
+                               2);
+  rwhv_parent->OnScrollEvent(&scroll_event);
+  waiter.Wait();
+
+  // Verify that this a mouse wheel event was sent to the child frame renderer.
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  EXPECT_EQ(child_frame_monitor.EventType(), blink::WebInputEvent::kMouseWheel);
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       InputEventRouterWheelCoalesceTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewAura* rwhv_parent =
+      static_cast<RenderWidgetHostViewAura*>(
+          root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents()->GetInputEventRouter();
+
+  // Create listener for input events.
+  TestInputEventObserver child_frame_monitor(
+      child_node->current_frame_host()->GetRenderWidgetHost());
+  InputEventAckWaiter waiter(
+      child_node->current_frame_host()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kMouseWheel);
+
+  // Send a mouse wheel event to child.
+  blink::WebMouseWheelEvent wheel_event(
+      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  wheel_event.SetPositionInWidget(75, 75);
+  wheel_event.delta_x = 10;
+  wheel_event.delta_y = 20;
+  wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
+  router->RouteMouseWheelEvent(rwhv_parent, &wheel_event, ui::LatencyInfo());
+
+  // Send more mouse wheel events to the child. Since we are waiting for the
+  // async targeting on the first event, these new mouse wheel events should
+  // be coalesced properly.
+  blink::WebMouseWheelEvent wheel_event1(
+      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  wheel_event1.SetPositionInWidget(70, 70);
+  wheel_event1.delta_x = 12;
+  wheel_event1.delta_y = 22;
+  wheel_event1.phase = blink::WebMouseWheelEvent::kPhaseChanged;
+  router->RouteMouseWheelEvent(rwhv_parent, &wheel_event1, ui::LatencyInfo());
+
+  blink::WebMouseWheelEvent wheel_event2(
+      blink::WebInputEvent::kMouseWheel, blink::WebInputEvent::kNoModifiers,
+      blink::WebInputEvent::kTimeStampForTesting);
+  wheel_event2.SetPositionInWidget(65, 65);
+  wheel_event2.delta_x = 14;
+  wheel_event2.delta_y = 24;
+  wheel_event2.phase = blink::WebMouseWheelEvent::kPhaseChanged;
+  router->RouteMouseWheelEvent(rwhv_parent, &wheel_event2, ui::LatencyInfo());
+
+  // Since we are targeting child, event dispatch should not happen
+  // synchronously. Validate that the expected target does not receive the
+  // event immediately.
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+
+  waiter.Wait();
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  EXPECT_EQ(child_frame_monitor.EventType(), blink::WebInputEvent::kMouseWheel);
+
+  // Check if the two mouse-wheel update events are coalesced correctly.
+  const auto& gesture_event =
+      static_cast<const blink::WebGestureEvent&>(child_frame_monitor.event());
+  EXPECT_EQ(26 /* wheel_event1.delta_x + wheel_event2.delta_x */,
+            gesture_event.data.scroll_update.delta_x);
+  EXPECT_EQ(46 /* wheel_event1.delta_y + wheel_event2.delta_y */,
+            gesture_event.data.scroll_update.delta_y);
+}
+#endif  // defined(USE_AURA)
+
+// Test that mouse events are being routed to the correct RenderWidgetHostView
+// based on coordinates.
+#if defined(THREAD_SANITIZER)
+// The test times out often on TSAN bot.
+// https://crbug.com/591170.
+#define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest
+#else
+#define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       MAYBE_SurfaceHitTestTest) {
+  SurfaceHitTestTestHelper(shell(), embedded_test_server());
+}
+
+// Same test as above, but runs in high-dpi mode.
+#if defined(OS_ANDROID) || defined(OS_WIN)
+// High DPI browser tests are not needed on Android, and confuse some of the
+// coordinate calculations. Android uses fixed device scale factor.
+// Windows is disabled because of https://crbug.com/545547.
+#define MAYBE_HighDPISurfaceHitTestTest DISABLED_SurfaceHitTestTest
+#else
+#define MAYBE_HighDPISurfaceHitTestTest SurfaceHitTestTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIHitTestBrowserTest,
+                       MAYBE_HighDPISurfaceHitTestTest) {
+  SurfaceHitTestTestHelper(shell(), embedded_test_server());
+}
+
+// Test that mouse events are being routed to the correct RenderWidgetHostView
+// when there are nested out-of-process iframes.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       NestedSurfaceHitTestTest) {
+  NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIHitTestBrowserTest,
+                       NestedSurfaceHitTestTest) {
+  NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       OverlapSurfaceHitTestTest) {
+  OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIHitTestBrowserTest,
+                       OverlapSurfaceHitTestTest) {
+  OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       HitTestLayerSquashing) {
+  HitTestLayerSquashing(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIHitTestBrowserTest,
+                       HitTestLayerSquashing) {
+  HitTestLayerSquashing(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest, HitTestWatermark) {
+  HitTestWatermark(shell(), embedded_test_server());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIHitTestBrowserTest,
+                       HitTestWatermark) {
+  HitTestWatermark(shell(), embedded_test_server());
+}
+
+// This test tests that browser process hittesting ignores frames with
+// pointer-events: none.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       SurfaceHitTestPointerEventsNone) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame_pointer-events_none.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  // Create listeners for mouse events.
+  RenderWidgetHostMouseEventMonitor main_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor child_frame_monitor(
+      child_node->current_frame_host()->GetRenderWidgetHost());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents()->GetInputEventRouter();
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  // Target input event to child frame.
+  blink::WebMouseEvent child_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  child_event.button = blink::WebPointerProperties::Button::kLeft;
+  child_event.SetPositionInWidget(75, 75);
+  child_event.click_count = 1;
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  router->RouteMouseEvent(root_view, &child_event, ui::LatencyInfo());
+
+  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().y, 2);
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+}
+
+// Verify that an event is properly retargeted to the main frame when an
+// asynchronous hit test to the child frame times out.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       AsynchronousHitTestChildTimeout) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_busy_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+
+  // Create listeners for mouse events.
+  RenderWidgetHostMouseEventMonitor main_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor child_frame_monitor(
+      child_node->current_frame_host()->GetRenderWidgetHost());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents()->GetInputEventRouter();
+
+  // Shorten the timeout for purposes of this test.
+  router->GetRenderWidgetTargeterForTests()
+      ->set_async_hit_test_timeout_delay_for_testing(
+          TestTimeouts::tiny_timeout());
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  // Target input event to child frame. It should get delivered to the main
+  // frame instead because the child frame main thread is non-responsive.
+  blink::WebMouseEvent child_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  child_event.button = blink::WebPointerProperties::Button::kLeft;
+  child_event.SetPositionInWidget(75, 75);
+  child_event.click_count = 1;
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, root_view,
+                                      &child_event);
+
+  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().y, 2);
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+}
+
+// This test verifies that MouseEnter and MouseLeave events fire correctly
+// when the mouse cursor moves between processes.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       CrossProcessMouseEnterAndLeaveTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b,c(d))"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  EXPECT_EQ(
+      " Site A ------------ proxies for B C D\n"
+      "   |--Site B ------- proxies for A C D\n"
+      "   +--Site C ------- proxies for A B D\n"
+      "        +--Site D -- proxies for A B C\n"
+      "Where A = http://a.com/\n"
+      "      B = http://b.com/\n"
+      "      C = http://c.com/\n"
+      "      D = http://d.com/",
+      DepictFrameTree(root));
+
+  FrameTreeNode* b_node = root->child_at(0);
+  FrameTreeNode* c_node = root->child_at(1);
+  FrameTreeNode* d_node = c_node->child_at(0);
+
+  RenderWidgetHostViewBase* rwhv_a = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_b = static_cast<RenderWidgetHostViewBase*>(
+      b_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_d = static_cast<RenderWidgetHostViewBase*>(
+      d_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  // Verifying surfaces are ready in B and D are sufficient, since other
+  // surfaces contain at least one of them.
+  WaitForChildFrameSurfaceReady(b_node->current_frame_host());
+  WaitForChildFrameSurfaceReady(d_node->current_frame_host());
+
+  // Create listeners for mouse events. These are used to verify that the
+  // RenderWidgetHostInputEventRouter is generating MouseLeave, etc for
+  // the right renderers.
+  RenderWidgetHostMouseEventMonitor root_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor a_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor b_frame_monitor(
+      b_node->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor c_frame_monitor(
+      c_node->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor d_frame_monitor(
+      d_node->current_frame_host()->GetRenderWidgetHost());
+
+  float scale_factor = GetPageScaleFactor(shell());
+
+  // Get the view bounds of the child iframe, which should account for the
+  // relative offset of its direct parent within the root frame, for use in
+  // targeting the input event.
+  gfx::Rect a_bounds = rwhv_a->GetViewBounds();
+  gfx::Rect b_bounds = rwhv_b->GetViewBounds();
+  gfx::Rect d_bounds = rwhv_d->GetViewBounds();
+
+  gfx::Point point_in_a_frame(2, 2);
+  gfx::Point point_in_b_frame(
+      gfx::ToCeiledInt((b_bounds.x() - a_bounds.x() + 25) * scale_factor),
+      gfx::ToCeiledInt((b_bounds.y() - a_bounds.y() + 25) * scale_factor));
+  gfx::Point point_in_d_frame(
+      gfx::ToCeiledInt((d_bounds.x() - a_bounds.x() + 25) * scale_factor),
+      gfx::ToCeiledInt((d_bounds.y() - a_bounds.y() + 25) * scale_factor));
+
+  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseMove,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  mouse_event.SetPositionInWidget(point_in_a_frame.x(), point_in_a_frame.y());
+
+  // Send an initial MouseMove to the root view, which shouldn't affect the
+  // other renderers.
+  web_contents()->GetInputEventRouter()->RouteMouseEvent(rwhv_a, &mouse_event,
+                                                         ui::LatencyInfo());
+  EXPECT_TRUE(a_frame_monitor.EventWasReceived());
+  a_frame_monitor.ResetEventReceived();
+  EXPECT_FALSE(b_frame_monitor.EventWasReceived());
+  EXPECT_FALSE(c_frame_monitor.EventWasReceived());
+  EXPECT_FALSE(d_frame_monitor.EventWasReceived());
+
+  // Next send a MouseMove to B frame, which shouldn't affect C or D but
+  // A should receive a MouseMove event.
+  mouse_event.SetPositionInWidget(point_in_b_frame.x(), point_in_b_frame.y());
+  auto* router = web_contents()->GetInputEventRouter();
+  RouteMouseEventAndWaitUntilDispatch(router, rwhv_a, rwhv_b, &mouse_event);
+  EXPECT_TRUE(a_frame_monitor.EventWasReceived());
+  EXPECT_EQ(a_frame_monitor.event().GetType(),
+            blink::WebInputEvent::kMouseMove);
+  a_frame_monitor.ResetEventReceived();
+  EXPECT_TRUE(b_frame_monitor.EventWasReceived());
+  b_frame_monitor.ResetEventReceived();
+  EXPECT_FALSE(c_frame_monitor.EventWasReceived());
+  EXPECT_FALSE(d_frame_monitor.EventWasReceived());
+
+  // Next send a MouseMove to D frame, which should have side effects in every
+  // other RenderWidgetHostView.
+  mouse_event.SetPositionInWidget(point_in_d_frame.x(), point_in_d_frame.y());
+  RouteMouseEventAndWaitUntilDispatch(router, rwhv_a, rwhv_d, &mouse_event);
+  EXPECT_TRUE(a_frame_monitor.EventWasReceived());
+  EXPECT_EQ(a_frame_monitor.event().GetType(),
+            blink::WebInputEvent::kMouseMove);
+  EXPECT_TRUE(b_frame_monitor.EventWasReceived());
+  EXPECT_EQ(b_frame_monitor.event().GetType(),
+            blink::WebInputEvent::kMouseLeave);
+  EXPECT_TRUE(c_frame_monitor.EventWasReceived());
+  EXPECT_EQ(c_frame_monitor.event().GetType(),
+            blink::WebInputEvent::kMouseMove);
+  EXPECT_TRUE(d_frame_monitor.EventWasReceived());
+}
+
+// Verify that mouse capture works on a RenderWidgetHostView level, so that
+// dragging scroll bars and selecting text continues even when the mouse
+// cursor crosses over cross-process frame boundaries.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       CrossProcessMouseCapture) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  // Create listeners for mouse events.
+  RenderWidgetHostMouseEventMonitor main_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor child_frame_monitor(
+      child_node->current_frame_host()->GetRenderWidgetHost());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents()->GetInputEventRouter();
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  float scale_factor = GetPageScaleFactor(shell());
+
+  // Get the view bounds of the child iframe, which should account for the
+  // relative offset of its direct parent within the root frame, for use in
+  // targeting the input event.
+  gfx::Rect bounds = rwhv_child->GetViewBounds();
+  int child_frame_target_x = gfx::ToCeiledInt(
+      (bounds.x() - root_view->GetViewBounds().x() + 5) * scale_factor);
+  int child_frame_target_y = gfx::ToCeiledInt(
+      (bounds.y() - root_view->GetViewBounds().y() + 5) * scale_factor);
+
+  // Target MouseDown to child frame.
+  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  mouse_event.button = blink::WebPointerProperties::Button::kLeft;
+  mouse_event.SetPositionInWidget(child_frame_target_x, child_frame_target_y);
+  mouse_event.click_count = 1;
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
+                                      &mouse_event);
+
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+
+  // Target MouseMove to main frame. This should still be routed to the
+  // child frame because it is now capturing mouse input.
+  mouse_event.SetType(blink::WebInputEvent::kMouseMove);
+  mouse_event.SetModifiers(blink::WebInputEvent::kLeftButtonDown);
+  mouse_event.SetPositionInWidget(1, 1);
+  // Note that this event is sent twice, with the monitors cleared after
+  // the first time, because the first MouseMove to the child frame
+  // causes a MouseMove to be sent to the main frame also, which we
+  // need to ignore.
+  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  mouse_event.SetPositionInWidget(1, 5);
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
+                                      &mouse_event);
+
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+
+  // A MouseUp to the child frame should cancel the mouse capture.
+  mouse_event.SetType(blink::WebInputEvent::kMouseUp);
+  mouse_event.SetModifiers(blink::WebInputEvent::kNoModifiers);
+  mouse_event.SetPositionInWidget(child_frame_target_x, child_frame_target_y);
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
+                                      &mouse_event);
+
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+
+  // Subsequent MouseMove events targeted to the main frame should be routed
+  // to that frame.
+  mouse_event.SetType(blink::WebInputEvent::kMouseMove);
+  mouse_event.SetPositionInWidget(1, 10);
+  // Sending the MouseMove twice for the same reason as above.
+  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  mouse_event.SetPositionInWidget(1, 15);
+  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
+
+  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+
+  // Target MouseDown to the main frame to cause it to capture input.
+  mouse_event.SetType(blink::WebInputEvent::kMouseDown);
+  mouse_event.SetPositionInWidget(1, 20);
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
+
+  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+
+  // Sending a MouseMove to the child frame should still result in the main
+  // frame receiving the event.
+  mouse_event.SetType(blink::WebInputEvent::kMouseMove);
+  mouse_event.SetModifiers(blink::WebInputEvent::kLeftButtonDown);
+  mouse_event.SetPositionInWidget(child_frame_target_x, child_frame_target_y);
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
+
+  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+}
+
+// There are no cursors on Android.
+#if !defined(OS_ANDROID)
+class CursorMessageFilter : public content::BrowserMessageFilter {
+ public:
+  CursorMessageFilter()
+      : content::BrowserMessageFilter(ViewMsgStart),
+        message_loop_runner_(new content::MessageLoopRunner),
+        last_set_cursor_routing_id_(MSG_ROUTING_NONE) {}
+
+  bool OnMessageReceived(const IPC::Message& message) override {
+    if (message.type() == ViewHostMsg_SetCursor::ID) {
+      content::BrowserThread::PostTask(
+          content::BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&CursorMessageFilter::OnSetCursor, this,
+                         message.routing_id()));
+    }
+    return false;
+  }
+
+  void OnSetCursor(int routing_id) {
+    last_set_cursor_routing_id_ = routing_id;
+    message_loop_runner_->Quit();
+  }
+
+  int last_set_cursor_routing_id() const { return last_set_cursor_routing_id_; }
+
+  void Wait() {
+    // Do not reset the cursor, as the cursor may already have been set (and
+    // Quit() already called on |message_loop_runner_|).
+    message_loop_runner_->Run();
+  }
+
+ private:
+  ~CursorMessageFilter() override {}
+
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  int last_set_cursor_routing_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(CursorMessageFilter);
+};
+
+// Verify that we receive a mouse cursor update message when we mouse over
+// a text field contained in an out-of-process iframe.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       CursorUpdateReceivedFromCrossSiteIframe) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+  FrameTreeNode* child_node = root->child_at(0);
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  scoped_refptr<CursorMessageFilter> filter = new CursorMessageFilter();
+  child_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHost* rwh_child =
+      root->child_at(0)->current_frame_host()->GetRenderWidgetHost();
+  RenderWidgetHostViewBase* child_view =
+      static_cast<RenderWidgetHostViewBase*>(rwh_child->GetView());
+
+  // This should only return nullptr on Android.
+  EXPECT_TRUE(root_view->GetCursorManager());
+
+  WebCursor cursor;
+  EXPECT_FALSE(
+      root_view->GetCursorManager()->GetCursorForTesting(root_view, cursor));
+  EXPECT_FALSE(
+      root_view->GetCursorManager()->GetCursorForTesting(child_view, cursor));
+
+  // Send a MouseMove to the subframe. The frame contains text, and moving the
+  // mouse over it should cause the renderer to send a mouse cursor update.
+  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseMove,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  mouse_event.SetPositionInWidget(60, 60);
+  auto* router = web_contents()->GetInputEventRouter();
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, child_view,
+                                      &mouse_event);
+
+  // CursorMessageFilter::Wait() implicitly tests whether we receive a
+  // ViewHostMsg_SetCursor message from the renderer process, because it does
+  // does not return otherwise.
+  filter->Wait();
+  EXPECT_EQ(filter->last_set_cursor_routing_id(), rwh_child->GetRoutingID());
+
+  // Yield to ensure that the SetCursor message is processed by its real
+  // handler.
+  {
+    base::RunLoop loop;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  loop.QuitClosure());
+    loop.Run();
+  }
+
+  // The |root_view| ends up getting a mouse-leave event, causing it to send an
+  // updated cursor for the view.
+  EXPECT_TRUE(
+      root_view->GetCursorManager()->GetCursorForTesting(root_view, cursor));
+  EXPECT_TRUE(
+      root_view->GetCursorManager()->GetCursorForTesting(child_view, cursor));
+  // Since this moused over a text box, this should not be the default cursor.
+  CursorInfo cursor_info;
+  cursor.GetCursorInfo(&cursor_info);
+  EXPECT_EQ(cursor_info.type, blink::WebCursorInfo::kTypeIBeam);
+}
+#endif  // !defined(OS_ANDROID)
+
+#if defined(USE_AURA)
+// Browser process hit testing is not implemented on Android, and these tests
+// require Aura for RenderWidgetHostViewAura::OnTouchEvent().
+// https://crbug.com/491334
+
+// Ensure that scroll events can be cancelled with a wheel handler.
+// https://crbug.com/698195
+
+class SitePerProcessMouseWheelHitTestBrowserTest
+    : public SitePerProcessBrowserTest {
+ public:
+  SitePerProcessMouseWheelHitTestBrowserTest() : rwhv_root_(nullptr) {}
+
+  void SetupWheelAndScrollHandlers(content::RenderFrameHostImpl* rfh) {
+    // Set up event handlers. The wheel event handler calls prevent default on
+    // alternate events, so only every other wheel generates a scroll. The fact
+    // that any scroll events fire is dependent on the event going to the main
+    // thread, which requires the nonFastScrollableRegion be set correctly
+    // on the compositor.
+    std::string script =
+        "wheel_count = 0;"
+        "function wheel_handler(e) {"
+        "  wheel_count++;"
+        "  if (wheel_count % 2 == 0)"
+        "    e.preventDefault();\n"
+        "  domAutomationController.send('wheel: ' + wheel_count);"
+        "}"
+        "function scroll_handler(e) {"
+        "  domAutomationController.send('scroll: ' + wheel_count);"
+        "}"
+        "scroll_div = document.getElementById('scrollable_div');"
+        "scroll_div.addEventListener('wheel', wheel_handler);"
+        "scroll_div.addEventListener('scroll', scroll_handler);"
+        "document.body.style.background = 'black';";
+
+    content::DOMMessageQueue msg_queue;
+    std::string reply;
+    EXPECT_TRUE(ExecuteScript(rfh, script));
+
+    // Wait until renderer's compositor thread is synced. Otherwise the event
+    // handler won't be installed when the event arrives.
+    {
+      MainThreadFrameObserver observer(rfh->GetRenderWidgetHost());
+      observer.Wait();
+    }
+  }
+
+  void SendMouseWheel(gfx::Point location) {
+    DCHECK(rwhv_root_);
+    ui::ScrollEvent scroll_event(ui::ET_SCROLL, location, ui::EventTimeForNow(),
+                                 0, 0, -ui::MouseWheelEvent::kWheelDelta, 0,
+                                 ui::MouseWheelEvent::kWheelDelta,
+                                 2);  // This must be '2' or it gets silently
+                                      // dropped.
+    rwhv_root_->OnScrollEvent(&scroll_event);
+  }
+
+  void set_rwhv_root(RenderWidgetHostViewAura* rwhv_root) {
+    rwhv_root_ = rwhv_root;
+  }
+
+  void RunTest(gfx::Point pos, RenderWidgetHostViewBase* expected_target) {
+    content::DOMMessageQueue msg_queue;
+    std::string reply;
+
+    auto* rwhv_root = static_cast<RenderWidgetHostViewAura*>(
+        web_contents()->GetRenderWidgetHostView());
+    set_rwhv_root(rwhv_root);
+
+    InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
+                               blink::WebInputEvent::kMouseWheel);
+    SendMouseWheel(pos);
+    waiter.Wait();
+
+    // Expect both wheel and scroll handlers to fire.
+    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
+    EXPECT_EQ("\"wheel: 1\"", reply);
+    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
+    EXPECT_EQ("\"scroll: 1\"", reply);
+
+    SendMouseWheel(pos);
+
+    // If async_wheel_events is disabled, this time only the wheel handler
+    // fires, since even numbered scrolls are prevent-defaulted. If it is
+    // enabled, then this wheel event will be sent non-blockingly and won't be
+    // cancellable.
+    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
+    EXPECT_EQ("\"wheel: 2\"", reply);
+    if (base::FeatureList::IsEnabled(features::kAsyncWheelEvents) &&
+        base::FeatureList::IsEnabled(
+            features::kTouchpadAndWheelScrollLatching)) {
+      EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
+      EXPECT_EQ("\"scroll: 2\"", reply);
+    }
+
+    SendMouseWheel(pos);
+
+    // Odd number of wheels, expect both wheel and scroll handlers to fire
+    // again.
+    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
+    EXPECT_EQ("\"wheel: 3\"", reply);
+    EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
+    EXPECT_EQ("\"scroll: 3\"", reply);
+  }
+
+ private:
+  RenderWidgetHostViewAura* rwhv_root_;
+};
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessMouseWheelHitTestBrowserTest,
+                       SubframeWheelEventsOnMainThread) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  GURL frame_url(embedded_test_server()->GetURL(
+      "b.com", "/page_with_scrollable_div.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url);
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
+      root->child_at(0)->current_frame_host()->GetView());
+  WaitForChildFrameSurfaceReady(root->child_at(0)->current_frame_host());
+
+  content::RenderFrameHostImpl* child = root->child_at(0)->current_frame_host();
+  SetupWheelAndScrollHandlers(child);
+
+  gfx::Rect bounds = child_rwhv->GetViewBounds();
+  gfx::Point pos(bounds.x() + 10, bounds.y() + 10);
+
+  RunTest(pos, child_rwhv);
+}
+
+// Verifies that test in SubframeWheelEventsOnMainThread also makes sense for
+// the same page loaded in the mainframe.
+IN_PROC_BROWSER_TEST_F(SitePerProcessMouseWheelHitTestBrowserTest,
+                       MainframeWheelEventsOnMainThread) {
+  GURL main_url(
+      embedded_test_server()->GetURL("/page_with_scrollable_div.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  content::RenderFrameHostImpl* rfhi = root->current_frame_host();
+  SetupWheelAndScrollHandlers(rfhi);
+
+  gfx::Point pos(10, 10);
+
+  RunTest(pos, rfhi->GetRenderWidgetHost()->GetView());
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessMouseWheelHitTestBrowserTest,
+                       InputEventRouterWheelTargetTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  auto* rwhv_root = static_cast<RenderWidgetHostViewAura*>(
+      web_contents()->GetRenderWidgetHostView());
+  set_rwhv_root(rwhv_root);
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  GURL frame_url(embedded_test_server()->GetURL(
+      "b.com", "/page_with_scrollable_div.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url);
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>(
+      root->child_at(0)->current_frame_host()->GetView());
+  WaitForChildFrameSurfaceReady(root->child_at(0)->current_frame_host());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents()->GetInputEventRouter();
+
+  // Send a mouse wheel event to child.
+  gfx::Rect bounds = child_rwhv->GetViewBounds();
+  gfx::Point pos(bounds.x() + 10, bounds.y() + 10);
+  InputEventAckWaiter waiter(child_rwhv->GetRenderWidgetHost(),
+                             blink::WebInputEvent::kMouseWheel);
+  SendMouseWheel(pos);
+  waiter.Wait();
+
+  if (child_rwhv->wheel_scroll_latching_enabled())
+    EXPECT_EQ(child_rwhv, router->wheel_target_.target);
+  else
+    EXPECT_EQ(nullptr, router->wheel_target_.target);
+
+  // Send a mouse wheel event to the main frame. If wheel scroll latching is
+  // enabled it will be still routed to child till the end of current scrolling
+  // sequence. Since wheel scroll latching is enabled by default, we always do
+  // sync targeting so InputEventAckWaiter is not needed here.
+  TestInputEventObserver child_frame_monitor(child_rwhv->GetRenderWidgetHost());
+  SendMouseWheel(pos);
+  if (child_rwhv->wheel_scroll_latching_enabled())
+    EXPECT_EQ(child_rwhv, router->wheel_target_.target);
+  else
+    EXPECT_EQ(nullptr, router->wheel_target_.target);
+  // Verify that this a mouse wheel event was sent to the child frame renderer.
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  EXPECT_EQ(child_frame_monitor.EventType(), blink::WebInputEvent::kMouseWheel);
+
+  // Kill the wheel target view process. This must reset the wheel_target_.
+  RenderProcessHost* child_process =
+      root->child_at(0)->current_frame_host()->GetProcess();
+  RenderProcessHostWatcher crash_observer(
+      child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  child_process->Shutdown(0, false);
+  crash_observer.Wait();
+  EXPECT_EQ(nullptr, router->wheel_target_.target);
+}
+
+// Ensure that a cross-process subframe with a touch-handler can receive touch
+// events.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       SubframeTouchEventRouting) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  WebContentsImpl* contents = web_contents();
+  FrameTreeNode* root = contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  GURL frame_url(
+      embedded_test_server()->GetURL("b.com", "/page_with_touch_handler.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url);
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  WaitForChildFrameSurfaceReady(root->child_at(0)->current_frame_host());
+
+  // There's no intrinsic reason the following values can't be equal, but they
+  // aren't at present, and if they become the same this test will need to be
+  // updated to accommodate.
+  EXPECT_NE(cc::kTouchActionAuto, cc::kTouchActionNone);
+
+  // Verify the child's input router is initially set for kTouchActionAuto. The
+  // TouchStart event will trigger kTouchActionNone being sent back to the
+  // browser.
+  RenderWidgetHostImpl* child_render_widget_host =
+      root->child_at(0)->current_frame_host()->GetRenderWidgetHost();
+  EXPECT_EQ(cc::kTouchActionAuto,
+            child_render_widget_host->input_router()->AllowedTouchAction());
+
+  InputEventAckWaiter waiter(child_render_widget_host,
+                             blink::WebInputEvent::kTouchStart);
+
+  // Simulate touch event to sub-frame.
+  gfx::Point child_center(150, 150);
+  auto* rwhv = static_cast<RenderWidgetHostViewAura*>(
+      contents->GetRenderWidgetHostView());
+
+  // Wait until renderer's compositor thread is synced.
+  {
+    MainThreadFrameObserver observer(child_render_widget_host);
+    observer.Wait();
+  }
+
+  ui::TouchEvent touch_event(
+      ui::ET_TOUCH_PRESSED, child_center, ui::EventTimeForNow(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
+                         /* pointer_id*/ 0,
+                         /* radius_x */ 30.0f,
+                         /* radius_y */ 30.0f,
+                         /* force */ 0.0f));
+  rwhv->OnTouchEvent(&touch_event);
+  waiter.Wait();
+  {
+    MainThreadFrameObserver observer(child_render_widget_host);
+    observer.Wait();
+  }
+
+  // Verify touch handler in subframe was invoked.
+  std::string result;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      root->child_at(0),
+      "window.domAutomationController.send(getLastTouchEvent());", &result));
+  EXPECT_EQ("touchstart", result);
+
+  // Verify the presence of the touch handler in the child frame correctly
+  // propagates touch-action:none information back to the child's input router.
+  EXPECT_EQ(cc::kTouchActionNone,
+            child_render_widget_host->input_router()->AllowedTouchAction());
+}
+
+// This test verifies that the test in
+// SitePerProcessHitTestBrowserTest.SubframeTouchEventRouting also works
+// properly for the main frame. Prior to the CL in which this test is
+// introduced, use of MainThreadFrameObserver in SubframeTouchEventRouting was
+// not necessary since the touch events were handled on the main thread. Now
+// they are handled on the compositor thread, hence the need to synchronize.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       MainframeTouchEventRouting) {
+  GURL main_url(
+      embedded_test_server()->GetURL("/page_with_touch_handler.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  WebContentsImpl* contents = web_contents();
+  FrameTreeNode* root = contents->GetFrameTree()->root();
+
+  // Synchronize with the renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  auto* rwhv = static_cast<RenderWidgetHostViewAura*>(
+      contents->GetRenderWidgetHostView());
+
+  // There's no intrinsic reason the following values can't be equal, but they
+  // aren't at present, and if they become the same this test will need to be
+  // updated to accommodate.
+  EXPECT_NE(cc::kTouchActionAuto, cc::kTouchActionNone);
+
+  // Verify the main frame's input router is initially set for
+  // kTouchActionAuto. The
+  // TouchStart event will trigger kTouchActionNone being sent back to the
+  // browser.
+  RenderWidgetHostImpl* render_widget_host =
+      root->current_frame_host()->GetRenderWidgetHost();
+  EXPECT_EQ(cc::kTouchActionAuto,
+            render_widget_host->input_router()->AllowedTouchAction());
+
+  // Simulate touch event to sub-frame.
+  gfx::Point frame_center(150, 150);
+
+  // Wait until renderer's compositor thread is synced.
+  {
+    auto observer =
+        std::make_unique<MainThreadFrameObserver>(render_widget_host);
+    observer->Wait();
+  }
+
+  ui::TouchEvent touch_event(
+      ui::ET_TOUCH_PRESSED, frame_center, ui::EventTimeForNow(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
+                         /* pointer_id*/ 0,
+                         /* radius_x */ 30.0f,
+                         /* radius_y */ 30.0f,
+                         /* force */ 0.0f));
+  rwhv->OnTouchEvent(&touch_event);
+  {
+    auto observer =
+        std::make_unique<MainThreadFrameObserver>(render_widget_host);
+    observer->Wait();
+  }
+
+  // Verify touch handler in subframe was invoked.
+  std::string result;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      root, "window.domAutomationController.send(getLastTouchEvent());",
+      &result));
+  EXPECT_EQ("touchstart", result);
+
+  // Verify the presence of the touch handler in the child frame correctly
+  // propagates touch-action:none information back to the child's input router.
+  EXPECT_EQ(cc::kTouchActionNone,
+            render_widget_host->input_router()->AllowedTouchAction());
+}
+
+namespace {
+
+// Declared here to be close to the SubframeGestureEventRouting test.
+void OnSyntheticGestureCompleted(scoped_refptr<MessageLoopRunner> runner,
+                                 SyntheticGesture::Result result) {
+  EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
+  runner->Quit();
+}
+
+}  // anonymous namespace
+
+// https://crbug.com/592320
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       DISABLED_SubframeGestureEventRouting) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  GURL frame_url(
+      embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url);
+  auto* child_frame_host = root->child_at(0)->current_frame_host();
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  WaitForChildFrameSurfaceReady(child_frame_host);
+
+  // There have been no GestureTaps sent yet.
+  {
+    std::string result;
+    EXPECT_TRUE(ExecuteScriptAndExtractString(
+        child_frame_host,
+        "window.domAutomationController.send(getClickStatus());", &result));
+    EXPECT_EQ("0 clicks received", result);
+  }
+
+  // Simulate touch sequence to send GestureTap to sub-frame.
+  SyntheticTapGestureParams params;
+  params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
+  gfx::Point center(150, 150);
+  params.position = gfx::PointF(center.x(), center.y());
+  params.duration_ms = 100;
+  std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params));
+
+  scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner();
+
+  RenderWidgetHostImpl* render_widget_host =
+      root->current_frame_host()->GetRenderWidgetHost();
+  // TODO(wjmaclean): Convert the call to base::Bind() to a lambda someday.
+  render_widget_host->QueueSyntheticGesture(
+      std::move(gesture), base::BindOnce(OnSyntheticGestureCompleted, runner));
+
+  // We need to run the message loop while we wait for the synthetic gesture
+  // to be processed; the callback registered above will get us out of the
+  // message loop when that happens.
+  runner->Run();
+  runner = nullptr;
+
+  // Verify click handler in subframe was invoked
+  {
+    std::string result;
+    EXPECT_TRUE(ExecuteScriptAndExtractString(
+        child_frame_host,
+        "window.domAutomationController.send(getClickStatus());", &result));
+    EXPECT_EQ("1 click received", result);
+  }
+}
+
+namespace {
+
+// Defined here to be close to
+// SitePerProcessHitTestBrowserTest.InputEventRouterGestureTargetQueueTest.
+// Will wait for RenderWidgetHost's compositor thread to sync if one is given.
+// Returns the unique_touch_id of the TouchStart.
+uint32_t SendTouchTapWithExpectedTarget(
+    RenderWidgetHostViewBase* root_view,
+    const gfx::Point& touch_point,
+    RenderWidgetHostViewBase*& router_touch_target,
+    const RenderWidgetHostViewBase* expected_target,
+    RenderWidgetHostImpl* child_render_widget_host) {
+  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
+  if (child_render_widget_host != nullptr) {
+    MainThreadFrameObserver observer(child_render_widget_host);
+    observer.Wait();
+  }
+  ui::TouchEvent touch_event_pressed(
+      ui::ET_TOUCH_PRESSED, touch_point, ui::EventTimeForNow(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
+                         /* pointer_id*/ 0,
+                         /* radius_x */ 30.0f,
+                         /* radius_y */ 30.0f,
+                         /* force */ 0.0f));
+  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
+                             blink::WebInputEvent::kTouchStart);
+  root_view_aura->OnTouchEvent(&touch_event_pressed);
+  if (child_render_widget_host != nullptr) {
+    MainThreadFrameObserver observer(child_render_widget_host);
+    observer.Wait();
+  }
+  waiter.Wait();
+  EXPECT_EQ(expected_target, router_touch_target);
+  ui::TouchEvent touch_event_released(
+      ui::ET_TOUCH_RELEASED, touch_point, ui::EventTimeForNow(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
+                         /* pointer_id*/ 0,
+                         /* radius_x */ 30.0f,
+                         /* radius_y */ 30.0f,
+                         /* force */ 0.0f));
+  root_view_aura->OnTouchEvent(&touch_event_released);
+  if (child_render_widget_host != nullptr) {
+    MainThreadFrameObserver observer(child_render_widget_host);
+    observer.Wait();
+  }
+  EXPECT_EQ(nullptr, router_touch_target);
+  return touch_event_pressed.unique_event_id();
+}
+
+void SendGestureTapSequenceWithExpectedTarget(
+    RenderWidgetHostViewBase* root_view,
+    const gfx::Point& gesture_point,
+    RenderWidgetHostViewBase*& router_gesture_target,
+    const RenderWidgetHostViewBase* old_expected_target,
+    const RenderWidgetHostViewBase* expected_target,
+    const uint32_t unique_touch_event_id) {
+  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
+
+  ui::GestureEventDetails gesture_begin_details(ui::ET_GESTURE_BEGIN);
+  gesture_begin_details.set_device_type(
+      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  ui::GestureEvent gesture_begin_event(
+      gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+      gesture_begin_details, unique_touch_event_id);
+  root_view_aura->OnGestureEvent(&gesture_begin_event);
+  // We expect to still have the old gesture target in place for the
+  // GestureFlingCancel that will be inserted before GestureTapDown.
+  // Note: the GestureFlingCancel is inserted by RenderWidgetHostViewAura::
+  // OnGestureEvent() when it sees ui::ET_GESTURE_TAP_DOWN, so we don't
+  // explicitly add it here.
+  EXPECT_EQ(old_expected_target, router_gesture_target);
+
+  ui::GestureEventDetails gesture_tap_down_details(ui::ET_GESTURE_TAP_DOWN);
+  gesture_tap_down_details.set_device_type(
+      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  ui::GestureEvent gesture_tap_down_event(
+      gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+      gesture_tap_down_details, unique_touch_event_id);
+  root_view_aura->OnGestureEvent(&gesture_tap_down_event);
+  EXPECT_EQ(expected_target, router_gesture_target);
+
+  ui::GestureEventDetails gesture_show_press_details(ui::ET_GESTURE_SHOW_PRESS);
+  gesture_show_press_details.set_device_type(
+      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  ui::GestureEvent gesture_show_press_event(
+      gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
+      gesture_show_press_details, unique_touch_event_id);
+  root_view_aura->OnGestureEvent(&gesture_show_press_event);
+  EXPECT_EQ(expected_target, router_gesture_target);
+
+  ui::GestureEventDetails gesture_tap_details(ui::ET_GESTURE_TAP);
+  gesture_tap_details.set_device_type(
+      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  gesture_tap_details.set_tap_count(1);
+  ui::GestureEvent gesture_tap_event(gesture_point.x(), gesture_point.y(), 0,
+                                     ui::EventTimeForNow(), gesture_tap_details,
+                                     unique_touch_event_id);
+  root_view_aura->OnGestureEvent(&gesture_tap_event);
+  EXPECT_EQ(expected_target, router_gesture_target);
+
+  ui::GestureEventDetails gesture_end_details(ui::ET_GESTURE_END);
+  gesture_end_details.set_device_type(
+      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  ui::GestureEvent gesture_end_event(gesture_point.x(), gesture_point.y(), 0,
+                                     ui::EventTimeForNow(), gesture_end_details,
+                                     unique_touch_event_id);
+  root_view_aura->OnGestureEvent(&gesture_end_event);
+  EXPECT_EQ(expected_target, router_gesture_target);
+}
+
+void SendTouchpadPinchSequenceWithExpectedTarget(
+    RenderWidgetHostViewBase* root_view,
+    const gfx::Point& gesture_point,
+    RenderWidgetHostViewBase*& router_touchpad_gesture_target,
+    RenderWidgetHostViewBase* expected_target) {
+  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
+
+  ui::GestureEventDetails pinch_begin_details(ui::ET_GESTURE_PINCH_BEGIN);
+  pinch_begin_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+  ui::GestureEvent pinch_begin(gesture_point.x(), gesture_point.y(), 0,
+                               ui::EventTimeForNow(), pinch_begin_details);
+  TestInputEventObserver target_monitor(expected_target->GetRenderWidgetHost());
+  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
+                             blink::WebInputEvent::kGesturePinchBegin);
+  root_view_aura->OnGestureEvent(&pinch_begin);
+  // If the expected target is not the root, then we should be doing async
+  // targeting first. So event dispatch should not happen synchronously.
+  // Validate that the expected target does not receive the event immediately in
+  // such cases.
+  if (root_view != expected_target)
+    EXPECT_FALSE(target_monitor.EventWasReceived());
+  waiter.Wait();
+  EXPECT_TRUE(target_monitor.EventWasReceived());
+  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
+  target_monitor.ResetEventsReceived();
+
+  ui::GestureEventDetails pinch_update_details(ui::ET_GESTURE_PINCH_UPDATE);
+  pinch_update_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+  ui::GestureEvent pinch_update(gesture_point.x(), gesture_point.y(), 0,
+                                ui::EventTimeForNow(), pinch_update_details);
+  root_view_aura->OnGestureEvent(&pinch_update);
+  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
+  EXPECT_TRUE(target_monitor.EventWasReceived());
+  EXPECT_EQ(target_monitor.EventType(),
+            blink::WebInputEvent::kGesturePinchUpdate);
+  target_monitor.ResetEventsReceived();
+
+  ui::GestureEventDetails pinch_end_details(ui::ET_GESTURE_PINCH_END);
+  pinch_end_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
+  ui::GestureEvent pinch_end(gesture_point.x(), gesture_point.y(), 0,
+                             ui::EventTimeForNow(), pinch_end_details);
+  root_view_aura->OnGestureEvent(&pinch_end);
+  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
+  EXPECT_TRUE(target_monitor.EventWasReceived());
+  EXPECT_EQ(target_monitor.EventType(), blink::WebInputEvent::kGesturePinchEnd);
+}
+
+#if !defined(OS_WIN)
+// Sending touchpad fling events is not supported on Windows.
+void SendTouchpadFlingSequenceWithExpectedTarget(
+    RenderWidgetHostViewBase* root_view,
+    const gfx::Point& gesture_point,
+    RenderWidgetHostViewBase*& router_touchpad_gesture_target,
+    RenderWidgetHostViewBase* expected_target) {
+  auto* root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view);
+
+  if (root_view_aura->wheel_scroll_latching_enabled()) {
+    // Touchpad Fling must be sent inside a gesture scroll seqeunce.
+    blink::WebGestureEvent gesture_event(
+        blink::WebGestureEvent::kGestureScrollBegin,
+        blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::kTimeStampForTesting);
+    gesture_event.source_device = blink::kWebGestureDeviceTouchpad;
+    gesture_event.x = gesture_point.x();
+    gesture_event.y = gesture_point.y();
+    gesture_event.data.scroll_begin.delta_x_hint = 0.0f;
+    gesture_event.data.scroll_begin.delta_y_hint = 1.0f;
+    expected_target->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event);
+  }
+
+  ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gesture_point,
+                              ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1);
+  TestInputEventObserver target_monitor(expected_target->GetRenderWidgetHost());
+  InputEventAckWaiter waiter(expected_target->GetRenderWidgetHost(),
+                             blink::WebInputEvent::kGestureFlingStart);
+  root_view_aura->OnScrollEvent(&fling_start);
+  // If the expected target is not the root, then we should be doing async
+  // targeting first. So event dispatch should not happen synchronously.
+  // Validate that the expected target does not receive the event immediately in
+  // such cases.
+  if (root_view != expected_target)
+    EXPECT_FALSE(target_monitor.EventWasReceived());
+  waiter.Wait();
+  EXPECT_TRUE(target_monitor.EventWasReceived());
+  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
+  target_monitor.ResetEventsReceived();
+
+  ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, gesture_point,
+                               ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1);
+  root_view_aura->OnScrollEvent(&fling_cancel);
+  EXPECT_EQ(expected_target, router_touchpad_gesture_target);
+  EXPECT_TRUE(target_monitor.EventWasReceived());
+  EXPECT_EQ(target_monitor.EventType(),
+            blink::WebInputEvent::kGestureFlingCancel);
+
+  if (root_view_aura->wheel_scroll_latching_enabled()) {
+    blink::WebGestureEvent gesture_event(
+        blink::WebGestureEvent::kGestureScrollEnd,
+        blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::kTimeStampForTesting);
+    gesture_event.source_device = blink::kWebGestureDeviceTouchpad;
+    gesture_event.x = gesture_point.x();
+    gesture_event.y = gesture_point.y();
+    expected_target->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event);
+  }
+}
+#endif  // !defined(OS_WIN)
+
+}  // anonymous namespace
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       InputEventRouterGestureTargetMapTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  WebContentsImpl* contents = web_contents();
+  FrameTreeNode* root = contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  GURL frame_url(
+      embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url);
+  auto* child_frame_host = root->child_at(0)->current_frame_host();
+  auto* rwhv_child =
+      static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView());
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  WaitForChildFrameSurfaceReady(child_frame_host);
+
+  // All touches & gestures are sent to the main frame's view, and should be
+  // routed appropriately from there.
+  auto* rwhv_parent = static_cast<RenderWidgetHostViewBase*>(
+      contents->GetRenderWidgetHostView());
+
+  RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
+  EXPECT_TRUE(router->touchscreen_gesture_target_map_.empty());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send touch sequence to main-frame.
+  gfx::Point main_frame_point(25, 25);
+  uint32_t firstId = SendTouchTapWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
+      nullptr);
+  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send touch sequence to child.
+  gfx::Point child_center(150, 150);
+  uint32_t secondId = SendTouchTapWithExpectedTarget(
+      rwhv_parent, child_center, router->touch_target_.target, rwhv_child,
+      nullptr);
+  EXPECT_EQ(2u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send another touch sequence to main frame.
+  uint32_t thirdId = SendTouchTapWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
+      nullptr);
+  EXPECT_EQ(3u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send Gestures to clear GestureTargetQueue.
+
+  // The first touch sequence should generate a GestureTapDown, sent to the
+  // main frame.
+  SendGestureTapSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
+      nullptr, rwhv_parent, firstId);
+  EXPECT_EQ(2u, router->touchscreen_gesture_target_map_.size());
+  // Note: rwhv_parent is the target used for GestureFlingCancel sent by
+  // RenderWidgetHostViewAura::OnGestureEvent() at the start of the next gesture
+  // sequence; the sequence itself goes to rwhv_child.
+  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
+
+  // The second touch sequence should generate a GestureTapDown, sent to the
+  // child frame.
+  SendGestureTapSequenceWithExpectedTarget(
+      rwhv_parent, child_center, router->touchscreen_gesture_target_.target,
+      rwhv_parent, rwhv_child, secondId);
+  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(rwhv_child, router->touchscreen_gesture_target_.target);
+
+  // The third touch sequence should generate a GestureTapDown, sent to the
+  // main frame.
+  SendGestureTapSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
+      rwhv_child, rwhv_parent, thirdId);
+  EXPECT_EQ(0u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
+}
+
+// TODO: Flaking test crbug.com/802827
+#if defined(OS_WIN)
+#define MAYBE_InputEventRouterGesturePreventDefaultTargetMapTest \
+  DISABLED_InputEventRouterGesturePreventDefaultTargetMapTest
+#else
+#define MAYBE_InputEventRouterGesturePreventDefaultTargetMapTest \
+  InputEventRouterGesturePreventDefaultTargetMapTest
+#endif
+#if defined(USE_AURA) || defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(
+    SitePerProcessHitTestBrowserTest,
+    MAYBE_InputEventRouterGesturePreventDefaultTargetMapTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  WebContentsImpl* contents = web_contents();
+  FrameTreeNode* root = contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  GURL frame_url(embedded_test_server()->GetURL(
+      "b.com", "/page_with_touch_start_default_prevented.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url);
+
+  auto* child_frame_host = root->child_at(0)->current_frame_host();
+  RenderWidgetHostImpl* child_render_widget_host =
+      child_frame_host->GetRenderWidgetHost();
+  auto* rwhv_child =
+      static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView());
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  WaitForChildFrameSurfaceReady(child_frame_host);
+
+  // All touches & gestures are sent to the main frame's view, and should be
+  // routed appropriately from there.
+  auto* rwhv_parent = static_cast<RenderWidgetHostViewBase*>(
+      contents->GetRenderWidgetHostView());
+
+  RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
+  EXPECT_TRUE(router->touchscreen_gesture_target_map_.empty());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send touch sequence to main-frame.
+  gfx::Point main_frame_point(25, 25);
+  uint32_t firstId = SendTouchTapWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
+      child_render_widget_host);
+  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send touch sequence to child.
+  gfx::Point child_center(150, 150);
+  SendTouchTapWithExpectedTarget(rwhv_parent, child_center,
+                                 router->touch_target_.target, rwhv_child,
+                                 child_render_widget_host);
+  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send another touch sequence to main frame.
+  uint32_t thirdId = SendTouchTapWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touch_target_.target, rwhv_parent,
+      child_render_widget_host);
+  EXPECT_EQ(2u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
+
+  // Send Gestures to clear GestureTargetQueue.
+
+  // The first touch sequence should generate a GestureTapDown, sent to the
+  // main frame.
+  SendGestureTapSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
+      nullptr, rwhv_parent, firstId);
+  EXPECT_EQ(1u, router->touchscreen_gesture_target_map_.size());
+  // Note: rwhv_parent is the target used for GestureFlingCancel sent by
+  // RenderWidgetHostViewAura::OnGestureEvent() at the start of the next gesture
+  // sequence; the sequence itself goes to rwhv_child.
+  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
+
+  // The third touch sequence should generate a GestureTapDown, sent to the
+  // main frame.
+  SendGestureTapSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target,
+      rwhv_parent, rwhv_parent, thirdId);
+  EXPECT_EQ(0u, router->touchscreen_gesture_target_map_.size());
+  EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
+}
+#endif  // defined(USE_AURA) || defined(OS_ANDROID)
+
+// Disabled for flakiness: https://crbug.com/802085.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       DISABLED_InputEventRouterTouchpadGestureTargetTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  WebContentsImpl* contents = web_contents();
+  FrameTreeNode* root = contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  GURL frame_url(
+      embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html"));
+  NavigateFrameToURL(root->child_at(0), frame_url);
+  auto* child_frame_host = root->child_at(0)->current_frame_host();
+
+  // Synchronize with the child and parent renderers to guarantee that the
+  // surface information required for event hit testing is ready.
+  auto* rwhv_child =
+      static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView());
+  WaitForChildFrameSurfaceReady(child_frame_host);
+
+  // All touches & gestures are sent to the main frame's view, and should be
+  // routed appropriately from there.
+  auto* rwhv_parent = static_cast<RenderWidgetHostViewBase*>(
+      contents->GetRenderWidgetHostView());
+
+  RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
+  EXPECT_EQ(nullptr, router->touchpad_gesture_target_.target);
+
+  gfx::Point main_frame_point(25, 25);
+  gfx::Point child_center(150, 150);
+
+  // Send touchpad pinch sequence to main-frame.
+  SendTouchpadPinchSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
+      rwhv_parent);
+
+  // Send touchpad pinch sequence to child.
+  SendTouchpadPinchSequenceWithExpectedTarget(
+      rwhv_parent, child_center, router->touchpad_gesture_target_.target,
+      rwhv_child);
+
+  // Send another touchpad pinch sequence to main frame.
+  SendTouchpadPinchSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
+      rwhv_parent);
+
+#if !defined(OS_WIN)
+  // Sending touchpad fling events is not supported on Windows.
+
+  // Send touchpad fling sequence to main-frame.
+  SendTouchpadFlingSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
+      rwhv_parent);
+
+  // Send touchpad fling sequence to child.
+  SendTouchpadFlingSequenceWithExpectedTarget(
+      rwhv_parent, child_center, router->touchpad_gesture_target_.target,
+      rwhv_child);
+
+  // Send another touchpad fling sequence to main frame.
+  SendTouchpadFlingSequenceWithExpectedTarget(
+      rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target,
+      rwhv_parent);
+#endif
+}
+#endif  // defined(USE_AURA)
+
+// A WebContentsDelegate to capture ContextMenu creation events.
+class ContextMenuObserverDelegate : public WebContentsDelegate {
+ public:
+  ContextMenuObserverDelegate()
+      : context_menu_created_(false),
+        message_loop_runner_(new MessageLoopRunner) {}
+
+  ~ContextMenuObserverDelegate() override {}
+
+  bool HandleContextMenu(const content::ContextMenuParams& params) override {
+    context_menu_created_ = true;
+    menu_params_ = params;
+    message_loop_runner_->Quit();
+    return true;
+  }
+
+  ContextMenuParams getParams() { return menu_params_; }
+
+  void Wait() {
+    if (!context_menu_created_)
+      message_loop_runner_->Run();
+    context_menu_created_ = false;
+  }
+
+ private:
+  bool context_menu_created_;
+  ContextMenuParams menu_params_;
+
+  // The MessageLoopRunner used to spin the message loop.
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContextMenuObserverDelegate);
+};
+
+// Helper function to run the CreateContextMenuTest in either normal
+// or high DPI mode.
+void CreateContextMenuTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  // Ensure that the child process renderer is ready to have input events
+  // routed to it. This happens when the browser process has received
+  // updated compositor surfaces from both renderer processes.
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  // A WebContentsDelegate to listen for the ShowContextMenu message.
+  ContextMenuObserverDelegate context_menu_delegate;
+  shell->web_contents()->SetDelegate(&context_menu_delegate);
+
+  RenderWidgetHostInputEventRouter* router =
+      static_cast<WebContentsImpl*>(shell->web_contents())
+          ->GetInputEventRouter();
+
+  float scale_factor = GetPageScaleFactor(shell);
+
+  gfx::Rect root_bounds = root_view->GetViewBounds();
+  gfx::Rect bounds = rwhv_child->GetViewBounds();
+
+  gfx::Point point(
+      gfx::ToCeiledInt((bounds.x() - root_bounds.x() + 5) * scale_factor),
+      gfx::ToCeiledInt((bounds.y() - root_bounds.y() + 5) * scale_factor));
+
+  // Target right-click event to child frame.
+  blink::WebMouseEvent click_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  click_event.button = blink::WebPointerProperties::Button::kRight;
+  click_event.SetPositionInWidget(point.x(), point.y());
+  click_event.click_count = 1;
+  router->RouteMouseEvent(root_view, &click_event, ui::LatencyInfo());
+
+  // We also need a MouseUp event, needed by Windows.
+  click_event.SetType(blink::WebInputEvent::kMouseUp);
+  click_event.SetPositionInWidget(point.x(), point.y());
+  router->RouteMouseEvent(root_view, &click_event, ui::LatencyInfo());
+
+  context_menu_delegate.Wait();
+
+  ContextMenuParams params = context_menu_delegate.getParams();
+
+  EXPECT_NEAR(point.x(), params.x, 2);
+  EXPECT_NEAR(point.y(), params.y, 2);
+}
+
+// Test that a mouse right-click to an out-of-process iframe causes a context
+// menu to be generated with the correct screen position.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       CreateContextMenuTest) {
+  CreateContextMenuTestHelper(shell(), embedded_test_server());
+}
+
+// Test that a mouse right-click to an out-of-process iframe causes a context
+// menu to be generated with the correct screen position on a screen with
+// non-default scale factor.
+#if defined(OS_ANDROID) || defined(OS_WIN)
+// High DPI tests don't work properly on Android, which has fixed scale factor.
+// Windows is disabled because of https://crbug.com/545547.
+#define MAYBE_HighDPICreateContextMenuTest DISABLED_HighDPICreateContextMenuTest
+#else
+#define MAYBE_HighDPICreateContextMenuTest HighDPICreateContextMenuTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIHitTestBrowserTest,
+                       MAYBE_HighDPICreateContextMenuTest) {
+  CreateContextMenuTestHelper(shell(), embedded_test_server());
+}
+
+class ShowWidgetMessageFilter : public content::BrowserMessageFilter {
+ public:
+  ShowWidgetMessageFilter()
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+      : content::BrowserMessageFilter(FrameMsgStart),
+#else
+      : content::BrowserMessageFilter(ViewMsgStart),
+#endif
+        message_loop_runner_(new content::MessageLoopRunner) {
+  }
+
+  bool OnMessageReceived(const IPC::Message& message) override {
+    IPC_BEGIN_MESSAGE_MAP(ShowWidgetMessageFilter, message)
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+      IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
+#else
+      IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
+#endif
+    IPC_END_MESSAGE_MAP()
+    return false;
+  }
+
+  gfx::Rect last_initial_rect() const { return initial_rect_; }
+
+  int last_routing_id() const { return routing_id_; }
+
+  void Wait() {
+    initial_rect_ = gfx::Rect();
+    routing_id_ = MSG_ROUTING_NONE;
+    message_loop_runner_->Run();
+  }
+
+  void Reset() {
+    initial_rect_ = gfx::Rect();
+    routing_id_ = MSG_ROUTING_NONE;
+    message_loop_runner_ = new content::MessageLoopRunner;
+  }
+
+ private:
+  ~ShowWidgetMessageFilter() override {}
+
+  void OnShowWidget(int route_id, const gfx::Rect& initial_rect) {
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
+                       route_id, initial_rect));
+  }
+
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+  void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params) {
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
+                   MSG_ROUTING_NONE, params.bounds));
+  }
+#endif
+
+  void OnShowWidgetOnUI(int route_id, const gfx::Rect& initial_rect) {
+    initial_rect_ = initial_rect;
+    routing_id_ = route_id;
+    message_loop_runner_->Quit();
+  }
+
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  gfx::Rect initial_rect_;
+  int routing_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShowWidgetMessageFilter);
+};
+
+// Test that clicking a select element in an out-of-process iframe creates
+// a popup menu in the correct position.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest, PopupMenuTest) {
+  GURL main_url(
+      embedded_test_server()->GetURL("/cross_site_iframe_factory.html?a(a)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+  // Unused variable on Mac and Android.
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+#endif
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL(
+      "baz.com", "/site_isolation/page-with-select.html"));
+  NavigateFrameToURL(child_node, site_url);
+
+  web_contents()->SendScreenRects();
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter();
+  child_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+  // Target left-click event to child frame.
+  blink::WebMouseEvent click_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  click_event.button = blink::WebPointerProperties::Button::kLeft;
+  click_event.SetPositionInWidget(15, 15);
+  click_event.click_count = 1;
+  rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo());
+
+  // Dismiss the popup.
+  click_event.SetPositionInWidget(1, 1);
+  rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo());
+
+  filter->Wait();
+  gfx::Rect popup_rect = filter->last_initial_rect();
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+  // On Mac and Android we receive the coordinates before they are transformed,
+  // so they are still relative to the out-of-process iframe origin.
+  EXPECT_EQ(popup_rect.x(), 9);
+  EXPECT_EQ(popup_rect.y(), 9);
+#else
+  EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
+  EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 94);
+#endif
+
+#if defined(OS_LINUX)
+  // Verify click-and-drag selection of popups still works on Linux with
+  // OOPIFs enabled. This is only necessary to test on Aura because Mac and
+  // Android use native widgets. Windows does not support this as UI
+  // convention (it requires separate clicks to open the menu and select an
+  // option). See https://crbug.com/703191.
+  int process_id = child_node->current_frame_host()->GetProcess()->GetID();
+  filter->Reset();
+  RenderWidgetHostInputEventRouter* router =
+      static_cast<WebContentsImpl*>(shell()->web_contents())
+          ->GetInputEventRouter();
+  // Re-open the select element.
+  click_event.SetPositionInWidget(360, 90);
+  click_event.click_count = 1;
+  router->RouteMouseEvent(rwhv_root, &click_event, ui::LatencyInfo());
+
+  filter->Wait();
+
+  RenderWidgetHostViewAura* popup_view = static_cast<RenderWidgetHostViewAura*>(
+      RenderWidgetHost::FromID(process_id, filter->last_routing_id())
+          ->GetView());
+  // The IO thread posts to ViewMsg_ShowWidget handlers in both the message
+  // filter above and the WebContents, which initializes the popup's view.
+  // It is possible for this code to execute before the WebContents handler,
+  // in which case OnMouseEvent would be called on an uninitialized RWHVA.
+  // This loop ensures that the initialization completes before proceeding.
+  while (!popup_view->window()) {
+    base::RunLoop loop;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  loop.QuitClosure());
+    loop.Run();
+  }
+
+  RenderWidgetHostMouseEventMonitor popup_monitor(
+      popup_view->GetRenderWidgetHost());
+
+  // Next send a mouse up directly targeting the first option, simulating a
+  // drag. This requires a ui::MouseEvent because it tests behavior that is
+  // above RWH input event routing.
+  ui::MouseEvent mouse_up_event(ui::ET_MOUSE_RELEASED, gfx::Point(10, 5),
+                                gfx::Point(10, 5), ui::EventTimeForNow(),
+                                ui::EF_LEFT_MOUSE_BUTTON,
+                                ui::EF_LEFT_MOUSE_BUTTON);
+  popup_view->OnMouseEvent(&mouse_up_event);
+
+  // This verifies that the popup actually received the event, and it wasn't
+  // diverted to a different RenderWidgetHostView due to mouse capture.
+  EXPECT_TRUE(popup_monitor.EventWasReceived());
+#endif  // defined(OS_LINUX)
+}
+
+// Test that clicking a select element in a nested out-of-process iframe creates
+// a popup menu in the correct position, even if the top-level page repositions
+// its out-of-process iframe. This verifies that screen positioning information
+// is propagating down the frame tree correctly.
+#if defined(OS_ANDROID)
+// Surface-based hit testing and coordinate translation is not yet avaiable on
+// Android.
+#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
+#else
+// Times out frequently. https://crbug.com/599730.
+#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
+                       MAYBE_NestedPopupMenuTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/cross_site_iframe_factory.html?a(b(c))"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+#if !defined(OS_MACOSX)
+  // Undefined variable on Mac.
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+#endif
+  web_contents()->SendScreenRects();
+
+  // For clarity, we are labeling the frame tree nodes as:
+  //  - root_node
+  //   \-> b_node (out-of-process from root and c_node)
+  //     \-> c_node (out-of-process from root and b_node)
+
+  content::TestNavigationObserver navigation_observer(shell()->web_contents());
+  FrameTreeNode* b_node = root->child_at(0);
+  FrameTreeNode* c_node = b_node->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL(
+      "baz.com", "/site_isolation/page-with-select.html"));
+  NavigateFrameToURL(c_node, site_url);
+
+  RenderWidgetHostViewBase* rwhv_c_node =
+      static_cast<RenderWidgetHostViewBase*>(
+          c_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            c_node->current_frame_host()->GetSiteInstance());
+
+  scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter();
+  c_node->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+  // Target left-click event to child frame.
+  blink::WebMouseEvent click_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  click_event.button = blink::WebPointerProperties::Button::kLeft;
+  click_event.SetPositionInWidget(15, 15);
+  click_event.click_count = 1;
+  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
+
+  // Prompt the WebContents to dismiss the popup by clicking elsewhere.
+  click_event.SetPositionInWidget(1, 1);
+  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
+
+  filter->Wait();
+
+  gfx::Rect popup_rect = filter->last_initial_rect();
+
+#if defined(OS_MACOSX)
+  EXPECT_EQ(popup_rect.x(), 9);
+  EXPECT_EQ(popup_rect.y(), 9);
+#else
+  EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
+  EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 154);
+#endif
+
+  // Save the screen rect for b_node. Since it updates asynchronously from
+  // the script command that changes it, we need to wait for it to change
+  // before attempting to create the popup widget again.
+  gfx::Rect last_b_node_bounds_rect =
+      b_node->current_frame_host()->GetView()->GetViewBounds();
+
+  std::string script =
+      "var iframe = document.querySelector('iframe');"
+      "iframe.style.position = 'absolute';"
+      "iframe.style.left = 150;"
+      "iframe.style.top = 150;";
+  EXPECT_TRUE(ExecuteScript(root, script));
+
+  filter->Reset();
+
+  // Busy loop to wait for b_node's screen rect to get updated. There
+  // doesn't seem to be any better way to find out when this happens.
+  while (last_b_node_bounds_rect.x() ==
+             b_node->current_frame_host()->GetView()->GetViewBounds().x() &&
+         last_b_node_bounds_rect.y() ==
+             b_node->current_frame_host()->GetView()->GetViewBounds().y()) {
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
+    run_loop.Run();
+  }
+
+  click_event.button = blink::WebPointerProperties::Button::kLeft;
+  click_event.SetPositionInWidget(15, 15);
+  click_event.click_count = 1;
+  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
+
+  click_event.SetPositionInWidget(1, 1);
+  rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
+
+  filter->Wait();
+
+  popup_rect = filter->last_initial_rect();
+
+#if defined(OS_MACOSX)
+  EXPECT_EQ(popup_rect.x(), 9);
+  EXPECT_EQ(popup_rect.y(), 9);
+#else
+  EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 203);
+  EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 248);
+#endif
+}
+
+#if defined(USE_AURA)
+class SitePerProcessGestureHitTestBrowserTest
+    : public SitePerProcessBrowserTest {
+ public:
+  SitePerProcessGestureHitTestBrowserTest() {}
+
+  // This functions simulates a sequence of events that are typical of a
+  // gesture pinch at |position|. We need this since machinery in the event
+  // codepath will require GesturePinch* to be enclosed in
+  // GestureScrollBegin/End, and since RenderWidgetHostInputEventRouter needs
+  // both the preceding touch events, as well as GestureTapDown, in order to
+  // correctly target the subsequent gesture event stream. The minimum stream
+  // required to trigger the correct behaviours is represented here, but could
+  // be expanded to include additional events such as one or more
+  // GestureScrollUpdate and GesturePinchUpdate events.
+  void SendPinchBeginEndSequence(RenderWidgetHostViewAura* rwhva,
+                                 const gfx::Point& position,
+                                 RenderWidgetHost* expected_target_rwh) {
+    DCHECK(rwhva);
+    // Use full version of constructor with radius, angle and force since it
+    // will crash in the renderer otherwise.
+    ui::TouchEvent touch_pressed(
+        ui::ET_TOUCH_PRESSED, position, ui::EventTimeForNow(),
+        ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
+                           /* pointer_id*/ 0,
+                           /* radius_x */ 1.0f,
+                           /* radius_y */ 1.0f,
+                           /* force */ 1.0f));
+    InputEventAckWaiter waiter(expected_target_rwh,
+                               blink::WebInputEvent::kTouchStart);
+    rwhva->OnTouchEvent(&touch_pressed);
+    waiter.Wait();
+    ui::TouchEvent touch_released(
+        ui::ET_TOUCH_RELEASED, position, ui::EventTimeForNow(),
+        ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
+                           /* pointer_id*/ 0,
+                           /* radius_x */ 1.0f,
+                           /* radius_y */ 1.0f,
+                           /* force */ 1.0f));
+    rwhva->OnTouchEvent(&touch_released);
+
+    ui::GestureEventDetails gesture_tap_down_details(ui::ET_GESTURE_TAP_DOWN);
+    gesture_tap_down_details.set_device_type(
+        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+    ui::GestureEvent gesture_tap_down(
+        position.x(), position.y(), 0, ui::EventTimeForNow(),
+        gesture_tap_down_details, touch_pressed.unique_event_id());
+    rwhva->OnGestureEvent(&gesture_tap_down);
+
+    ui::GestureEventDetails gesture_scroll_begin_details(
+        ui::ET_GESTURE_SCROLL_BEGIN);
+    gesture_scroll_begin_details.set_device_type(
+        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+    ui::GestureEvent gesture_scroll_begin(
+        position.x(), position.y(), 0, ui::EventTimeForNow(),
+        gesture_scroll_begin_details, touch_pressed.unique_event_id());
+    rwhva->OnGestureEvent(&gesture_scroll_begin);
+
+    ui::GestureEventDetails gesture_pinch_begin_details(
+        ui::ET_GESTURE_PINCH_BEGIN);
+    gesture_pinch_begin_details.set_device_type(
+        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+    ui::GestureEvent gesture_pinch_begin(
+        position.x(), position.y(), 0, ui::EventTimeForNow(),
+        gesture_pinch_begin_details, touch_pressed.unique_event_id());
+    rwhva->OnGestureEvent(&gesture_pinch_begin);
+
+    ui::GestureEventDetails gesture_pinch_end_details(ui::ET_GESTURE_PINCH_END);
+    gesture_pinch_end_details.set_device_type(
+        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+    ui::GestureEvent gesture_pinch_end(
+        position.x(), position.y(), 0, ui::EventTimeForNow(),
+        gesture_pinch_end_details, touch_pressed.unique_event_id());
+    rwhva->OnGestureEvent(&gesture_pinch_end);
+
+    ui::GestureEventDetails gesture_scroll_end_details(
+        ui::ET_GESTURE_SCROLL_END);
+    gesture_scroll_end_details.set_device_type(
+        ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+    ui::GestureEvent gesture_scroll_end(
+        position.x(), position.y(), 0, ui::EventTimeForNow(),
+        gesture_scroll_end_details, touch_pressed.unique_event_id());
+    rwhva->OnGestureEvent(&gesture_scroll_end);
+  }
+
+  void SetupRootAndChild() {
+    GURL main_url(embedded_test_server()->GetURL(
+        "a.com", "/cross_site_iframe_factory.html?a(b)"));
+    EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+    FrameTreeNode* root_node =
+        static_cast<WebContentsImpl*>(shell()->web_contents())
+            ->GetFrameTree()
+            ->root();
+    FrameTreeNode* child_node = root_node->child_at(0);
+
+    rwhv_child_ = static_cast<RenderWidgetHostViewBase*>(
+        child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+    rwhva_root_ = static_cast<RenderWidgetHostViewAura*>(
+        shell()->web_contents()->GetRenderWidgetHostView());
+
+    WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+    rwhi_child_ = child_node->current_frame_host()->GetRenderWidgetHost();
+    rwhi_root_ = root_node->current_frame_host()->GetRenderWidgetHost();
+  }
+
+ protected:
+  RenderWidgetHostViewBase* rwhv_child_;
+  RenderWidgetHostViewAura* rwhva_root_;
+  RenderWidgetHostImpl* rwhi_child_;
+  RenderWidgetHostImpl* rwhi_root_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SitePerProcessGestureHitTestBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessGestureHitTestBrowserTest,
+                       SubframeGesturePinchGoesToMainFrame) {
+  SetupRootAndChild();
+
+  TestInputEventObserver root_frame_monitor(rwhi_root_);
+  TestInputEventObserver child_frame_monitor(rwhi_child_);
+
+  // Need child rect in main frame coords.
+  gfx::Rect bounds = rwhv_child_->GetViewBounds();
+  bounds.Offset(gfx::Point() - rwhva_root_->GetViewBounds().origin());
+  SendPinchBeginEndSequence(rwhva_root_, bounds.CenterPoint(), rwhi_child_);
+
+  // Verify root-RWHI gets GSB/GPB/GPE/GSE.
+  EXPECT_TRUE(root_frame_monitor.EventWasReceived());
+  EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
+            root_frame_monitor.events_received()[0]);
+  EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin,
+            root_frame_monitor.events_received()[1]);
+  EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd,
+            root_frame_monitor.events_received()[2]);
+  EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
+            root_frame_monitor.events_received()[3]);
+
+  // Verify child-RWHI gets TS/TE, GTD/GSB/GSE.
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  EXPECT_EQ(blink::WebInputEvent::kTouchStart,
+            child_frame_monitor.events_received()[0]);
+  EXPECT_EQ(blink::WebInputEvent::kTouchEnd,
+            child_frame_monitor.events_received()[1]);
+  EXPECT_EQ(blink::WebInputEvent::kGestureTapDown,
+            child_frame_monitor.events_received()[2]);
+  EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
+            child_frame_monitor.events_received()[3]);
+  EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
+            child_frame_monitor.events_received()[4]);
+}
+
+IN_PROC_BROWSER_TEST_F(SitePerProcessGestureHitTestBrowserTest,
+                       MainframeGesturePinchGoesToMainFrame) {
+  SetupRootAndChild();
+
+  TestInputEventObserver root_frame_monitor(rwhi_root_);
+  TestInputEventObserver child_frame_monitor(rwhi_child_);
+
+  // Need child rect in main frame coords.
+  gfx::Rect bounds = rwhv_child_->GetViewBounds();
+  bounds.Offset(gfx::Point() - rwhva_root_->GetViewBounds().origin());
+
+  gfx::Point main_frame_point(bounds.origin());
+  main_frame_point += gfx::Vector2d(-5, -5);
+  SendPinchBeginEndSequence(rwhva_root_, main_frame_point, rwhi_root_);
+
+  // Verify root-RWHI gets TS/TE/GTD/GSB/GPB/GPE/GSE.
+  EXPECT_TRUE(root_frame_monitor.EventWasReceived());
+  EXPECT_EQ(blink::WebInputEvent::kTouchStart,
+            root_frame_monitor.events_received()[0]);
+  EXPECT_EQ(blink::WebInputEvent::kTouchEnd,
+            root_frame_monitor.events_received()[1]);
+  EXPECT_EQ(blink::WebInputEvent::kGestureTapDown,
+            root_frame_monitor.events_received()[2]);
+  EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
+            root_frame_monitor.events_received()[3]);
+  EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin,
+            root_frame_monitor.events_received()[4]);
+  EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd,
+            root_frame_monitor.events_received()[5]);
+  EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
+            root_frame_monitor.events_received()[6]);
+
+  // Verify child-RWHI gets no events.
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+}
+#endif  // defined(USE_AURA)
+
+// Test that MouseDown and MouseUp to the same coordinates do not result in
+// different coordinates after routing. See bug https://crbug.com/670253.
+#if defined(OS_ANDROID)
+// Android uses fixed scale factor, which makes this test unnecessary.
+#define MAYBE_MouseClickWithNonIntegerScaleFactor \
+  DISABLED_MouseClickWithNonIntegerScaleFactor
+#else
+#define MAYBE_MouseClickWithNonIntegerScaleFactor \
+  MouseClickWithNonIntegerScaleFactor
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessNonIntegerScaleFactorHitTestBrowserTest,
+                       MAYBE_MouseClickWithNonIntegerScaleFactor) {
+  GURL initial_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), initial_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  RenderWidgetHostInputEventRouter* router =
+      static_cast<WebContentsImpl*>(shell()->web_contents())
+          ->GetInputEventRouter();
+
+  // Create listener for input events.
+  RenderWidgetHostMouseEventMonitor event_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+
+  blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  mouse_event.button = blink::WebPointerProperties::Button::kLeft;
+  mouse_event.SetPositionInWidget(75, 75);
+  mouse_event.click_count = 1;
+  event_monitor.ResetEventReceived();
+  router->RouteMouseEvent(rwhv, &mouse_event, ui::LatencyInfo());
+
+  EXPECT_TRUE(event_monitor.EventWasReceived());
+  gfx::Point mouse_down_coords =
+      gfx::Point(event_monitor.event().PositionInWidget().x,
+                 event_monitor.event().PositionInWidget().y);
+  event_monitor.ResetEventReceived();
+
+  mouse_event.SetType(blink::WebInputEvent::kMouseUp);
+  mouse_event.SetPositionInWidget(75, 75);
+  router->RouteMouseEvent(rwhv, &mouse_event, ui::LatencyInfo());
+
+  EXPECT_TRUE(event_monitor.EventWasReceived());
+  EXPECT_EQ(mouse_down_coords,
+            gfx::Point(event_monitor.event().PositionInWidget().x,
+                       event_monitor.event().PositionInWidget().y));
+}
+
+// Verify InputTargetClient works within an OOPIF process.
+IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest, HitTestNestedFrames) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  EXPECT_EQ(
+      " Site A ------------ proxies for B C\n"
+      "   +--Site B ------- proxies for A C\n"
+      "        +--Site C -- proxies for A B\n"
+      "Where A = http://127.0.0.1/\n"
+      "      B = http://a.com/\n"
+      "      C = http://baz.com/",
+      DepictFrameTree(root));
+
+  FrameTreeNode* child_node = root->child_at(0);
+  FrameTreeNode* grandchild_node = child_node->child_at(0);
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_grandchild =
+      static_cast<RenderWidgetHostViewBase*>(
+          grandchild_node->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetView());
+
+  WaitForChildFrameSurfaceReady(grandchild_node->current_frame_host());
+
+  // Create two points to hit test: One in the child of the main frame, and
+  // one in the frame nested within that. The hit test request is sent to the
+  // child's renderer.
+  gfx::Point point_in_child(1, 1);
+  gfx::PointF point_in_nested_child(5, 5);
+  rwhv_grandchild->TransformPointToCoordSpaceForView(
+      point_in_nested_child, rwhv_child, &point_in_nested_child);
+
+  {
+    base::RunLoop run_loop;
+    viz::FrameSinkId received_frame_sink_id;
+    base::Closure quit_closure =
+        content::GetDeferredQuitTaskForRunLoop(&run_loop);
+    DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
+              nullptr);
+    child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
+        point_in_child,
+        base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
+          received_frame_sink_id = id;
+          quit_closure.Run();
+        }));
+    content::RunThisRunLoop(&run_loop);
+    // |point_in_child| should hit test to the view for |child_node|.
+    ASSERT_EQ(rwhv_child->GetFrameSinkId(), received_frame_sink_id);
+  }
+
+  {
+    base::RunLoop run_loop;
+    viz::FrameSinkId received_frame_sink_id;
+    base::Closure quit_closure =
+        content::GetDeferredQuitTaskForRunLoop(&run_loop);
+    DCHECK_NE(child_node->current_frame_host()->GetInputTargetClient(),
+              nullptr);
+    child_node->current_frame_host()->GetInputTargetClient()->FrameSinkIdAt(
+        gfx::ToCeiledPoint(point_in_nested_child),
+        base::BindLambdaForTesting([&](const viz::FrameSinkId& id) {
+          received_frame_sink_id = id;
+          quit_closure.Run();
+        }));
+    content::RunThisRunLoop(&run_loop);
+    // |point_in_nested_child| should hit test to |rwhv_grandchild|.
+    ASSERT_EQ(rwhv_grandchild->GetFrameSinkId(), received_frame_sink_id);
+  }
+}
+
+}  // namespace content
diff --git a/content/common/DEPS b/content/common/DEPS
index d85de16..7d336393 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -30,6 +30,7 @@
   "+third_party/WebKit/public/platform/WebHistoryScrollRestorationType.h",
   "+third_party/WebKit/public/platform/WebInputEvent.h",
   "+third_party/WebKit/public/platform/WebInsecureRequestPolicy.h",
+  "+third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h",
   "+third_party/WebKit/public/platform/WebKeyboardEvent.h",
   "+third_party/WebKit/public/platform/WebMixedContentContextType.h",
   "+third_party/WebKit/public/platform/WebMouseWheelEvent.h",
diff --git a/content/common/cross_site_document_classifier.cc b/content/common/cross_site_document_classifier.cc
index 5d21d26..f9c8e439 100644
--- a/content/common/cross_site_document_classifier.cc
+++ b/content/common/cross_site_document_classifier.cc
@@ -153,19 +153,9 @@
   return url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kHttpsScheme);
 }
 
-bool CrossSiteDocumentClassifier::IsSameSite(const url::Origin& frame_origin,
-                                             const GURL& response_url) {
-  if (frame_origin.unique() || !response_url.is_valid())
-    return false;
-
-  if (frame_origin.scheme() != response_url.scheme())
-    return false;
-
-  // SameDomainOrHost() extracts the effective domains (public suffix plus one)
-  // from the two URLs and compare them.
-  return net::registry_controlled_domains::SameDomainOrHost(
-      response_url, frame_origin,
-      net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+bool CrossSiteDocumentClassifier::IsSameOrigin(const url::Origin& frame_origin,
+                                               const GURL& response_url) {
+  return frame_origin.IsSameOriginWith(url::Origin::Create(response_url));
 }
 
 // We don't use Webkit's existing CORS policy implementation since
@@ -192,7 +182,7 @@
   if (access_control_origin == "*" || access_control_origin == "null")
     return true;
 
-  return IsSameSite(frame_origin, GURL(access_control_origin));
+  return IsSameOrigin(frame_origin, GURL(access_control_origin));
 }
 
 // This function is a slight modification of |net::SniffForHTML|.
diff --git a/content/common/cross_site_document_classifier.h b/content/common/cross_site_document_classifier.h
index de009cb..e4c244d 100644
--- a/content/common/cross_site_document_classifier.h
+++ b/content/common/cross_site_document_classifier.h
@@ -55,9 +55,10 @@
   // policy(XSDP). This returns true only for http://* and https://* urls.
   static bool IsBlockableScheme(const GURL& frame_origin);
 
-  // Returns whether the two urls belong to the same sites.
-  static bool IsSameSite(const url::Origin& frame_origin,
-                         const GURL& response_url);
+  // Returns whether the two urls belong to the same origin.
+  // TODO(lukasza): Remove this function / inline it into the callers.
+  static bool IsSameOrigin(const url::Origin& frame_origin,
+                           const GURL& response_url);
 
   // Returns whether there's a valid CORS header for frame_origin.  This is
   // simliar to CrossOriginAccessControl::passesAccessControlCheck(), but we use
@@ -67,6 +68,7 @@
   // not allowed by actual CORS rules by ignoring 1) credentials and 2)
   // methods. Preflight requests don't matter here since they are not used to
   // decide whether to block a document or not on the client side.
+  // TODO(lukasza): Remove the unused website_origin parameter.
   static bool IsValidCorsHeaderSet(const url::Origin& frame_origin,
                                    const GURL& website_origin,
                                    const std::string& access_control_origin);
diff --git a/content/common/cross_site_document_classifier_unittest.cc b/content/common/cross_site_document_classifier_unittest.cc
index 5974158b..3dd32e9 100644
--- a/content/common/cross_site_document_classifier_unittest.cc
+++ b/content/common/cross_site_document_classifier_unittest.cc
@@ -30,33 +30,47 @@
   EXPECT_TRUE(CrossSiteDocumentClassifier::IsBlockableScheme(https_url));
 }
 
-TEST(CrossSiteDocumentClassifierTest, IsSameSite) {
+TEST(CrossSiteDocumentClassifierTest, IsSameOrigin) {
   GURL a_com_url0("https://mock1.a.com:8080/page1.html");
   GURL a_com_url1("https://mock2.a.com:9090/page2.html");
   GURL a_com_url2("https://a.com/page3.html");
+  GURL a_com_url3("https://a.com/page4.html");
+  GURL a_com_url4("https://a.com:1234/page4.html");
   url::Origin a_com_origin0 = url::Origin::Create(a_com_url0);
-  EXPECT_TRUE(
-      CrossSiteDocumentClassifier::IsSameSite(a_com_origin0, a_com_url1));
-  EXPECT_TRUE(CrossSiteDocumentClassifier::IsSameSite(
+  EXPECT_FALSE(
+      CrossSiteDocumentClassifier::IsSameOrigin(a_com_origin0, a_com_url1));
+  EXPECT_FALSE(CrossSiteDocumentClassifier::IsSameOrigin(
       url::Origin::Create(a_com_url1), a_com_url2));
-  EXPECT_TRUE(CrossSiteDocumentClassifier::IsSameSite(
+  EXPECT_FALSE(CrossSiteDocumentClassifier::IsSameOrigin(
       url::Origin::Create(a_com_url2), a_com_url0));
+  EXPECT_TRUE(CrossSiteDocumentClassifier::IsSameOrigin(
+      url::Origin::Create(a_com_url2), a_com_url3));
+  EXPECT_FALSE(CrossSiteDocumentClassifier::IsSameOrigin(
+      url::Origin::Create(a_com_url3), a_com_url4));
 
   GURL b_com_url0("https://mock1.b.com/index.html");
   EXPECT_FALSE(
-      CrossSiteDocumentClassifier::IsSameSite(a_com_origin0, b_com_url0));
+      CrossSiteDocumentClassifier::IsSameOrigin(a_com_origin0, b_com_url0));
 
   GURL about_blank_url("about:blank");
-  EXPECT_FALSE(
-      CrossSiteDocumentClassifier::IsSameSite(a_com_origin0, about_blank_url));
+  EXPECT_FALSE(CrossSiteDocumentClassifier::IsSameOrigin(a_com_origin0,
+                                                         about_blank_url));
 
   GURL chrome_url("chrome://extension");
   EXPECT_FALSE(
-      CrossSiteDocumentClassifier::IsSameSite(a_com_origin0, chrome_url));
+      CrossSiteDocumentClassifier::IsSameOrigin(a_com_origin0, chrome_url));
 
   GURL empty_url("");
+  EXPECT_FALSE(empty_url.is_valid());
   EXPECT_FALSE(
-      CrossSiteDocumentClassifier::IsSameSite(a_com_origin0, empty_url));
+      CrossSiteDocumentClassifier::IsSameOrigin(a_com_origin0, empty_url));
+
+  url::Origin unique_origin;
+  EXPECT_TRUE(unique_origin.unique());
+  EXPECT_FALSE(
+      CrossSiteDocumentClassifier::IsSameOrigin(unique_origin, empty_url));
+  EXPECT_FALSE(
+      CrossSiteDocumentClassifier::IsSameOrigin(unique_origin, b_com_url0));
 }
 
 TEST(CrossSiteDocumentClassifierTest, IsValidCorsHeaderSet) {
@@ -67,10 +81,12 @@
       frame_origin, site_origin_url, "*"));
   EXPECT_FALSE(CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
       frame_origin, site_origin_url, "\"*\""));
-  EXPECT_TRUE(CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
-      frame_origin, site_origin_url, "http://mail.google.com"));
   EXPECT_FALSE(CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
-      frame_origin, site_origin_url, "https://mail.google.com"));
+      frame_origin, site_origin_url, "http://mail.google.com"));
+  EXPECT_TRUE(CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
+      frame_origin, site_origin_url, "http://www.google.com"));
+  EXPECT_FALSE(CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
+      frame_origin, site_origin_url, "https://www.google.com"));
   EXPECT_FALSE(CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
       frame_origin, site_origin_url, "http://yahoo.com"));
   EXPECT_FALSE(CrossSiteDocumentClassifier::IsValidCorsHeaderSet(
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 4bcff55..8143937 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -57,6 +57,7 @@
 #include "third_party/WebKit/common/message_port/message_port_channel.h"
 #include "third_party/WebKit/public/platform/WebFocusType.h"
 #include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h"
+#include "third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h"
 #include "third_party/WebKit/public/platform/WebScrollIntoViewParams.h"
 #include "third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
@@ -134,6 +135,18 @@
 IPC_ENUM_TRAITS_MAX_VALUE(blink::WebTriggeringEventInfo,
                           blink::WebTriggeringEventInfo::kLast)
 
+IPC_STRUCT_TRAITS_BEGIN(blink::WebFloatSize)
+  IPC_STRUCT_TRAITS_MEMBER(width)
+  IPC_STRUCT_TRAITS_MEMBER(height)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(blink::WebIntrinsicSizingInfo)
+  IPC_STRUCT_TRAITS_MEMBER(size)
+  IPC_STRUCT_TRAITS_MEMBER(aspect_ratio)
+  IPC_STRUCT_TRAITS_MEMBER(has_width)
+  IPC_STRUCT_TRAITS_MEMBER(has_height)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(blink::WebFindOptions)
   IPC_STRUCT_TRAITS_MEMBER(forward)
   IPC_STRUCT_TRAITS_MEMBER(match_case)
@@ -759,6 +772,11 @@
 // -----------------------------------------------------------------------------
 // Messages sent from the browser to the renderer.
 
+// Notifies the embedding frame that the intrinsic sizing info parameters
+// of a child frame have changed.
+IPC_MESSAGE_ROUTED1(FrameMsg_IntrinsicSizingInfoOfChildChanged,
+                    blink::WebIntrinsicSizingInfo)
+
 IPC_MESSAGE_ROUTED1(FrameMsg_SetChildFrameSurface,
                     viz::SurfaceInfo /* surface_info */)
 
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 72668127..50258ad7 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -48,6 +48,7 @@
 #include "third_party/WebKit/public/platform/WebDisplayMode.h"
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebFloatRect.h"
+#include "third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h"
 #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
@@ -732,6 +733,12 @@
                     bool /* user_gesture */,
                     bool /* privileged */)
 
+// Requests to tell the renderer for the containing frame of the current
+// renderer of a change in intrinsic sizing info parameters. This is only
+// used for SVG inside of <object>, and not for iframes.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_IntrinsicSizingInfoChanged,
+                    blink::WebIntrinsicSizingInfo)
+
 // Requests to unlock the mouse. A ViewMsg_MouseLockLost message will be sent
 // whenever the mouse is unlocked (which may or may not be caused by
 // ViewHostMsg_UnlockMouse).
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java
index 684ebe1..44af576 100644
--- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java
@@ -5,6 +5,7 @@
 package org.chromium.content.browser.remoteobjects;
 
 import org.chromium.blink.mojom.RemoteInvocationArgument;
+import org.chromium.blink.mojom.RemoteInvocationError;
 import org.chromium.blink.mojom.RemoteInvocationResult;
 import org.chromium.blink.mojom.RemoteObject;
 import org.chromium.mojo.system.MojoException;
@@ -76,7 +77,7 @@
         int numArguments = arguments.length;
         Method method = findMethod(name, numArguments);
         if (method == null) {
-            // TODO(jbroman): Handle this.
+            callback.call(makeErrorResult(RemoteInvocationError.METHOD_NOT_FOUND));
             return;
         }
 
@@ -130,6 +131,13 @@
 
     private RemoteInvocationResult convertResult(Object result) {
         // TODO(jbroman): Convert result.
-        return null;
+        return new RemoteInvocationResult();
+    }
+
+    private static RemoteInvocationResult makeErrorResult(int error) {
+        assert error != RemoteInvocationError.OK;
+        RemoteInvocationResult result = new RemoteInvocationResult();
+        result.error = error;
+        return result;
     }
 }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java
index 5cd6e15..e65c0fb4 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java
@@ -19,6 +19,7 @@
 import org.mockito.InOrder;
 
 import org.chromium.blink.mojom.RemoteInvocationArgument;
+import org.chromium.blink.mojom.RemoteInvocationError;
 import org.chromium.blink.mojom.RemoteInvocationResult;
 import org.chromium.blink.mojom.RemoteObject;
 
@@ -177,8 +178,34 @@
         verify(response, times(2)).call(resultIsOk());
     }
 
+    @Test
+    public void testInvokeMethodNotFound() {
+        Object target = new Object() {
+            public void unexposedMethod() {
+                Assert.fail("Unexposed method should not be called.");
+            }
+
+            @TestJavascriptInterface
+            public void exposedMethodWithWrongArity(Object argument) {
+                Assert.fail("Exposed method should only be called with the correct arity.");
+            }
+        };
+
+        RemoteObject remoteObject = new RemoteObjectImpl(target, TestJavascriptInterface.class);
+        RemoteObject.InvokeMethodResponse response = mock(RemoteObject.InvokeMethodResponse.class);
+        remoteObject.invokeMethod("nonexistentMethod", new RemoteInvocationArgument[] {}, response);
+        remoteObject.invokeMethod("unexposedMethod", new RemoteInvocationArgument[] {}, response);
+        remoteObject.invokeMethod(
+                "exposedMethodWithWrongArity", new RemoteInvocationArgument[] {}, response);
+
+        verify(response, times(3)).call(resultHasError(RemoteInvocationError.METHOD_NOT_FOUND));
+    }
+
+    private RemoteInvocationResult resultHasError(final int error) {
+        return ArgumentMatchers.argThat(result -> result.error == error);
+    }
+
     private RemoteInvocationResult resultIsOk() {
-        // TODO(jbroman): Check the error code once there is one.
-        return ArgumentMatchers.<RemoteInvocationResult>any();
+        return resultHasError(RemoteInvocationError.OK);
     }
 }
diff --git a/content/renderer/loader/site_isolation_stats_gatherer.cc b/content/renderer/loader/site_isolation_stats_gatherer.cc
index 60d5045a..43bee60 100644
--- a/content/renderer/loader/site_isolation_stats_gatherer.cc
+++ b/content/renderer/loader/site_isolation_stats_gatherer.cc
@@ -119,9 +119,7 @@
   if (!CrossSiteDocumentClassifier::IsBlockableScheme(response_url))
     return nullptr;
 
-  // TODO(csharrison): Add a path for IsSameSite/IsValidCorsHeaderSet to take an
-  // Origin.
-  if (CrossSiteDocumentClassifier::IsSameSite(frame_origin, response_url))
+  if (CrossSiteDocumentClassifier::IsSameOrigin(frame_origin, response_url))
     return nullptr;
 
   CrossSiteDocumentMimeType canonical_mime_type =
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index b8109b94..caba676 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -1116,6 +1116,8 @@
     // associated with multiple tracks (multiple receivers).
     for (auto& receiver_state : states.receiver_states) {
       for (auto& stream_ref : receiver_state.stream_refs) {
+        CHECK(stream_ref);
+        CHECK(stream_ref->adapter().is_initialized());
         CHECK(!stream_ref->adapter().web_stream().IsNull());
         CHECK(stream_ref->adapter().webrtc_stream());
         auto* stream_state =
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc b/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc
index 32040d6f..519464e8 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter.cc
@@ -195,8 +195,8 @@
                                blink::WebMediaStream()),
       is_initialized_(false),
       weak_factory_(this) {
-  DCHECK(!main_thread_->BelongsToCurrentThread());
-  DCHECK(track_adapter_map_);
+  CHECK(!main_thread_->BelongsToCurrentThread());
+  CHECK(track_adapter_map_);
 
   RemoteAdapterRefs adapter_refs = GetRemoteAdapterRefsFromWebRtcStream(
       track_adapter_map_, webrtc_stream_.get());
@@ -238,8 +238,8 @@
     RemoteAdapterRefs adapter_refs,
     size_t audio_track_count,
     size_t video_track_count) {
-  DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK_EQ(audio_track_count + video_track_count, adapter_refs.size());
+  CHECK(main_thread_->BelongsToCurrentThread());
+  CHECK_EQ(audio_track_count + video_track_count, adapter_refs.size());
 
   adapter_refs_ = std::move(adapter_refs);
   blink::WebVector<blink::WebMediaStreamTrack> web_audio_tracks(
@@ -258,6 +258,7 @@
 
   web_stream_.Initialize(blink::WebString::FromUTF8(label), web_audio_tracks,
                          web_video_tracks);
+  CHECK(!web_stream_.IsNull());
 
   base::AutoLock scoped_lock(lock_);
   is_initialized_ = true;
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.cc b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.cc
index 89ef430..fb5219c6 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.cc
@@ -107,7 +107,8 @@
 std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
 WebRtcMediaStreamAdapterMap::GetOrCreateLocalStreamAdapter(
     const blink::WebMediaStream& web_stream) {
-  DCHECK(main_thread_->BelongsToCurrentThread());
+  CHECK(main_thread_->BelongsToCurrentThread());
+  CHECK(!web_stream.IsNull());
   base::AutoLock scoped_lock(lock_);
   AdapterEntry* adapter_entry =
       local_stream_adapters_.FindByPrimary(web_stream.UniqueId());
@@ -126,7 +127,8 @@
 
     adapter_entry = local_stream_adapters_.Insert(web_stream.UniqueId(),
                                                   std::move(adapter));
-    DCHECK(adapter_entry->adapter->is_initialized());
+    CHECK(adapter_entry->adapter->is_initialized());
+    CHECK(adapter_entry->adapter->webrtc_stream());
     local_stream_adapters_.SetSecondaryKey(
         web_stream.UniqueId(), adapter_entry->adapter->webrtc_stream().get());
   }
@@ -166,8 +168,8 @@
 std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
 WebRtcMediaStreamAdapterMap::GetOrCreateRemoteStreamAdapter(
     scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream) {
-  DCHECK(!main_thread_->BelongsToCurrentThread());
-  DCHECK(webrtc_stream);
+  CHECK(!main_thread_->BelongsToCurrentThread());
+  CHECK(webrtc_stream);
   base::AutoLock scoped_lock(lock_);
   AdapterEntry* adapter_entry =
       remote_stream_adapters_.FindByPrimary(webrtc_stream.get());
@@ -210,8 +212,9 @@
 
 void WebRtcMediaStreamAdapterMap::OnRemoteStreamAdapterInitialized(
     std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef> adapter_ref) {
-  DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK(adapter_ref->is_initialized());
+  CHECK(main_thread_->BelongsToCurrentThread());
+  CHECK(adapter_ref->is_initialized());
+  CHECK(!adapter_ref->adapter().web_stream().IsNull());
   {
     base::AutoLock scoped_lock(lock_);
     remote_stream_adapters_.SetSecondaryKey(
diff --git a/content/renderer/media/webrtc/webrtc_set_remote_description_observer.cc b/content/renderer/media/webrtc/webrtc_set_remote_description_observer.cc
index dceb8639..9d162d9 100644
--- a/content/renderer/media/webrtc/webrtc_set_remote_description_observer.cc
+++ b/content/renderer/media/webrtc/webrtc_set_remote_description_observer.cc
@@ -68,7 +68,7 @@
 
 void WebRtcSetRemoteDescriptionObserverHandler::OnSetRemoteDescriptionComplete(
     webrtc::RTCError error) {
-  DCHECK(!main_thread_->BelongsToCurrentThread());
+  CHECK(!main_thread_->BelongsToCurrentThread());
 
   webrtc::RTCErrorOr<WebRtcSetRemoteDescriptionObserver::States>
       states_or_error;
@@ -101,7 +101,7 @@
     OnSetRemoteDescriptionCompleteOnMainThread(
         webrtc::RTCErrorOr<WebRtcSetRemoteDescriptionObserver::States>
             states_or_error) {
-  DCHECK(main_thread_->BelongsToCurrentThread());
+  CHECK(main_thread_->BelongsToCurrentThread());
   observer_->OnSetRemoteDescriptionComplete(std::move(states_or_error));
 }
 
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 1b131852..a4f56d2 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -370,6 +370,8 @@
     IPC_MESSAGE_HANDLER(FrameMsg_DeleteProxy, OnDeleteProxy)
     IPC_MESSAGE_HANDLER(FrameMsg_ChildFrameProcessGone, OnChildFrameProcessGone)
     IPC_MESSAGE_HANDLER(FrameMsg_SetChildFrameSurface, OnSetChildFrameSurface)
+    IPC_MESSAGE_HANDLER(FrameMsg_IntrinsicSizingInfoOfChildChanged,
+                        OnIntrinsicSizingInfoOfChildChanged)
     IPC_MESSAGE_HANDLER(FrameMsg_UpdateOpener, OnUpdateOpener)
     IPC_MESSAGE_HANDLER(FrameMsg_ViewChanged, OnViewChanged)
     IPC_MESSAGE_HANDLER(FrameMsg_DidStartLoading, OnDidStartLoading)
@@ -427,6 +429,11 @@
   SetChildFrameSurface(surface_info);
 }
 
+void RenderFrameProxy::OnIntrinsicSizingInfoOfChildChanged(
+    blink::WebIntrinsicSizingInfo sizing_info) {
+  web_frame()->IntrinsicSizingInfoChanged(sizing_info);
+}
+
 void RenderFrameProxy::OnUpdateOpener(int opener_routing_id) {
   blink::WebFrame* opener = RenderFrameImpl::ResolveOpener(opener_routing_id);
   web_frame_->SetOpener(opener);
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index bf21044..5a778cb 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -208,6 +208,8 @@
   void OnCompositorFrameSwapped(const IPC::Message& message);
   // TODO(fsamuel): Rename OnFirstSurfaceActivation().
   void OnSetChildFrameSurface(const viz::SurfaceInfo& surface_info);
+  void OnIntrinsicSizingInfoOfChildChanged(
+      blink::WebIntrinsicSizingInfo sizing_info);
   void OnUpdateOpener(int opener_routing_id);
   void OnViewChanged(const viz::FrameSinkId& frame_sink_id);
   void OnDidStopLoading();
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index a6ee8c5..c82d4d8 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1479,6 +1479,11 @@
   return compositor_.get();
 }
 
+void RenderWidget::IntrinsicSizingInfoChanged(
+    const blink::WebIntrinsicSizingInfo& sizing_info) {
+  Send(new ViewHostMsg_IntrinsicSizingInfoChanged(routing_id_, sizing_info));
+}
+
 void RenderWidget::WillCloseLayerTreeView() {
   if (host_closing_)
     return;
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index b7841f1a..86e352c9 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -293,6 +293,8 @@
 
   // blink::WebWidgetClient
   blink::WebLayerTreeView* InitializeLayerTreeView() override;
+  void IntrinsicSizingInfoChanged(
+      const blink::WebIntrinsicSizingInfo&) override;
   void DidMeaningfulLayout(blink::WebMeaningfulLayout layout_type) override;
   void DidChangeCursor(const blink::WebCursorInfo&) override;
   void AutoscrollStart(const blink::WebFloatPoint& point) override;
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index 26a09583..f222b9e 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -775,7 +775,8 @@
   test_phase_ = CLEAN_UP;
   if (!printer_->output_finished())
     printer_->PrintImageFooter();
-  main_window_->web_contents()->ExitFullscreen(/*will_cause_resize=*/false);
+  if (main_window_)
+    main_window_->web_contents()->ExitFullscreen(/*will_cause_resize=*/false);
   devtools_bindings_.reset();
   devtools_protocol_test_bindings_.reset();
 
@@ -926,6 +927,13 @@
   if (pending_layout_dumps_ > 0)
     return;
 
+  // If the main test window was destroyed while waiting for the responses, then
+  // there is nobody to receive the |stitched_layout_dump| and finish the test.
+  if (!web_contents()) {
+    OnTestFinished();
+    return;
+  }
+
   // Stitch the frame-specific results in the right order.
   std::string stitched_layout_dump;
   for (auto* render_frame_host : web_contents()->GetAllFrames()) {
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index a8c2d15..fa0d6d2 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -731,7 +731,6 @@
     "../browser/frame_host/render_frame_message_filter_browsertest.cc",
     "../browser/generic_sensor_browsertest.cc",
     "../browser/gpu/gpu_ipc_browsertests.cc",
-    "../browser/gpu/in_process_gpu_thread_browsertests.cc",
     "../browser/indexed_db/indexed_db_browsertest.cc",
     "../browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc",
     "../browser/indexed_db/mock_browsertest_indexed_db_class_factory.h",
@@ -796,6 +795,7 @@
     "../browser/shared_worker/worker_browsertest.cc",
     "../browser/site_per_process_browsertest.cc",
     "../browser/site_per_process_browsertest.h",
+    "../browser/site_per_process_hit_test_browsertest.cc",
     "../browser/site_per_process_mac_browsertest.mm",
     "../browser/snapshot_browsertest.cc",
     "../browser/storage_partition_impl_browsertest.cc",
@@ -863,7 +863,6 @@
     "//content/public/browser",
     "//content/public/child",
     "//content/public/common",
-    "//content/public/gpu:gpu_sources",
     "//content/public/renderer",
     "//content/renderer:for_content_tests",
     "//content/shell:content_shell_lib",
@@ -962,12 +961,6 @@
     ]
   }
 
-  # FIXME: Workaround for link errors on win_chromium_compile_dbg_ng.
-  if (is_win) {
-    deps -= [ "//content/public/gpu:gpu_sources" ]
-    sources -= [ "../browser/gpu/in_process_gpu_thread_browsertests.cc" ]
-  }
-
   if (is_win) {
     sources += [ "../browser/accessibility/accessibility_win_browsertest.cc" ]
 
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 87820f3..700aeced 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -332,6 +332,7 @@
         ['passthrough', 'opengl', 'intel'], bug=602688)
 
     # Passthrough command decoder / Linux / OpenGL / NVIDIA
+    self.Flaky('*', ['linux', 'passthrough', 'opengl', 'nvidia'], bug=602688)
     self.Fail('conformance/textures/image_bitmap_from_video/' +
         'tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html',
         ['linux', 'passthrough', 'opengl', 'nvidia'], bug=773861)
diff --git a/device/geolocation/geolocation_impl.h b/device/geolocation/geolocation_impl.h
index 0036ba68..97e14d18 100644
--- a/device/geolocation/geolocation_impl.h
+++ b/device/geolocation/geolocation_impl.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef DEVICE_GEOLOCATION_GEOLOCATION_IMPL_H_
+#define DEVICE_GEOLOCATION_GEOLOCATION_IMPL_H_
+
 #include <memory>
 
 #include "base/macros.h"
@@ -9,9 +12,6 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/device/public/interfaces/geolocation.mojom.h"
 
-#ifndef DEVICE_GEOLOCATION_GEOLOCATION_IMPL_H_
-#define DEVICE_GEOLOCATION_GEOLOCATION_IMPL_H_
-
 namespace device {
 
 class GeolocationProvider;
diff --git a/device/test/test_device_client.h b/device/test/test_device_client.h
index c984a0a..ed684c6a 100644
--- a/device/test/test_device_client.h
+++ b/device/test/test_device_client.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef DEVICE_TEST_TEST_DEVICE_CLIENT_H_
+#define DEVICE_TEST_TEST_DEVICE_CLIENT_H_
+
 #include <memory>
 
 #include "build/build_config.h"
@@ -25,3 +28,5 @@
 };
 
 }  // namespace device
+
+#endif  // DEVICE_TEST_TEST_DEVICE_CLIENT_H_
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 24f41ae..08ecc391 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -261,6 +261,8 @@
     "install_flag.h",
     "io_thread_extension_message_filter.cc",
     "io_thread_extension_message_filter.h",
+    "json_file_sanitizer.cc",
+    "json_file_sanitizer.h",
     "lazy_background_task_queue.cc",
     "lazy_background_task_queue.h",
     "lazy_background_task_queue_factory.cc",
@@ -554,6 +556,7 @@
     "image_loader_unittest.cc",
     "image_sanitizer_unittest.cc",
     "info_map_unittest.cc",
+    "json_file_sanitizer_unittest.cc",
     "lazy_background_task_queue_unittest.cc",
     "load_monitoring_extension_host_queue_unittest.cc",
     "management_policy_unittest.cc",
diff --git a/extensions/browser/json_file_sanitizer.cc b/extensions/browser/json_file_sanitizer.cc
new file mode 100644
index 0000000..f943ecbe
--- /dev/null
+++ b/extensions/browser/json_file_sanitizer.cc
@@ -0,0 +1,148 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/json_file_sanitizer.h"
+
+#include "base/files/file_util.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/task_runner_util.h"
+#include "extensions/browser/extension_file_task_runner.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace extensions {
+
+namespace {
+
+// Reads the file in |path| and then deletes it.
+// Returns a tuple containing: the file content, whether the read was
+// successful, whether the delete was successful.
+std::tuple<std::string, bool, bool> ReadAndDeleteFile(
+    const base::FilePath& path) {
+  std::string contents;
+  bool read_success = base::ReadFileToString(path, &contents);
+  bool delete_success = base::DeleteFile(path, /*recursive=*/false);
+  return std::make_tuple(contents, read_success, delete_success);
+}
+
+int WriteStringToFile(const std::string& contents,
+                      const base::FilePath& file_path) {
+  int size = static_cast<int>(contents.length());
+  return base::WriteFile(file_path, contents.data(), size);
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<JsonFileSanitizer> JsonFileSanitizer::CreateAndStart(
+    service_manager::Connector* connector,
+    const service_manager::Identity& identity,
+    const std::set<base::FilePath>& file_paths,
+    Callback callback) {
+  // Note we can't use std::make_unique as we want to keep the constructor
+  // private.
+  std::unique_ptr<JsonFileSanitizer> sanitizer(
+      new JsonFileSanitizer(file_paths, std::move(callback)));
+  sanitizer->Start(connector, identity);
+  return sanitizer;
+}
+
+JsonFileSanitizer::JsonFileSanitizer(const std::set<base::FilePath>& file_paths,
+                                     Callback callback)
+    : file_paths_(file_paths),
+      callback_(std::move(callback)),
+      weak_factory_(this) {}
+
+JsonFileSanitizer::~JsonFileSanitizer() = default;
+
+void JsonFileSanitizer::Start(service_manager::Connector* connector,
+                              const service_manager::Identity& identity) {
+  if (file_paths_.empty()) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&JsonFileSanitizer::ReportSuccess,
+                                  weak_factory_.GetWeakPtr()));
+    return;
+  }
+
+  connector->BindInterface(identity, &json_parser_ptr_);
+
+  for (const base::FilePath& path : file_paths_) {
+    base::PostTaskAndReplyWithResult(
+        extensions::GetExtensionFileTaskRunner().get(), FROM_HERE,
+        base::BindOnce(&ReadAndDeleteFile, path),
+        base::BindOnce(&JsonFileSanitizer::JsonFileRead,
+                       weak_factory_.GetWeakPtr(), path));
+  }
+}
+
+void JsonFileSanitizer::JsonFileRead(
+    const base::FilePath& file_path,
+    std::tuple<std::string, bool, bool> read_and_delete_result) {
+  if (!std::get<1>(read_and_delete_result)) {
+    ReportError(Status::kFileReadError, std::string());
+    return;
+  }
+  if (!std::get<2>(read_and_delete_result)) {
+    ReportError(Status::kFileDeleteError, std::string());
+    return;
+  }
+  json_parser_ptr_->Parse(
+      std::get<0>(read_and_delete_result),
+      base::BindOnce(&JsonFileSanitizer::JsonParsingDone,
+                     weak_factory_.GetWeakPtr(), file_path));
+}
+
+void JsonFileSanitizer::JsonParsingDone(
+    const base::FilePath& file_path,
+    std::unique_ptr<base::Value> json_value,
+    const base::Optional<std::string>& error) {
+  if (!json_value || !json_value->is_dict()) {
+    ReportError(Status::kDecodingError, error ? *error : std::string());
+    return;
+  }
+
+  // Reserialize the JSON and write it back to the original file.
+  std::string json_string;
+  JSONStringValueSerializer serializer(&json_string);
+  serializer.set_pretty_print(true);
+  if (!serializer.Serialize(*json_value)) {
+    ReportError(Status::kSerializingError, std::string());
+    return;
+  }
+
+  int size = static_cast<int>(json_string.length());
+  base::PostTaskAndReplyWithResult(
+      extensions::GetExtensionFileTaskRunner().get(), FROM_HERE,
+      base::BindOnce(&WriteStringToFile, std::move(json_string), file_path),
+      base::BindOnce(&JsonFileSanitizer::JsonFileWritten,
+                     weak_factory_.GetWeakPtr(), file_path, size));
+}
+
+void JsonFileSanitizer::JsonFileWritten(const base::FilePath& file_path,
+                                        int expected_size,
+                                        int actual_size) {
+  if (expected_size != actual_size) {
+    ReportError(Status::kFileWriteError, std::string());
+    return;
+  }
+  // We have finished with this JSON file.
+  size_t removed_count = file_paths_.erase(file_path);
+  DCHECK_EQ(1U, removed_count);
+
+  if (file_paths_.empty()) {
+    // This was the last path, we are done.
+    ReportSuccess();
+  }
+}
+
+void JsonFileSanitizer::ReportSuccess() {
+  std::move(callback_).Run(Status::kSuccess, std::string());
+}
+
+void JsonFileSanitizer::ReportError(Status status, const std::string& error) {
+  // Prevent any other task from reporting, we want to notify only once.
+  weak_factory_.InvalidateWeakPtrs();
+  std::move(callback_).Run(status, error);
+}
+
+}  // namespace extensions
\ No newline at end of file
diff --git a/extensions/browser/json_file_sanitizer.h b/extensions/browser/json_file_sanitizer.h
new file mode 100644
index 0000000..efce47b
--- /dev/null
+++ b/extensions/browser/json_file_sanitizer.h
@@ -0,0 +1,101 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_JSON_FILE_SANITIZER_H_
+#define EXTENSIONS_BROWSER_JSON_FILE_SANITIZER_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <tuple>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/values.h"
+#include "services/data_decoder/public/interfaces/json_parser.mojom.h"
+#include "services/service_manager/public/cpp/identity.h"
+
+namespace service_manager {
+class Connector;
+}
+
+namespace extensions {
+
+// This class takes potentially unsafe JSON files, decodes them in a sandboxed
+// process, then reencodes them so that they can later be parsed safely from the
+// browser process.
+// Note that at this time it this is limited to JSON files that contain a
+// unique dictionary as their root and will fail with a kDecodingError if that
+// is not the case.
+class JsonFileSanitizer {
+ public:
+  enum class Status {
+    kSuccess = 0,
+    kFileReadError,
+    kFileDeleteError,
+    kDecodingError,
+    kSerializingError,
+    kFileWriteError,
+  };
+
+  // Callback invoked when the JSON sanitization is is done. If status is an
+  // error, |error_msg| contains the error message.
+  using Callback =
+      base::OnceCallback<void(Status status, const std::string& error_msg)>;
+
+  // Creates a JsonFileSanitizer and starts the sanitization of the JSON files
+  // in |file_paths|.
+  // |connector| should be a connector to the ServiceManager usable on the
+  // current thread. |identity| is used when accessing the data decoder service
+  // which is used internally to parse JSON. It lets callers indicate they'd
+  // like to use a sahred process for the data decoder service with some
+  // potentially unrelated data decoding operations.
+  // |callback| is invoked asynchronously when all JSON files have been
+  // sanitized or if an error occurred.
+  // If the returned JsonFileSanitizer instance is deleted before |callback| was
+  // invoked, then |callback| is never invoked and the sanitization stops
+  // promptly (some background tasks may still run).
+  static std::unique_ptr<JsonFileSanitizer> CreateAndStart(
+      service_manager::Connector* connector,
+      const service_manager::Identity& identity,
+      const std::set<base::FilePath>& file_paths,
+      Callback callback);
+
+  ~JsonFileSanitizer();
+
+ private:
+  JsonFileSanitizer(const std::set<base::FilePath>& file_paths,
+                    Callback callback);
+
+  void Start(service_manager::Connector* connector,
+             const service_manager::Identity& identity);
+
+  void JsonFileRead(const base::FilePath& file_path,
+                    std::tuple<std::string, bool, bool> read_and_delete_result);
+
+  void JsonParsingDone(const base::FilePath& file_path,
+                       std::unique_ptr<base::Value> json_value,
+                       const base::Optional<std::string>& error);
+
+  void JsonFileWritten(const base::FilePath& file_path,
+                       int expected_size,
+                       int actual_size);
+
+  void ReportSuccess();
+
+  void ReportError(Status status, const std::string& path);
+
+  std::set<base::FilePath> file_paths_;
+  Callback callback_;
+  data_decoder::mojom::JsonParserPtr json_parser_ptr_;
+  base::WeakPtrFactory<JsonFileSanitizer> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(JsonFileSanitizer);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_JSON_FILE_SANITIZER_H_
\ No newline at end of file
diff --git a/extensions/browser/json_file_sanitizer_unittest.cc b/extensions/browser/json_file_sanitizer_unittest.cc
new file mode 100644
index 0000000..25ed508
--- /dev/null
+++ b/extensions/browser/json_file_sanitizer_unittest.cc
@@ -0,0 +1,149 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/json_file_sanitizer.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "services/data_decoder/public/cpp/test_data_decoder_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+class JsonFileSanitizerTest : public testing::Test {
+ public:
+  JsonFileSanitizerTest()
+      : thread_bundle_(content::TestBrowserThreadBundle::DEFAULT) {}
+
+ protected:
+  base::FilePath CreateFilePath(const base::FilePath::StringType& file_name) {
+    return temp_dir_.GetPath().Append(file_name);
+  }
+
+  void CreateValidJsonFile(const base::FilePath& path) {
+    std::string kJson = "{\"hello\":\"bonjour\"}";
+    ASSERT_TRUE(base::WriteFile(path, kJson.data(), kJson.size()));
+  }
+
+  void CreateInvalidJsonFile(const base::FilePath& path) {
+    std::string kJson = "sjkdsk;'<?js";
+    ASSERT_TRUE(base::WriteFile(path, kJson.data(), kJson.size()));
+  }
+
+  const base::FilePath& GetJsonFilePath() const { return temp_dir_.GetPath(); }
+
+  void WaitForSanitizationDone() {
+    ASSERT_FALSE(done_callback_);
+    base::RunLoop run_loop;
+    done_callback_ = run_loop.QuitClosure();
+    run_loop.Run();
+  }
+
+  void CreateAndStartSanitizer(const std::set<base::FilePath>& file_paths) {
+    sanitizer_ = JsonFileSanitizer::CreateAndStart(
+        test_data_decoder_service_.connector(), service_manager::Identity(),
+        file_paths,
+        base::BindOnce(&JsonFileSanitizerTest::SanitizationDone,
+                       base::Unretained(this)));
+  }
+
+  JsonFileSanitizer::Status last_reported_status() const {
+    return last_status_;
+  }
+
+  const std::string& last_reported_error() const { return last_error_; }
+
+ private:
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  void SanitizationDone(JsonFileSanitizer::Status status,
+                        const std::string& error_msg) {
+    last_status_ = status;
+    last_error_ = error_msg;
+    if (done_callback_)
+      std::move(done_callback_).Run();
+  }
+
+  content::TestBrowserThreadBundle thread_bundle_;
+  data_decoder::TestDataDecoderService test_data_decoder_service_;
+  JsonFileSanitizer::Status last_status_;
+  std::string last_error_;
+  base::OnceClosure done_callback_;
+  std::unique_ptr<JsonFileSanitizer> sanitizer_;
+  base::ScopedTempDir temp_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(JsonFileSanitizerTest);
+};
+
+}  // namespace
+
+TEST_F(JsonFileSanitizerTest, NoFilesProvided) {
+  CreateAndStartSanitizer(std::set<base::FilePath>());
+  WaitForSanitizationDone();
+  EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kSuccess);
+  EXPECT_TRUE(last_reported_error().empty());
+}
+
+TEST_F(JsonFileSanitizerTest, ValidCase) {
+  constexpr std::array<const base::FilePath::CharType* const, 10> kFileNames{
+      {FILE_PATH_LITERAL("test0"), FILE_PATH_LITERAL("test1"),
+       FILE_PATH_LITERAL("test2"), FILE_PATH_LITERAL("test3"),
+       FILE_PATH_LITERAL("test4"), FILE_PATH_LITERAL("test5"),
+       FILE_PATH_LITERAL("test6"), FILE_PATH_LITERAL("test7"),
+       FILE_PATH_LITERAL("test8"), FILE_PATH_LITERAL("test9")}};
+  std::set<base::FilePath> paths;
+  for (const base::FilePath::CharType* file_name : kFileNames) {
+    base::FilePath path = CreateFilePath(file_name);
+    CreateValidJsonFile(path);
+    paths.insert(path);
+  }
+  CreateAndStartSanitizer(paths);
+  WaitForSanitizationDone();
+  EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kSuccess);
+  EXPECT_TRUE(last_reported_error().empty());
+  // Make sure the JSON files are there and non empty.
+  for (const auto& path : paths) {
+    int64_t file_size = 0;
+    EXPECT_TRUE(base::GetFileSize(path, &file_size));
+    EXPECT_GT(file_size, 0);
+  }
+}
+
+TEST_F(JsonFileSanitizerTest, MissingJsonFile) {
+  constexpr base::FilePath::CharType kGoodName[] =
+      FILE_PATH_LITERAL("i_exists");
+  constexpr base::FilePath::CharType kNonExistingName[] =
+      FILE_PATH_LITERAL("i_don_t_exist");
+  base::FilePath good_path = CreateFilePath(kGoodName);
+  CreateValidJsonFile(good_path);
+  base::FilePath invalid_path = CreateFilePath(kNonExistingName);
+  CreateAndStartSanitizer({good_path, invalid_path});
+  WaitForSanitizationDone();
+  EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kFileReadError);
+}
+
+TEST_F(JsonFileSanitizerTest, InvalidJson) {
+  constexpr base::FilePath::CharType kGoodJsonFileName[] =
+      FILE_PATH_LITERAL("good.json");
+  constexpr base::FilePath::CharType kBadJsonFileName[] =
+      FILE_PATH_LITERAL("bad.json");
+  base::FilePath good_path = CreateFilePath(kGoodJsonFileName);
+  CreateValidJsonFile(good_path);
+  base::FilePath badd_path = CreateFilePath(kBadJsonFileName);
+  CreateInvalidJsonFile(badd_path);
+  CreateAndStartSanitizer({good_path, badd_path});
+  WaitForSanitizationDone();
+  EXPECT_EQ(last_reported_status(), JsonFileSanitizer::Status::kDecodingError);
+  EXPECT_FALSE(last_reported_error().empty());
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 84cdd3d..425cccd 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -14,6 +14,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/i18n/rtl.h"
 #include "base/json/json_string_value_serializer.h"
@@ -27,6 +28,7 @@
 #include "components/crx_file/crx_verifier.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/api/declarative_net_request/utils.h"
+#include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
@@ -39,6 +41,7 @@
 #include "extensions/common/features/feature_session_type.h"
 #include "extensions/common/file_util.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/default_locale_handler.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
 #include "extensions/common/switches.h"
 #include "extensions/strings/grit/extensions_strings.h"
@@ -185,20 +188,23 @@
   return false;
 }
 
-// Read the decoded message catalogs back from the file we saved them to.
-// |extension_path| is the path to the extension we unpacked that wrote the
-// data. Returns true on success.
-bool ReadMessageCatalogsFromFile(const base::FilePath& extension_path,
-                                 base::DictionaryValue* catalogs) {
-  base::FilePath path =
-      extension_path.AppendASCII(kDecodedMessageCatalogsFilename);
-  std::string file_str;
-  if (!base::ReadFileToString(path, &file_str))
-    return false;
+std::set<base::FilePath> GetMessageCatalogPathsToBeSanitized(
+    const base::FilePath& locales_path) {
+  // Not all folders under _locales have to be valid locales.
+  base::FileEnumerator locales(locales_path, /*recursive=*/false,
+                               base::FileEnumerator::DIRECTORIES);
 
-  IPC::Message pickle(file_str.data(), file_str.size());
-  base::PickleIterator iter(pickle);
-  return IPC::ReadParam(&pickle, &iter, catalogs);
+  std::set<base::FilePath> message_catalog_paths;
+  std::set<std::string> all_locales;
+  extension_l10n_util::GetAllLocales(&all_locales);
+  base::FilePath locale_path;
+  while (!(locale_path = locales.Next()).empty()) {
+    if (!extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
+                                                   all_locales)) {
+      message_catalog_paths.insert(locale_path.Append(kMessagesFilename));
+    }
+  }
+  return message_catalog_paths;
 }
 
 }  // namespace
@@ -236,7 +242,7 @@
 }
 
 bool SandboxedUnpacker::CreateTempDirectory() {
-  CHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
 
   base::FilePath temp_dir;
   if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) {
@@ -261,7 +267,7 @@
 void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) {
   // We assume that we are started on the thread that the client wants us
   // to do file IO on.
-  CHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
 
   crx_unpack_start_time_ = base::TimeTicks::Now();
   std::string expected_hash;
@@ -354,6 +360,18 @@
   // This is OK because ExtensionGarbageCollector will take care of the leaked
   // |temp_dir_| eventually.
   temp_dir_.Take();
+
+  // Make sure that members get deleted on the thread they were created.
+  if (image_sanitizer_) {
+    unpacker_io_task_runner_->DeleteSoon(FROM_HERE,
+                                         std::move(image_sanitizer_));
+  }
+  if (json_file_sanitizer_) {
+    unpacker_io_task_runner_->DeleteSoon(FROM_HERE,
+                                         std::move(json_file_sanitizer_));
+  }
+  if (connector_)
+    unpacker_io_task_runner_->DeleteSoon(FROM_HERE, std::move(connector_));
 }
 
 void SandboxedUnpacker::StartUtilityProcessIfNeeded() {
@@ -461,7 +479,7 @@
 void SandboxedUnpacker::UnpackExtensionSucceeded(
     std::unique_ptr<base::DictionaryValue> manifest,
     std::unique_ptr<base::ListValue> json_ruleset) {
-  CHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
 
   std::unique_ptr<base::DictionaryValue> final_manifest(
       RewriteManifestFile(*manifest));
@@ -515,6 +533,7 @@
     return;
   }
 
+  DCHECK(!image_sanitizer_);
   std::set<base::FilePath> image_paths =
       ExtensionsClient::Get()->GetBrowserImagePaths(extension_.get());
   image_sanitizer_ = ImageSanitizer::CreateAndStart(
@@ -524,6 +543,12 @@
                      std::move(manifest), std::move(json_ruleset)));
 }
 
+void SandboxedUnpacker::ImageSanitizerDecodedImage(const base::FilePath& path,
+                                                   SkBitmap image) {
+  if (path == install_icon_path_)
+    install_icon_ = image;
+}
+
 void SandboxedUnpacker::ImageSanitizationDone(
     std::unique_ptr<base::DictionaryValue> manifest,
     std::unique_ptr<base::ListValue> json_ruleset,
@@ -536,17 +561,8 @@
   image_sanitizer_ = nullptr;
 
   if (status == ImageSanitizer::Status::kSuccess) {
-    if (!RewriteCatalogFiles())
-      return;
-
-    // Index and persist ruleset for the Declarative Net Request API.
-    base::Optional<int> dnr_ruleset_checksum;
-    if (!IndexAndPersistRulesIfNeeded(std::move(json_ruleset),
-                                      &dnr_ruleset_checksum)) {
-      return;  // Failure was already reported.
-    }
-
-    ReportSuccess(std::move(manifest), dnr_ruleset_checksum);
+    // Next step is to sanitize the message catalogs.
+    ReadMessageCatalogs(std::move(manifest), std::move(json_ruleset));
     return;
   }
 
@@ -592,10 +608,82 @@
   ReportFailure(failure_reason, error);
 }
 
-void SandboxedUnpacker::ImageSanitizerDecodedImage(const base::FilePath& path,
-                                                   SkBitmap image) {
-  if (path == install_icon_path_)
-    install_icon_ = image;
+void SandboxedUnpacker::ReadMessageCatalogs(
+    std::unique_ptr<base::DictionaryValue> manifest,
+    std::unique_ptr<base::ListValue> json_ruleset) {
+  DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+  if (LocaleInfo::GetDefaultLocale(extension_.get()).empty()) {
+    MessageCatalogsSanitized(std::move(manifest), std::move(json_ruleset),
+                             JsonFileSanitizer::Status::kSuccess,
+                             std::string());
+    return;
+  }
+
+  // Get the paths to the message catalogs we should sanitize on the file task
+  // runner.
+  base::FilePath locales_path = extension_root_.Append(kLocaleFolder);
+
+  base::PostTaskAndReplyWithResult(
+      extensions::GetExtensionFileTaskRunner().get(), FROM_HERE,
+      base::BindOnce(&GetMessageCatalogPathsToBeSanitized, locales_path),
+      base::BindOnce(&SandboxedUnpacker::SanitizeMessageCatalogs, this,
+                     std::move(manifest), std::move(json_ruleset)));
+}
+
+void SandboxedUnpacker::SanitizeMessageCatalogs(
+    std::unique_ptr<base::DictionaryValue> manifest,
+    std::unique_ptr<base::ListValue> json_ruleset,
+    const std::set<base::FilePath>& message_catalog_paths) {
+  DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+  json_file_sanitizer_ = JsonFileSanitizer::CreateAndStart(
+      connector_.get(), data_decoder_identity_, message_catalog_paths,
+      base::BindOnce(&SandboxedUnpacker::MessageCatalogsSanitized, this,
+                     std::move(manifest), std::move(json_ruleset)));
+}
+
+void SandboxedUnpacker::MessageCatalogsSanitized(
+    std::unique_ptr<base::DictionaryValue> manifest,
+    std::unique_ptr<base::ListValue> json_ruleset,
+    JsonFileSanitizer::Status status,
+    const std::string& error_msg) {
+  DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+  if (status == JsonFileSanitizer::Status::kSuccess) {
+    // Index and persist ruleset for the Declarative Net Request API.
+    base::Optional<int> dnr_ruleset_checksum;
+    if (!IndexAndPersistRulesIfNeeded(std::move(json_ruleset),
+                                      &dnr_ruleset_checksum)) {
+      return;  // Failure was already reported.
+    }
+
+    ReportSuccess(std::move(manifest), dnr_ruleset_checksum);
+    return;
+  }
+
+  FailureReason failure_reason = UNPACKER_CLIENT_FAILED;
+  base::string16 error;
+  switch (status) {
+    case JsonFileSanitizer::Status::kFileReadError:
+    case JsonFileSanitizer::Status::kDecodingError:
+      failure_reason = INVALID_CATALOG_DATA;
+      error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+                                         ASCIIToUTF16("INVALID_CATALOG_DATA"));
+      break;
+    case JsonFileSanitizer::Status::kSerializingError:
+      failure_reason = ERROR_SERIALIZING_CATALOG;
+      error =
+          l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+                                     ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"));
+    case JsonFileSanitizer::Status::kFileDeleteError:
+    case JsonFileSanitizer::Status::kFileWriteError:
+      failure_reason = ERROR_SAVING_CATALOG;
+      error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
+                                         ASCIIToUTF16("ERROR_SAVING_CATALOG"));
+    default:
+      NOTREACHED();
+      break;
+  }
+
+  ReportFailure(failure_reason, error);
 }
 
 bool SandboxedUnpacker::IndexAndPersistRulesIfNeeded(
@@ -645,7 +733,7 @@
 }
 
 void SandboxedUnpacker::UnpackExtensionFailed(const base::string16& error) {
-  CHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
 
   ReportFailure(
       UNPACKER_CLIENT_FAILED,
@@ -704,10 +792,6 @@
     case ERROR_SAVING_MANIFEST_JSON:
       return ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON");
 
-    case COULD_NOT_READ_IMAGE_DATA_FROM_DISK:
-      return ASCIIToUTF16("COULD_NOT_READ_IMAGE_DATA_FROM_DISK");
-    case DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST:
-      return ASCIIToUTF16("DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST");
     case INVALID_PATH_FOR_BROWSER_IMAGE:
       return ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE");
     case ERROR_REMOVING_OLD_IMAGE_FILE:
@@ -719,12 +803,8 @@
     case ERROR_SAVING_THEME_IMAGE:
       return ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE");
 
-    case COULD_NOT_READ_CATALOG_DATA_FROM_DISK:
-      return ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK");
     case INVALID_CATALOG_DATA:
       return ASCIIToUTF16("INVALID_CATALOG_DATA");
-    case INVALID_PATH_FOR_CATALOG:
-      return ASCIIToUTF16("INVALID_PATH_FOR_CATALOG");
     case ERROR_SERIALIZING_CATALOG:
       return ASCIIToUTF16("ERROR_SERIALIZING_CATALOG");
     case ERROR_SAVING_CATALOG:
@@ -745,6 +825,7 @@
 
     case DEPRECATED_ABORTED_DUE_TO_SHUTDOWN:
     case NUM_FAILURE_REASONS:
+    default:
       NOTREACHED();
       return base::string16();
   }
@@ -885,70 +966,6 @@
   return final_manifest.release();
 }
 
-bool SandboxedUnpacker::RewriteCatalogFiles() {
-  base::DictionaryValue catalogs;
-  if (!ReadMessageCatalogsFromFile(temp_dir_.GetPath(), &catalogs)) {
-    // Could not read catalog data from disk.
-    ReportFailure(COULD_NOT_READ_CATALOG_DATA_FROM_DISK,
-                  l10n_util::GetStringFUTF16(
-                      IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
-                      ASCIIToUTF16("COULD_NOT_READ_CATALOG_DATA_FROM_DISK")));
-    return false;
-  }
-
-  // Write our parsed catalogs back to disk.
-  for (base::DictionaryValue::Iterator it(catalogs); !it.IsAtEnd();
-       it.Advance()) {
-    const base::DictionaryValue* catalog = NULL;
-    if (!it.value().GetAsDictionary(&catalog)) {
-      // Invalid catalog data.
-      ReportFailure(
-          INVALID_CATALOG_DATA,
-          l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
-                                     ASCIIToUTF16("INVALID_CATALOG_DATA")));
-      return false;
-    }
-
-    base::FilePath relative_path = base::FilePath::FromUTF8Unsafe(it.key());
-    relative_path = relative_path.Append(kMessagesFilename);
-    if (relative_path.IsAbsolute() || relative_path.ReferencesParent()) {
-      // Invalid path for catalog.
-      ReportFailure(
-          INVALID_PATH_FOR_CATALOG,
-          l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
-                                     ASCIIToUTF16("INVALID_PATH_FOR_CATALOG")));
-      return false;
-    }
-
-    base::FilePath path = extension_root_.Append(relative_path);
-
-    std::string catalog_json;
-    JSONStringValueSerializer serializer(&catalog_json);
-    serializer.set_pretty_print(true);
-    if (!serializer.Serialize(*catalog)) {
-      // Error serializing catalog.
-      ReportFailure(ERROR_SERIALIZING_CATALOG,
-                    l10n_util::GetStringFUTF16(
-                        IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
-                        ASCIIToUTF16("ERROR_SERIALIZING_CATALOG")));
-      return false;
-    }
-
-    // Note: we're overwriting existing files that the utility process read,
-    // so we can be sure the directory exists.
-    int size = base::checked_cast<int>(catalog_json.size());
-    if (base::WriteFile(path, catalog_json.c_str(), size) != size) {
-      // Error saving catalog.
-      ReportFailure(
-          ERROR_SAVING_CATALOG,
-          l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR,
-                                     ASCIIToUTF16("ERROR_SAVING_CATALOG")));
-      return false;
-    }
-  }
-
-  return true;
-}
 
 void SandboxedUnpacker::Cleanup() {
   DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
@@ -956,6 +973,9 @@
     LOG(WARNING) << "Can not delete temp directory at "
                  << temp_dir_.GetPath().value();
   }
+  connector_.reset();
+  image_sanitizer_.reset();
+  json_file_sanitizer_.reset();
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/sandboxed_unpacker.h b/extensions/browser/sandboxed_unpacker.h
index a9dd506..2e4ff34b 100644
--- a/extensions/browser/sandboxed_unpacker.h
+++ b/extensions/browser/sandboxed_unpacker.h
@@ -19,6 +19,7 @@
 #include "extensions/browser/crx_file_info.h"
 #include "extensions/browser/image_sanitizer.h"
 #include "extensions/browser/install/crx_install_error.h"
+#include "extensions/browser/json_file_sanitizer.h"
 #include "extensions/common/manifest.h"
 #include "services/service_manager/public/cpp/identity.h"
 
@@ -177,8 +178,8 @@
     ERROR_SAVING_MANIFEST_JSON,
 
     // SandboxedUnpacker::RewriteImageFiles()
-    COULD_NOT_READ_IMAGE_DATA_FROM_DISK,
-    DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST,
+    COULD_NOT_READ_IMAGE_DATA_FROM_DISK_UNUSED,
+    DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST_UNUSED,
     INVALID_PATH_FOR_BROWSER_IMAGE,
     ERROR_REMOVING_OLD_IMAGE_FILE,
     INVALID_PATH_FOR_BITMAP_IMAGE,
@@ -187,9 +188,9 @@
     DEPRECATED_ABORTED_DUE_TO_SHUTDOWN,  // No longer used; kept for UMA.
 
     // SandboxedUnpacker::RewriteCatalogFiles()
-    COULD_NOT_READ_CATALOG_DATA_FROM_DISK,
+    COULD_NOT_READ_CATALOG_DATA_FROM_DISK_UNUSED,
     INVALID_CATALOG_DATA,
-    INVALID_PATH_FOR_CATALOG,
+    INVALID_PATH_FOR_CATALOG_UNUSED,
     ERROR_SERIALIZING_CATALOG,
     ERROR_SAVING_CATALOG,
 
@@ -251,6 +252,19 @@
                              const base::FilePath& path);
   void ImageSanitizerDecodedImage(const base::FilePath& path, SkBitmap image);
 
+  void ReadMessageCatalogs(std::unique_ptr<base::DictionaryValue> manifest,
+                           std::unique_ptr<base::ListValue> json_ruleset);
+
+  void SanitizeMessageCatalogs(
+      std::unique_ptr<base::DictionaryValue> manifest,
+      std::unique_ptr<base::ListValue> json_ruleset,
+      const std::set<base::FilePath>& message_catalog_paths);
+
+  void MessageCatalogsSanitized(std::unique_ptr<base::DictionaryValue> manifest,
+                                std::unique_ptr<base::ListValue> json_ruleset,
+                                JsonFileSanitizer::Status status,
+                                const std::string& error_msg);
+
   // Reports unpack success or failure, or unzip failure.
   void ReportSuccess(std::unique_ptr<base::DictionaryValue> original_manifest,
                      const base::Optional<int>& dnr_ruleset_checksum);
@@ -261,10 +275,6 @@
   base::DictionaryValue* RewriteManifestFile(
       const base::DictionaryValue& manifest);
 
-  // Overwrites original files with safe results from utility process.
-  // Reports error and returns false if it fails.
-  bool RewriteCatalogFiles();
-
   // Cleans up temp directory artifacts.
   void Cleanup();
 
@@ -338,6 +348,10 @@
   // The ImageSanitizer used to clean-up images.
   std::unique_ptr<ImageSanitizer> image_sanitizer_;
 
+  // Used during the message catalog rewriting phase to sanitize the extension
+  // provided message catalogs.
+  std::unique_ptr<JsonFileSanitizer> json_file_sanitizer_;
+
   DISALLOW_COPY_AND_ASSIGN(SandboxedUnpacker);
 };
 
diff --git a/extensions/browser/sandboxed_unpacker_unittest.cc b/extensions/browser/sandboxed_unpacker_unittest.cc
index 40f1508..4f990fcf 100644
--- a/extensions/browser/sandboxed_unpacker_unittest.cc
+++ b/extensions/browser/sandboxed_unpacker_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/strings/pattern.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -23,6 +24,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_paths.h"
+#include "extensions/common/manifest_constants.h"
 #include "extensions/common/switches.h"
 #include "extensions/test/test_extensions_client.h"
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
@@ -251,6 +253,18 @@
   EXPECT_NE(base::string16(), GetInstallError());
 }
 
+TEST_F(SandboxedUnpackerTest, InvalidMessagesFile) {
+  SetupUnpackerWithDirectory("invalid_messages_file.crx");
+  // Check that there is no _locales folder.
+  base::FilePath install_path = GetInstallPath().Append(kLocaleFolder);
+  EXPECT_FALSE(base::PathExists(install_path));
+  EXPECT_TRUE(base::MatchPattern(
+      GetInstallError(),
+      base::ASCIIToUTF16("*_locales?en_US?messages.json': Line: 2, column: 10,"
+                         " Syntax error.'.")))
+      << GetInstallError();
+}
+
 TEST_F(SandboxedUnpackerTest, PassHashCheck) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       extensions::switches::kEnableCrxHashCheck);
diff --git a/extensions/utility/unpacker.cc b/extensions/utility/unpacker.cc
index 405bf335..59c3cab 100644
--- a/extensions/utility/unpacker.cc
+++ b/extensions/utility/unpacker.cc
@@ -10,10 +10,8 @@
 #include <tuple>
 #include <utility>
 
-#include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/i18n/rtl.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
@@ -29,11 +27,8 @@
 #include "extensions/common/file_util.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
-#include "extensions/common/manifest_handlers/default_locale_handler.h"
 #include "extensions/strings/grit/extensions_strings.h"
-#include "ipc/ipc_message_utils.h"
 #include "net/base/file_stream.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -50,13 +45,6 @@
     FILE_PATH_LITERAL(".json"), FILE_PATH_LITERAL(".png"),
     FILE_PATH_LITERAL(".webp")};
 
-bool WritePickle(const IPC::Message& pickle, const base::FilePath& dest_path) {
-  int size = base::checked_cast<int>(pickle.size());
-  const char* data = static_cast<const char*>(pickle.data());
-  int bytes_written = base::WriteFile(dest_path, data, size);
-  return (bytes_written == size);
-}
-
 }  // namespace
 
 Unpacker::Unpacker(const base::FilePath& working_dir,
@@ -123,30 +111,6 @@
   return base::DictionaryValue::From(std::move(root));
 }
 
-bool Unpacker::ReadAllMessageCatalogs() {
-  base::FilePath locales_path = extension_dir_.Append(kLocaleFolder);
-
-  // Not all folders under _locales have to be valid locales.
-  base::FileEnumerator locales(locales_path, false,
-                               base::FileEnumerator::DIRECTORIES);
-
-  std::set<std::string> all_locales;
-  extension_l10n_util::GetAllLocales(&all_locales);
-  base::FilePath locale_path;
-  while (!(locale_path = locales.Next()).empty()) {
-    if (extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
-                                                  all_locales))
-      continue;
-
-    base::FilePath messages_path = locale_path.Append(kMessagesFilename);
-
-    if (!ReadMessageCatalog(messages_path))
-      return false;
-  }
-
-  return true;
-}
-
 bool Unpacker::Run() {
   // Parse the manifest.
   std::string error;
@@ -171,15 +135,7 @@
   }
   extension->AddInstallWarnings(warnings);
 
-  // Parse all message catalogs (if any).
-  parsed_catalogs_.reset(new base::DictionaryValue);
-  if (!LocaleInfo::GetDefaultLocale(extension.get()).empty()) {
-    if (!ReadAllMessageCatalogs())
-      return false;  // Error was already reported.
-  }
-
-  return ReadJSONRulesetIfNeeded(extension.get()) &&
-         DumpMessageCatalogsToFile();
+  return ReadJSONRulesetIfNeeded(extension.get());
 }
 
 bool Unpacker::ReadJSONRulesetIfNeeded(const Extension* extension) {
@@ -206,55 +162,6 @@
   return true;
 }
 
-bool Unpacker::DumpMessageCatalogsToFile() {
-  IPC::Message pickle;
-  IPC::WriteParam(&pickle, *parsed_catalogs_.get());
-
-  base::FilePath path =
-      working_dir_.AppendASCII(kDecodedMessageCatalogsFilename);
-  if (!WritePickle(pickle, path)) {
-    SetError("Could not write message catalogs to disk.");
-    return false;
-  }
-
-  return true;
-}
-
-bool Unpacker::ReadMessageCatalog(const base::FilePath& message_path) {
-  std::string error;
-  JSONFileValueDeserializer deserializer(message_path);
-  std::unique_ptr<base::DictionaryValue> root =
-      base::DictionaryValue::From(deserializer.Deserialize(NULL, &error));
-  if (!root.get()) {
-    base::string16 messages_file = message_path.LossyDisplayName();
-    if (error.empty()) {
-      // If file is missing, Deserialize will fail with empty error.
-      SetError(base::StringPrintf("%s %s", errors::kLocalesMessagesFileMissing,
-                                  base::UTF16ToUTF8(messages_file).c_str()));
-    } else {
-      SetError(base::StringPrintf(
-          "%s: %s", base::UTF16ToUTF8(messages_file).c_str(), error.c_str()));
-    }
-    return false;
-  }
-
-  base::FilePath relative_path;
-  // message_path was created from temp_install_dir. This should never fail.
-  if (!extension_dir_.AppendRelativePath(message_path, &relative_path)) {
-    NOTREACHED();
-    return false;
-  }
-
-  std::string dir_name = relative_path.DirName().MaybeAsASCII();
-  if (dir_name.empty()) {
-    NOTREACHED();
-    return false;
-  }
-  parsed_catalogs_->Set(dir_name, std::move(root));
-
-  return true;
-}
-
 void Unpacker::SetError(const std::string& error) {
   SetUTF16Error(base::UTF8ToUTF16(error));
 }
diff --git a/extensions/utility/unpacker.h b/extensions/utility/unpacker.h
index 4473110f..b009d8a7 100644
--- a/extensions/utility/unpacker.h
+++ b/extensions/utility/unpacker.h
@@ -52,7 +52,6 @@
 
   const base::string16& error_message() { return error_message_; }
   base::DictionaryValue* parsed_manifest() { return parsed_manifest_.get(); }
-  base::DictionaryValue* parsed_catalogs() { return parsed_catalogs_.get(); }
 
   std::unique_ptr<base::DictionaryValue> TakeParsedManifest() {
     return std::move(parsed_manifest_);
@@ -110,10 +109,6 @@
   // extension did not provide one.
   std::unique_ptr<base::ListValue> parsed_json_ruleset_;
 
-  // Dictionary of relative paths and catalogs per path. Paths are in the form
-  // of _locales/locale, without messages.json base part.
-  std::unique_ptr<base::DictionaryValue> parsed_catalogs_;
-
   // The last error message that was set.  Empty if there were no errors.
   base::string16 error_message_;
 
diff --git a/extensions/utility/unpacker_unittest.cc b/extensions/utility/unpacker_unittest.cc
index fdd085e..938a8ff 100644
--- a/extensions/utility/unpacker_unittest.cc
+++ b/extensions/utility/unpacker_unittest.cc
@@ -84,16 +84,6 @@
             unpacker_->error_message());
 }
 
-TEST_F(UnpackerTest, InvalidMessagesFile) {
-  SetupUnpacker("invalid_messages_file.crx");
-  EXPECT_FALSE(unpacker_->Run());
-  EXPECT_TRUE(base::MatchPattern(
-      unpacker_->error_message(),
-      ASCIIToUTF16("*_locales?en_US?messages.json: Line: 2, column: 10,"
-                   " Syntax error.")))
-      << unpacker_->error_message();
-}
-
 TEST_F(UnpackerTest, MissingDefaultData) {
   SetupUnpacker("missing_default_data.crx");
   EXPECT_FALSE(unpacker_->Run());
@@ -127,20 +117,6 @@
             unpacker_->error_message());
 }
 
-TEST_F(UnpackerTest, GoodL10n) {
-  SetupUnpacker("good_l10n.crx");
-  EXPECT_TRUE(unpacker_->Run());
-  EXPECT_TRUE(unpacker_->error_message().empty());
-  ASSERT_EQ(2U, unpacker_->parsed_catalogs()->size());
-}
-
-TEST_F(UnpackerTest, NoL10n) {
-  SetupUnpacker("no_l10n.crx");
-  EXPECT_TRUE(unpacker_->Run());
-  EXPECT_TRUE(unpacker_->error_message().empty());
-  EXPECT_EQ(0U, unpacker_->parsed_catalogs()->size());
-}
-
 struct UnzipFileFilterTestCase {
   const base::FilePath::CharType* input;
   const bool should_unzip;
diff --git a/google_apis/gcm/engine/gcm_request_test_base.h b/google_apis/gcm/engine/gcm_request_test_base.h
index 3eb384d..b0a1b5b3 100644
--- a/google_apis/gcm/engine/gcm_request_test_base.h
+++ b/google_apis/gcm/engine/gcm_request_test_base.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef GOOGLE_APIS_GCM_ENGINE_GCM_REQUEST_TEST_BASE_H_
+#define GOOGLE_APIS_GCM_ENGINE_GCM_REQUEST_TEST_BASE_H_
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/test/test_mock_time_task_runner.h"
@@ -58,3 +61,5 @@
 };
 
 }  // namespace gcm
+
+#endif  // GOOGLE_APIS_GCM_ENGINE_GCM_REQUEST_TEST_BASE_H_
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index a0de859..fbd3b2a 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -288,6 +288,8 @@
     "command_buffer/common/gles2_cmd_utils_unittest.cc",
     "command_buffer/common/id_allocator_test.cc",
     "command_buffer/common/id_type_unittest.cc",
+    "command_buffer/common/raster_cmd_format_test.cc",
+    "command_buffer/common/raster_cmd_format_test_autogen.h",
     "command_buffer/common/unittest_main.cc",
     "command_buffer/service/buffer_manager_unittest.cc",
     "command_buffer/service/client_service_map_unittest.cc",
diff --git a/gpu/command_buffer/build_cmd_buffer_lib.py b/gpu/command_buffer/build_cmd_buffer_lib.py
index dd65091..0d922ad 100644
--- a/gpu/command_buffer/build_cmd_buffer_lib.py
+++ b/gpu/command_buffer/build_cmd_buffer_lib.py
@@ -13,14 +13,14 @@
 _SIZE_OF_COMMAND_HEADER = 4
 _FIRST_SPECIFIC_COMMAND_ID = 256
 
-_LICENSE = """// Copyright 2014 The Chromium Authors. All rights reserved.
+_LICENSE = """// Copyright %s 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.
 
 """
 
 _DO_NOT_EDIT_WARNING = """// This file is auto-generated from
-// gpu/command_buffer/build_gles2_cmd_buffer.py
+// gpu/command_buffer/build_%s_cmd_buffer.py
 // It's formatted by clang-format using chromium coding style:
 //    clang-format -i -style=chromium filename
 // DO NOT EDIT!
@@ -93,6 +93,36 @@
 ]
 
 
+_prefix = None
+_upper_prefix = None
+_lower_prefix = None
+def InitializePrefix(mixed_case_prefix):
+  """Initialize prefix used for autogenerated code.
+
+  Must be called before autogenerating code. Prefixes are used by autogenerated
+  code in many places: class names, filenames, namespaces, constants,
+  defines. Given a single mixed case prefix suitable for a class name, we also
+  initialize lower and upper case prefixes for other uses (e.g. filenames and
+  #defines).
+  """
+  global _prefix
+  if _prefix:
+    raise AssertionError
+  _prefix = mixed_case_prefix
+
+  global _upper_prefix
+  _upper_prefix = mixed_case_prefix.upper()
+
+  global _lower_prefix
+  _lower_prefix = mixed_case_prefix.lower()
+
+
+def _Namespace():
+  if _lower_prefix != 'gles2':
+    return 'gles2::'
+  return ''
+
+
 def Grouper(n, iterable, fillvalue=None):
   """Collect data into fixed-length chunks or blocks"""
   args = [iter(iterable)] * n
@@ -229,10 +259,10 @@
       myfile.write("hello")
       # type(myfile) == file
   """
-  def __init__(self, filename):
+  def __init__(self, filename, year):
     self.filename = filename
     self._file = open(filename, 'wb')
-    self._ENTER_MSG = _LICENSE + _DO_NOT_EDIT_WARNING
+    self._ENTER_MSG = _LICENSE % year + _DO_NOT_EDIT_WARNING % _lower_prefix
     self._EXIT_MSG = ""
 
   def __enter__(self):
@@ -251,8 +281,8 @@
   around it. If `file_comment` is set, it will write that before the #ifdef
   guard.
   """
-  def __init__(self, filename, file_comment=None):
-    super(CHeaderWriter, self).__init__(filename)
+  def __init__(self, filename, year, file_comment=None):
+    super(CHeaderWriter, self).__init__(filename, year)
     guard = self._get_guard()
     if file_comment is None:
       file_comment = ""
@@ -387,7 +417,7 @@
 
   def WriteFormatTest(self, func, f):
     """Writes a format test for a command."""
-    f.write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+    f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name))
     f.write("  cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
                (func.name, func.name))
     f.write("  void* next_cmd = cmd.Set(\n")
@@ -1767,7 +1797,7 @@
 
   def WriteImmediateFormatTest(self, func, f):
     """Overrriden from TypeHandler."""
-    f.write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+    f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name))
     f.write("  static GLuint ids[] = { 12, 23, 34, };\n")
     f.write("  cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
                (func.name, func.name))
@@ -2193,7 +2223,7 @@
 
   def WriteImmediateFormatTest(self, func, f):
     """Overrriden from TypeHandler."""
-    f.write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+    f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name))
     f.write("  static GLuint ids[] = { 12, 23, 34, };\n")
     f.write("  cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
                (func.name, func.name))
@@ -2825,7 +2855,7 @@
 
   def WriteImmediateFormatTest(self, func, f):
     """Overrriden from TypeHandler."""
-    f.write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+    f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name))
     f.write("  const int kSomeBaseValueToTestWith = 51;\n")
     f.write("  static %s data[] = {\n" % self.GetArrayType(func))
     for v in range(0, self.GetArrayCount(func)):
@@ -3162,7 +3192,7 @@
     for arg in args:
       if arg.name == "count":
         count_param = int(arg.GetValidClientSideCmdArg(func))
-    f.write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+    f.write("TEST_F(%sFormatTest, %s) {\n" % (_prefix, func.name))
     f.write("  const int kSomeBaseValueToTestWith = 51;\n")
     f.write("  static %s data[] = {\n" % self.GetArrayType(func))
     for v in range(0, self.GetArrayCount(func) * count_param):
@@ -3655,7 +3685,7 @@
       check_code.append("  EXPECT_EQ(static_cast<%s>(%d), cmd.%s);" %
                         (arg.type, value + 11, arg.name))
     code = """
-TEST_F(GLES2FormatTest, %(func_name)s) {
+TEST_F(%(prefix)sFormatTest, %(func_name)s) {
   cmds::%(func_name)s& cmd = *GetBufferAs<cmds::%(func_name)s>();
   static const char* const test_str = \"test string\";
   void* next_cmd = cmd.Set(
@@ -3682,6 +3712,7 @@
 
 """
     f.write(code % {
+          'prefix': _prefix,
           'func_name': func.name,
           'init_code': "\n".join(init_code),
           'check_code': "\n".join(check_code),
@@ -4821,7 +4852,7 @@
     """Writes specialized accessor for compound members."""
     f.write("  %s %s() const volatile {\n" % (self.type, self.name))
     f.write("    return static_cast<%s>(\n" % self.type)
-    f.write("        GLES2Util::MapTwoUint32ToUint64(\n")
+    f.write("        %sGLES2Util::MapTwoUint32ToUint64(\n" % _Namespace())
     f.write("            %s_0,\n" % self.name)
     f.write("            %s_1));\n" % self.name)
     f.write("  }\n")
@@ -4833,8 +4864,8 @@
 
   def WriteSetCode(self, f, indent, var):
     indent_str = ' ' * indent
-    f.write("%sGLES2Util::MapUint64ToTwoUint32(static_cast<uint64_t>(%s),\n" %
-            (indent_str, var))
+    f.write("%s%sGLES2Util::MapUint64ToTwoUint32(static_cast<uint64_t>(%s),\n" %
+            (indent_str, _Namespace(), var))
     f.write("%s                                &%s_0,\n" %
             (indent_str, self.name))
     f.write("%s                                &%s_1);\n" %
@@ -5525,11 +5556,12 @@
   _comment_re = re.compile(r'^//.*$')
   _function_re = re.compile(r'^GL_APICALL(.*?)GL_APIENTRY (.*?) \((.*?)\);$')
 
-  def __init__(self, verbose, function_info, named_type_info, state_info,
-               capability_flags):
+  def __init__(self, verbose, year, function_info, named_type_info,
+               state_info, capability_flags):
     self.original_functions = []
     self.functions = []
     self.verbose = verbose
+    self.year = year
     self.errors = 0
     self.pepper_interfaces = []
     self.interface_info = {}
@@ -5659,8 +5691,8 @@
 
   def WriteCommandIds(self, filename):
     """Writes the command buffer format"""
-    with CHeaderWriter(filename) as f:
-      f.write("#define GLES2_COMMAND_LIST(OP) \\\n")
+    with CHeaderWriter(filename, self.year) as f:
+      f.write("#define %s_COMMAND_LIST(OP) \\\n" % _upper_prefix)
       cmd_id = 256
       for func in self.functions:
         f.write("  %-60s /* %d */ \\\n" %
@@ -5670,26 +5702,27 @@
 
       f.write("enum CommandId {\n")
       f.write("  kOneBeforeStartPoint = cmd::kLastCommonId,  "
-                 "// All GLES2 commands start after this.\n")
-      f.write("#define GLES2_CMD_OP(name) k ## name,\n")
-      f.write("  GLES2_COMMAND_LIST(GLES2_CMD_OP)\n")
-      f.write("#undef GLES2_CMD_OP\n")
+                 "// All %s commands start after this.\n" % _prefix)
+      f.write("#define %s_CMD_OP(name) k ## name,\n" % _upper_prefix)
+      f.write("  %s_COMMAND_LIST(%s_CMD_OP)\n" %
+              (_upper_prefix, _upper_prefix))
+      f.write("#undef %s_CMD_OP\n" % _upper_prefix)
       f.write("  kNumCommands,\n")
-      f.write("  kFirstGLES2Command = kOneBeforeStartPoint + 1\n")
+      f.write("  kFirst%sCommand = kOneBeforeStartPoint + 1\n" % _prefix)
       f.write("};\n")
       f.write("\n")
     self.generated_cpp_filenames.append(filename)
 
   def WriteFormat(self, filename):
     """Writes the command buffer format"""
-    with CHeaderWriter(filename) as f:
+    with CHeaderWriter(filename, self.year) as f:
       # Forward declaration of a few enums used in constant argument
       # to avoid including GL header files.
-      enum_defines = {
-          'GL_SCANOUT_CHROMIUM': '0x6000',
-          'GL_SYNC_GPU_COMMANDS_COMPLETE': '0x9117',
-          'GL_SYNC_FLUSH_COMMANDS_BIT': '0x00000001',
-        }
+      enum_defines = {'GL_SCANOUT_CHROMIUM': '0x6000'}
+      if 'FenceSync' in self.function_info:
+        enum_defines['GL_SYNC_GPU_COMMANDS_COMPLETE'] = '0x9117'
+      if 'ClientWaitSync' in self.function_info:
+        enum_defines['GL_SYNC_FLUSH_COMMANDS_BIT'] = '0x00000001'
       f.write('\n')
       for enum in enum_defines:
         f.write("#define %s %s\n" % (enum, enum_defines[enum]))
@@ -5701,7 +5734,7 @@
 
   def WriteDocs(self, filename):
     """Writes the command buffer doc version of the commands"""
-    with CHeaderWriter(filename) as f:
+    with CHeaderWriter(filename, self.year) as f:
       for func in self.functions:
         func.WriteDocs(f)
       f.write("\n")
@@ -5709,16 +5742,17 @@
 
   def WriteFormatTest(self, filename):
     """Writes the command buffer format test."""
-    comment = ("// This file contains unit tests for gles2 commmands\n"
-               "// It is included by gles2_cmd_format_test.cc\n\n")
-    with CHeaderWriter(filename, comment) as f:
+    comment = ("// This file contains unit tests for %s commmands\n"
+               "// It is included by %s_cmd_format_test.cc\n\n" %
+               (_lower_prefix, _lower_prefix))
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.functions:
         func.WriteFormatTest(f)
     self.generated_cpp_filenames.append(filename)
 
   def WriteCmdHelperHeader(self, filename):
     """Writes the gles2 command helper."""
-    with CHeaderWriter(filename) as f:
+    with CHeaderWriter(filename, self.year) as f:
       for func in self.functions:
         func.WriteCmdHelper(f)
     self.generated_cpp_filenames.append(filename)
@@ -5726,7 +5760,7 @@
   def WriteServiceContextStateHeader(self, filename):
     """Writes the service context state header."""
     comment = "// It is included by context_state.h\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       f.write("struct EnableFlags {\n")
       f.write("  EnableFlags();\n")
       for capability in self.capability_flags:
@@ -5783,7 +5817,7 @@
   def WriteClientContextStateHeader(self, filename):
     """Writes the client context state header."""
     comment = "// It is included by client_context_state.h\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       f.write("struct EnableFlags {\n")
       f.write("  EnableFlags();\n")
       for capability in self.capability_flags:
@@ -5855,7 +5889,7 @@
   def WriteServiceContextStateImpl(self, filename):
     """Writes the context state service implementation."""
     comment = "// It is included by context_state.cc\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       code = []
       for capability in self.capability_flags:
         code.append("%s(%s)" %
@@ -6029,7 +6063,7 @@
   def WriteClientContextStateImpl(self, filename):
     """Writes the context state client side implementation."""
     comment = "// It is included by client_context_state.cc\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       code = []
       for capability in self.capability_flags:
         if 'extension_flag' in capability:
@@ -6083,7 +6117,7 @@
   def WriteServiceImplementation(self, filename):
     """Writes the service decorder implementation."""
     comment = "// It is included by gles2_cmd_decoder.cc\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.functions:
         func.WriteServiceImplementation(f)
 
@@ -6123,7 +6157,7 @@
 
   def WritePassthroughServiceImplementation(self, filename):
     """Writes the passthrough service decorder implementation."""
-    with CWriter(filename) as f:
+    with CWriter(filename, self.year) as f:
       header = """
 #include \"gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h\"
 
@@ -6154,7 +6188,7 @@
       filename = filename_pattern % count
       comment = "// It is included by gles2_cmd_decoder_unittest_%d.cc\n" \
                 % count
-      with CHeaderWriter(filename, comment) as f:
+      with CHeaderWriter(filename, self.year, comment) as f:
         end = test_num + FUNCTIONS_PER_FILE
         if end > num_tests:
           end = num_tests
@@ -6178,7 +6212,7 @@
 
     comment = "// It is included by gles2_cmd_decoder_unittest_base.cc\n"
     filename = filename_pattern % 0
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       f.write(
 """void GLES2DecoderTestBase::SetupInitCapabilitiesExpectations(
       bool es3_capable) {""")
@@ -6283,7 +6317,7 @@
     """
     functions = [f for f in self.functions if f.GetInfo('extension_flag')]
     comment = "// It is included by gles2_cmd_decoder_unittest_extensions.cc\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in functions:
         if True:
           if func.GetInfo('unit_test') != False:
@@ -6300,7 +6334,7 @@
   def WriteGLES2Header(self, filename):
     """Writes the GLES2 header."""
     comment = "// This file contains Chromium-specific GLES2 declarations.\n\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2Header(f)
       f.write("\n")
@@ -6309,7 +6343,7 @@
   def WriteGLES2CLibImplementation(self, filename):
     """Writes the GLES2 c lib implementation."""
     comment = "// These functions emulate GLES2 over command buffers.\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2CLibImplementation(f)
       f.write("""
@@ -6332,7 +6366,7 @@
     """Writes the GLES2 interface header."""
     comment = ("// This file is included by gles2_interface.h to declare the\n"
                "// GL api functions.\n")
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2InterfaceHeader(f)
     self.generated_cpp_filenames.append(filename)
@@ -6340,7 +6374,7 @@
   def WriteGLES2InterfaceStub(self, filename):
     """Writes the GLES2 interface stub header."""
     comment = "// This file is included by gles2_interface_stub.h.\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2InterfaceStub(f)
     self.generated_cpp_filenames.append(filename)
@@ -6348,7 +6382,7 @@
   def WriteGLES2InterfaceStubImpl(self, filename):
     """Writes the GLES2 interface header."""
     comment = "// This file is included by gles2_interface_stub.cc.\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2InterfaceStubImpl(f)
     self.generated_cpp_filenames.append(filename)
@@ -6358,7 +6392,7 @@
     comment = \
       ("// This file is included by gles2_implementation.h to declare the\n"
        "// GL api functions.\n")
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2ImplementationHeader(f)
     self.generated_cpp_filenames.append(filename)
@@ -6368,7 +6402,7 @@
     comment = \
       ("// This file is included by gles2_implementation.cc to define the\n"
        "// GL api functions.\n")
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2Implementation(f)
     self.generated_cpp_filenames.append(filename)
@@ -6376,7 +6410,7 @@
   def WriteGLES2TraceImplementationHeader(self, filename):
     """Writes the GLES2 Trace Implementation header."""
     comment = "// This file is included by gles2_trace_implementation.h\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2TraceImplementationHeader(f)
     self.generated_cpp_filenames.append(filename)
@@ -6384,7 +6418,7 @@
   def WriteGLES2TraceImplementation(self, filename):
     """Writes the GLES2 Trace Implementation."""
     comment = "// This file is included by gles2_trace_implementation.cc\n"
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2TraceImplementation(f)
     self.generated_cpp_filenames.append(filename)
@@ -6394,14 +6428,14 @@
     comment = \
       ("// This file is included by gles2_implementation.h to declare the\n"
        "// GL api functions.\n")
-    with CHeaderWriter(filename, comment) as f:
+    with CHeaderWriter(filename, self.year, comment) as f:
       for func in self.original_functions:
         func.WriteGLES2ImplementationUnitTest(f)
     self.generated_cpp_filenames.append(filename)
 
   def WriteServiceUtilsHeader(self, filename):
     """Writes the gles2 auto generated utility header."""
-    with CHeaderWriter(filename) as f:
+    with CHeaderWriter(filename, self.year) as f:
       for name in sorted(self.named_type_info.keys()):
         named_type = NamedType(self.named_type_info[name])
         if not named_type.CreateValidator():
@@ -6429,7 +6463,7 @@
 
   def WriteServiceUtilsImplementation(self, filename):
     """Writes the gles2 auto generated utility implementation."""
-    with CHeaderWriter(filename) as f:
+    with CHeaderWriter(filename, self.year) as f:
       names = sorted(self.named_type_info.keys())
       for name in names:
         named_type = NamedType(self.named_type_info[name])
@@ -6540,7 +6574,7 @@
 
   def WriteCommonUtilsHeader(self, filename):
     """Writes the gles2 common utility header."""
-    with CHeaderWriter(filename) as f:
+    with CHeaderWriter(filename, self.year) as f:
       type_infos = sorted(self.named_type_info.keys())
       for type_info in type_infos:
         if self.named_type_info[type_info]['type'] == 'GLenum':
@@ -6572,25 +6606,25 @@
               self.Error("code collision: %s and %s have the same code %s" %
                          (define_dict[value], name, value))
 
-    with CHeaderWriter(filename) as f:
-      f.write("static const GLES2Util::EnumToString "
-                 "enum_to_string_table[] = {\n")
+    with CHeaderWriter(filename, self.year) as f:
+      f.write("static const %sUtil::EnumToString "
+                 "enum_to_string_table[] = {\n" % _prefix)
       for value in sorted(define_dict):
         f.write('  { %s, "%s", },\n' % (value, define_dict[value]))
       f.write("""};
 
-const GLES2Util::EnumToString* const GLES2Util::enum_to_string_table_ =
+const %(p)sUtil::EnumToString* const %(p)sUtil::enum_to_string_table_ =
     enum_to_string_table;
-const size_t GLES2Util::enum_to_string_table_len_ =
+const size_t %(p)sUtil::enum_to_string_table_len_ =
     sizeof(enum_to_string_table) / sizeof(enum_to_string_table[0]);
 
-""")
+""" % { 'p' : _prefix})
 
       enums = sorted(self.named_type_info.keys())
       for enum in enums:
         if self.named_type_info[enum]['type'] == 'GLenum':
-          f.write("std::string GLES2Util::GetString%s(uint32_t value) {\n" %
-                     enum)
+          f.write("std::string %sUtil::GetString%s(uint32_t value) {\n" %
+                     (_prefix, enum))
           valid_list = self.named_type_info[enum]['valid']
           if 'valid_es3' in self.named_type_info[enum]:
             for es3_enum in self.named_type_info[enum]['valid_es3']:
@@ -6602,22 +6636,22 @@
             for value in valid_list:
               f.write('    { %s, "%s" },\n' % (value, value))
             f.write("""  };
-  return GLES2Util::GetQualifiedEnumString(
+  return %sUtil::GetQualifiedEnumString(
       string_table, arraysize(string_table), value);
 }
 
-""")
+""" % _prefix)
           else:
-            f.write("""  return GLES2Util::GetQualifiedEnumString(
+            f.write("""  return %sUtil::GetQualifiedEnumString(
       NULL, 0, value);
 }
 
-""")
+""" % _prefix)
     self.generated_cpp_filenames.append(filename)
 
   def WritePepperGLES2Interface(self, filename, dev):
     """Writes the Pepper OpenGLES interface definition."""
-    with CWriter(filename) as f:
+    with CWriter(filename, self.year) as f:
       f.write("label Chrome {\n")
       f.write("  M39 = 1.0\n")
       f.write("};\n\n")
@@ -6678,7 +6712,7 @@
 
   def WritePepperGLES2Implementation(self, filename):
     """Writes the Pepper OpenGLES interface implementation."""
-    with CWriter(filename) as f:
+    with CWriter(filename, self.year) as f:
       f.write("#include \"ppapi/shared_impl/ppb_opengles2_shared.h\"\n\n")
       f.write("#include \"base/logging.h\"\n")
       f.write("#include \"gpu/command_buffer/client/gles2_implementation.h\"\n")
@@ -6749,7 +6783,7 @@
 
   def WriteGLES2ToPPAPIBridge(self, filename):
     """Connects GLES2 helper library to PPB_OpenGLES2 interface"""
-    with CWriter(filename) as f:
+    with CWriter(filename, self.year) as f:
       f.write("#ifndef GL_GLEXT_PROTOTYPES\n")
       f.write("#define GL_GLEXT_PROTOTYPES\n")
       f.write("#endif\n")
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index c730653..ab0b7c1 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -4677,9 +4677,10 @@
   # This script lives under gpu/command_buffer, cd to base directory.
   os.chdir(os.path.dirname(__file__) + "/../..")
   base_dir = os.getcwd()
-  gen = build_cmd_buffer_lib.GLGenerator(options.verbose, _FUNCTION_INFO,
-                                         _NAMED_TYPE_INFO, _STATE_INFO,
-                                         _CAPABILITY_FLAGS)
+  build_cmd_buffer_lib.InitializePrefix("GLES2")
+  gen = build_cmd_buffer_lib.GLGenerator(options.verbose, "2014",
+                                         _FUNCTION_INFO, _NAMED_TYPE_INFO,
+                                         _STATE_INFO, _CAPABILITY_FLAGS)
   gen.ParseGLH("gpu/command_buffer/gles2_cmd_buffer_functions.txt")
 
   # Support generating files under gen/
diff --git a/gpu/command_buffer/build_raster_cmd_buffer.py b/gpu/command_buffer/build_raster_cmd_buffer.py
index 94c813d1..288043b 100755
--- a/gpu/command_buffer/build_raster_cmd_buffer.py
+++ b/gpu/command_buffer/build_raster_cmd_buffer.py
@@ -1056,9 +1056,10 @@
   # This script lives under gpu/command_buffer, cd to base directory.
   os.chdir(os.path.dirname(__file__) + "/../..")
   base_dir = os.getcwd()
-  gen = build_cmd_buffer_lib.GLGenerator(options.verbose, _FUNCTION_INFO,
-                                         _NAMED_TYPE_INFO, _STATE_INFO,
-                                         _CAPABILITY_FLAGS)
+  build_cmd_buffer_lib.InitializePrefix("Raster")
+  gen = build_cmd_buffer_lib.GLGenerator(options.verbose, "2018",
+                                         _FUNCTION_INFO, _NAMED_TYPE_INFO,
+                                         _STATE_INFO, _CAPABILITY_FLAGS)
   gen.ParseGLH("gpu/command_buffer/raster_cmd_buffer_functions.txt")
 
   # Support generating files under gen/
@@ -1068,10 +1069,10 @@
   os.chdir(base_dir)
 
   # TODO(backer): Uncomment once the output looks good.
-  # gen.WriteCommandIds("gpu/command_buffer/common/raster_cmd_ids_autogen.h")
-  # gen.WriteFormat("gpu/command_buffer/common/raster_cmd_format_autogen.h")
-  # gen.WriteFormatTest(
-  #   "gpu/command_buffer/common/raster_cmd_format_test_autogen.h")
+  gen.WriteCommandIds("gpu/command_buffer/common/raster_cmd_ids_autogen.h")
+  gen.WriteFormat("gpu/command_buffer/common/raster_cmd_format_autogen.h")
+  gen.WriteFormatTest(
+    "gpu/command_buffer/common/raster_cmd_format_test_autogen.h")
   # gen.WriteGLES2InterfaceHeader(
   #   "gpu/command_buffer/client/raster_interface_autogen.h")
   # gen.WriteGLES2InterfaceStub(
@@ -1104,10 +1105,6 @@
   # gen.WriteServiceUtilsImplementation(
   #   "gpu/command_buffer/service/"
   #   "raster_cmd_validation_implementation_autogen.h")
-  # gen.WriteCommonUtilsHeader(
-  #   "gpu/command_buffer/common/raster_cmd_utils_autogen.h")
-  # gen.WriteCommonUtilsImpl(
-  #   "gpu/command_buffer/common/raster_cmd_utils_implementation_autogen.h")
 
   build_cmd_buffer_lib.Format(gen.generated_cpp_filenames)
 
diff --git a/gpu/command_buffer/client/client_discardable_texture_manager.cc b/gpu/command_buffer/client/client_discardable_texture_manager.cc
index 3446b3cf..cc336a5 100644
--- a/gpu/command_buffer/client/client_discardable_texture_manager.cc
+++ b/gpu/command_buffer/client/client_discardable_texture_manager.cc
@@ -6,6 +6,15 @@
 
 namespace gpu {
 
+ClientDiscardableTextureManager::TextureEntry::TextureEntry(
+    ClientDiscardableHandle::Id id)
+    : id(id) {}
+ClientDiscardableTextureManager::TextureEntry::TextureEntry(
+    const TextureEntry& other) = default;
+ClientDiscardableTextureManager::TextureEntry&
+ClientDiscardableTextureManager::TextureEntry::operator=(
+    const TextureEntry& other) = default;
+
 ClientDiscardableTextureManager::ClientDiscardableTextureManager() = default;
 ClientDiscardableTextureManager::~ClientDiscardableTextureManager() = default;
 
@@ -13,56 +22,73 @@
     CommandBuffer* command_buffer,
     uint32_t texture_id) {
   base::AutoLock hold(lock_);
-  DCHECK(texture_id_to_handle_id_.find(texture_id) ==
-         texture_id_to_handle_id_.end());
+  DCHECK(texture_entries_.find(texture_id) == texture_entries_.end());
   ClientDiscardableHandle::Id handle_id =
       discardable_manager_.CreateHandle(command_buffer);
   if (handle_id.is_null())
     return ClientDiscardableHandle();
 
-  texture_id_to_handle_id_[texture_id] = handle_id;
+  texture_entries_.emplace(texture_id, TextureEntry(handle_id));
   return discardable_manager_.GetHandle(handle_id);
 }
 
 bool ClientDiscardableTextureManager::LockTexture(uint32_t texture_id) {
   base::AutoLock hold(lock_);
-  auto found = texture_id_to_handle_id_.find(texture_id);
-  DCHECK(found != texture_id_to_handle_id_.end());
-  return discardable_manager_.LockHandle(found->second);
+  auto found = texture_entries_.find(texture_id);
+  DCHECK(found != texture_entries_.end());
+  TextureEntry& entry = found->second;
+  if (!discardable_manager_.LockHandle(entry.id)) {
+    DCHECK_EQ(0u, entry.client_lock_count);
+    return false;
+  }
+
+  ++entry.client_lock_count;
+  return true;
+}
+
+void ClientDiscardableTextureManager::UnlockTexture(
+    uint32_t texture_id,
+    bool* should_unbind_texture) {
+  base::AutoLock hold(lock_);
+  auto found = texture_entries_.find(texture_id);
+  DCHECK(found != texture_entries_.end());
+  TextureEntry& entry = found->second;
+  DCHECK_GT(entry.client_lock_count, 0u);
+  --entry.client_lock_count;
+  *should_unbind_texture = (0u == entry.client_lock_count);
 }
 
 void ClientDiscardableTextureManager::FreeTexture(uint32_t texture_id) {
   base::AutoLock hold(lock_);
-  auto found = texture_id_to_handle_id_.find(texture_id);
-  if (found == texture_id_to_handle_id_.end())
+  auto found = texture_entries_.find(texture_id);
+  if (found == texture_entries_.end())
     return;
-  ClientDiscardableHandle::Id discardable_id = found->second;
-  texture_id_to_handle_id_.erase(found);
+  ClientDiscardableHandle::Id discardable_id = found->second.id;
+  texture_entries_.erase(found);
   return discardable_manager_.FreeHandle(discardable_id);
 }
 
 bool ClientDiscardableTextureManager::TextureIsValid(
     uint32_t texture_id) const {
   base::AutoLock hold(lock_);
-  return texture_id_to_handle_id_.find(texture_id) !=
-         texture_id_to_handle_id_.end();
+  return texture_entries_.find(texture_id) != texture_entries_.end();
 }
 
 bool ClientDiscardableTextureManager::TextureIsDeletedForTracing(
     uint32_t texture_id) const {
   base::AutoLock hold(lock_);
-  auto found = texture_id_to_handle_id_.find(texture_id);
-  if (found == texture_id_to_handle_id_.end())
+  auto found = texture_entries_.find(texture_id);
+  if (found == texture_entries_.end())
     return true;
-  return discardable_manager_.HandleIsDeletedForTracing(found->second);
+  return discardable_manager_.HandleIsDeletedForTracing(found->second.id);
 }
 
 ClientDiscardableHandle ClientDiscardableTextureManager::GetHandleForTesting(
     uint32_t texture_id) {
   base::AutoLock hold(lock_);
-  auto found = texture_id_to_handle_id_.find(texture_id);
-  DCHECK(found != texture_id_to_handle_id_.end());
-  return discardable_manager_.GetHandle(found->second);
+  auto found = texture_entries_.find(texture_id);
+  DCHECK(found != texture_entries_.end());
+  return discardable_manager_.GetHandle(found->second.id);
 }
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/client_discardable_texture_manager.h b/gpu/command_buffer/client/client_discardable_texture_manager.h
index b9ba5133..9460bd64 100644
--- a/gpu/command_buffer/client/client_discardable_texture_manager.h
+++ b/gpu/command_buffer/client/client_discardable_texture_manager.h
@@ -27,6 +27,7 @@
   ClientDiscardableHandle InitializeTexture(CommandBuffer* command_buffer,
                                             uint32_t texture_id);
   bool LockTexture(uint32_t texture_id);
+  void UnlockTexture(uint32_t texture_id, bool* should_unbind_texture);
   // Must be called by the GLES2Implementation when a texture is being deleted
   // to allow tracking memory to be reclaimed.
   void FreeTexture(uint32_t texture_id);
@@ -42,9 +43,20 @@
   ClientDiscardableHandle GetHandleForTesting(uint32_t texture_id);
 
  private:
+  struct TextureEntry {
+    TextureEntry(ClientDiscardableHandle::Id id);
+    TextureEntry(const TextureEntry& other);
+    TextureEntry& operator=(const TextureEntry& other);
+
+    ClientDiscardableHandle::Id id;
+    // Tracks the lock count of the given texture. Used to unbind texture
+    // the texture when fully unlocked.
+    uint32_t client_lock_count = 1;
+  };
+
   // Access to other members must always be done with |lock_| held.
   mutable base::Lock lock_;
-  std::map<uint32_t, ClientDiscardableHandle::Id> texture_id_to_handle_id_;
+  std::map<uint32_t, TextureEntry> texture_entries_;
   ClientDiscardableManager discardable_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(ClientDiscardableTextureManager);
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index b46b51f..368a4dc 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -4660,7 +4660,13 @@
   }
   for (GLsizei ii = 0; ii < n; ++ii) {
     share_group_->discardable_texture_manager()->FreeTexture(textures[ii]);
+  }
+  UnbindTexturesHelper(n, textures);
+}
 
+void GLES2Implementation::UnbindTexturesHelper(GLsizei n,
+                                               const GLuint* textures) {
+  for (GLsizei ii = 0; ii < n; ++ii) {
     for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
          ++tt) {
       TextureUnit& unit = texture_units_[tt];
@@ -7147,6 +7153,14 @@
                "Texture ID not initialized");
     return;
   }
+
+  // |should_unbind_texture| will be set to true if the texture has been fully
+  // unlocked. In this case, ensure the texture is unbound.
+  bool should_unbind_texture = false;
+  manager->UnlockTexture(texture_id, &should_unbind_texture);
+  if (should_unbind_texture)
+    UnbindTexturesHelper(1, &texture_id);
+
   helper_->UnlockDiscardableTextureCHROMIUM(texture_id);
 }
 
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 2f59edbe..6f545b7 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -520,6 +520,7 @@
   void DeleteFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
   void DeleteRenderbuffersHelper(GLsizei n, const GLuint* renderbuffers);
   void DeleteTexturesHelper(GLsizei n, const GLuint* textures);
+  void UnbindTexturesHelper(GLsizei n, const GLuint* textures);
   bool DeleteProgramHelper(GLuint program);
   bool DeleteShaderHelper(GLuint shader);
   void DeleteQueriesEXTHelper(GLsizei n, const GLuint* queries);
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index ce0ba6a..ebda88db 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -4596,13 +4596,16 @@
       share_group_->discardable_texture_manager()->TextureIsValid(texture_id));
 }
 
-TEST_F(GLES2ImplementationTest, DiscardableMemoryLockFail) {
+TEST_F(GLES2ImplementationTest, DiscardableTextureLockFail) {
   const GLuint texture_id = 1;
   gl_->InitializeDiscardableTextureCHROMIUM(texture_id);
   EXPECT_TRUE(
       share_group_->discardable_texture_manager()->TextureIsValid(texture_id));
 
-  // Unlock and delete the handle.
+  // Unlock the handle on the client side.
+  gl_->UnlockDiscardableTextureCHROMIUM(texture_id);
+
+  // Unlock and delete the handle on the service side.
   ClientDiscardableHandle client_handle =
       share_group_->discardable_texture_manager()->GetHandleForTesting(
           texture_id);
@@ -4618,7 +4621,7 @@
       share_group_->discardable_texture_manager()->TextureIsValid(texture_id));
 }
 
-TEST_F(GLES2ImplementationTest, DiscardableMemoryDoubleInitError) {
+TEST_F(GLES2ImplementationTest, DiscardableTextureDoubleInitError) {
   const GLuint texture_id = 1;
   gl_->InitializeDiscardableTextureCHROMIUM(texture_id);
   EXPECT_EQ(GL_NO_ERROR, CheckError());
@@ -4626,12 +4629,42 @@
   EXPECT_EQ(GL_INVALID_VALUE, CheckError());
 }
 
-TEST_F(GLES2ImplementationTest, DiscardableMemoryLockError) {
+TEST_F(GLES2ImplementationTest, DiscardableTextureLockError) {
   const GLuint texture_id = 1;
   EXPECT_FALSE(gl_->LockDiscardableTextureCHROMIUM(texture_id));
   EXPECT_EQ(GL_INVALID_VALUE, CheckError());
 }
 
+TEST_F(GLES2ImplementationTest, DiscardableTextureLockCounting) {
+  const GLint texture_id = 1;
+  gl_->InitializeDiscardableTextureCHROMIUM(texture_id);
+  EXPECT_TRUE(
+      share_group_->discardable_texture_manager()->TextureIsValid(texture_id));
+
+  // Bind the texture.
+  gl_->BindTexture(GL_TEXTURE_2D, texture_id);
+  GLint bound_texture_id = 0;
+  gl_->GetIntegerv(GL_TEXTURE_BINDING_2D, &bound_texture_id);
+  EXPECT_EQ(texture_id, bound_texture_id);
+
+  // Lock the texture 3 more times (for 4 locks total).
+  for (int i = 0; i < 3; ++i) {
+    gl_->LockDiscardableTextureCHROMIUM(texture_id);
+  }
+
+  // Unlock 4 times. Only after the last unlock should the texture be unbound.
+  for (int i = 0; i < 4; ++i) {
+    gl_->UnlockDiscardableTextureCHROMIUM(texture_id);
+    bound_texture_id = 0;
+    gl_->GetIntegerv(GL_TEXTURE_BINDING_2D, &bound_texture_id);
+    if (i < 3) {
+      EXPECT_EQ(texture_id, bound_texture_id);
+    } else {
+      EXPECT_EQ(0, bound_texture_id);
+    }
+  }
+}
+
 #include "base/macros.h"
 #include "gpu/command_buffer/client/gles2_implementation_unittest_autogen.h"
 
diff --git a/gpu/command_buffer/common/raster_cmd_format.h b/gpu/command_buffer/common/raster_cmd_format.h
new file mode 100644
index 0000000..b8a7e98
--- /dev/null
+++ b/gpu/command_buffer/common/raster_cmd_format.h
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the raster command buffer commands.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_H_
+#define GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "gpu/command_buffer/common/bitfield_helpers.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/gl2_types.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/common/raster_cmd_ids.h"
+
+namespace gpu {
+namespace raster {
+
+// Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned.
+#pragma pack(push, 4)
+static_assert(GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT == 4,
+              "pragma pack alignment must be equal to "
+              "GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT");
+
+// Used for some glGetXXX commands that return a result through a pointer. We
+// need to know if the command succeeded or not and the size of the result. If
+// the command failed its result size will 0.
+template <typename T>
+struct SizedResult {
+  typedef T Type;
+
+  T* GetData() { return static_cast<T*>(static_cast<void*>(&data)); }
+
+  // Returns the total size in bytes of the SizedResult for a given number of
+  // results including the size field.
+  static size_t ComputeSize(size_t num_results) {
+    return sizeof(T) * num_results + sizeof(uint32_t);  // NOLINT
+  }
+
+  // Returns the maximum number of results for a given buffer size.
+  static uint32_t ComputeMaxResults(size_t size_of_buffer) {
+    return (size_of_buffer >= sizeof(uint32_t))
+               ? ((size_of_buffer - sizeof(uint32_t)) / sizeof(T))
+               : 0;  // NOLINT
+  }
+
+  // Set the size for a given number of results.
+  void SetNumResults(size_t num_results) {
+    size = sizeof(T) * num_results;  // NOLINT
+  }
+
+  // Get the number of elements in the result
+  int32_t GetNumResults() const {
+    return size / sizeof(T);  // NOLINT
+  }
+
+  // Copy the result.
+  void CopyResult(void* dst) const { memcpy(dst, &data, size); }
+
+  uint32_t size;  // in bytes.
+  int32_t data;   // this is just here to get an offset.
+};
+
+static_assert(sizeof(SizedResult<int8_t>) == 8,
+              "size of SizedResult<int8_t> should be 8");
+static_assert(offsetof(SizedResult<int8_t>, size) == 0,
+              "offset of SizedResult<int8_t>.size should be 0");
+static_assert(offsetof(SizedResult<int8_t>, data) == 4,
+              "offset of SizedResult<int8_t>.data should be 4");
+
+namespace cmds {
+
+#include "gpu/command_buffer/common/raster_cmd_format_autogen.h"
+
+#pragma pack(pop)
+
+}  // namespace cmd
+}  // namespace raster
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_H_
diff --git a/gpu/command_buffer/common/raster_cmd_format_autogen.h b/gpu/command_buffer/common/raster_cmd_format_autogen.h
new file mode 100644
index 0000000..81e199a
--- /dev/null
+++ b/gpu/command_buffer/common/raster_cmd_format_autogen.h
@@ -0,0 +1,1848 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_raster_cmd_buffer.py
+// It's formatted by clang-format using chromium coding style:
+//    clang-format -i -style=chromium filename
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_AUTOGEN_H_
+
+#define GL_SCANOUT_CHROMIUM 0x6000
+
+struct ActiveTexture {
+  typedef ActiveTexture ValueType;
+  static const CommandId kCmdId = kActiveTexture;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _texture) {
+    SetHeader();
+    texture = _texture;
+  }
+
+  void* Set(void* cmd, GLenum _texture) {
+    static_cast<ValueType*>(cmd)->Init(_texture);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture;
+};
+
+static_assert(sizeof(ActiveTexture) == 8, "size of ActiveTexture should be 8");
+static_assert(offsetof(ActiveTexture, header) == 0,
+              "offset of ActiveTexture header should be 0");
+static_assert(offsetof(ActiveTexture, texture) == 4,
+              "offset of ActiveTexture texture should be 4");
+
+struct BindTexture {
+  typedef BindTexture ValueType;
+  static const CommandId kCmdId = kBindTexture;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(2);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target, GLuint _texture) {
+    SetHeader();
+    target = _target;
+    texture = _texture;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLuint _texture) {
+    static_cast<ValueType*>(cmd)->Init(_target, _texture);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t texture;
+};
+
+static_assert(sizeof(BindTexture) == 12, "size of BindTexture should be 12");
+static_assert(offsetof(BindTexture, header) == 0,
+              "offset of BindTexture header should be 0");
+static_assert(offsetof(BindTexture, target) == 4,
+              "offset of BindTexture target should be 4");
+static_assert(offsetof(BindTexture, texture) == 8,
+              "offset of BindTexture texture should be 8");
+
+struct CompressedTexImage2DBucket {
+  typedef CompressedTexImage2DBucket ValueType;
+  static const CommandId kCmdId = kCompressedTexImage2DBucket;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLint _level,
+            GLenum _internalformat,
+            GLsizei _width,
+            GLsizei _height,
+            GLuint _bucket_id) {
+    SetHeader();
+    target = _target;
+    level = _level;
+    internalformat = _internalformat;
+    width = _width;
+    height = _height;
+    bucket_id = _bucket_id;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLint _level,
+            GLenum _internalformat,
+            GLsizei _width,
+            GLsizei _height,
+            GLuint _bucket_id) {
+    static_cast<ValueType*>(cmd)->Init(_target, _level, _internalformat, _width,
+                                       _height, _bucket_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t level;
+  uint32_t internalformat;
+  int32_t width;
+  int32_t height;
+  uint32_t bucket_id;
+  static const int32_t border = 0;
+};
+
+static_assert(sizeof(CompressedTexImage2DBucket) == 28,
+              "size of CompressedTexImage2DBucket should be 28");
+static_assert(offsetof(CompressedTexImage2DBucket, header) == 0,
+              "offset of CompressedTexImage2DBucket header should be 0");
+static_assert(offsetof(CompressedTexImage2DBucket, target) == 4,
+              "offset of CompressedTexImage2DBucket target should be 4");
+static_assert(offsetof(CompressedTexImage2DBucket, level) == 8,
+              "offset of CompressedTexImage2DBucket level should be 8");
+static_assert(
+    offsetof(CompressedTexImage2DBucket, internalformat) == 12,
+    "offset of CompressedTexImage2DBucket internalformat should be 12");
+static_assert(offsetof(CompressedTexImage2DBucket, width) == 16,
+              "offset of CompressedTexImage2DBucket width should be 16");
+static_assert(offsetof(CompressedTexImage2DBucket, height) == 20,
+              "offset of CompressedTexImage2DBucket height should be 20");
+static_assert(offsetof(CompressedTexImage2DBucket, bucket_id) == 24,
+              "offset of CompressedTexImage2DBucket bucket_id should be 24");
+
+struct CompressedTexImage2D {
+  typedef CompressedTexImage2D ValueType;
+  static const CommandId kCmdId = kCompressedTexImage2D;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLint _level,
+            GLenum _internalformat,
+            GLsizei _width,
+            GLsizei _height,
+            GLsizei _imageSize,
+            uint32_t _data_shm_id,
+            uint32_t _data_shm_offset) {
+    SetHeader();
+    target = _target;
+    level = _level;
+    internalformat = _internalformat;
+    width = _width;
+    height = _height;
+    imageSize = _imageSize;
+    data_shm_id = _data_shm_id;
+    data_shm_offset = _data_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLint _level,
+            GLenum _internalformat,
+            GLsizei _width,
+            GLsizei _height,
+            GLsizei _imageSize,
+            uint32_t _data_shm_id,
+            uint32_t _data_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_target, _level, _internalformat, _width,
+                                       _height, _imageSize, _data_shm_id,
+                                       _data_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t level;
+  uint32_t internalformat;
+  int32_t width;
+  int32_t height;
+  int32_t imageSize;
+  uint32_t data_shm_id;
+  uint32_t data_shm_offset;
+  static const int32_t border = 0;
+};
+
+static_assert(sizeof(CompressedTexImage2D) == 36,
+              "size of CompressedTexImage2D should be 36");
+static_assert(offsetof(CompressedTexImage2D, header) == 0,
+              "offset of CompressedTexImage2D header should be 0");
+static_assert(offsetof(CompressedTexImage2D, target) == 4,
+              "offset of CompressedTexImage2D target should be 4");
+static_assert(offsetof(CompressedTexImage2D, level) == 8,
+              "offset of CompressedTexImage2D level should be 8");
+static_assert(offsetof(CompressedTexImage2D, internalformat) == 12,
+              "offset of CompressedTexImage2D internalformat should be 12");
+static_assert(offsetof(CompressedTexImage2D, width) == 16,
+              "offset of CompressedTexImage2D width should be 16");
+static_assert(offsetof(CompressedTexImage2D, height) == 20,
+              "offset of CompressedTexImage2D height should be 20");
+static_assert(offsetof(CompressedTexImage2D, imageSize) == 24,
+              "offset of CompressedTexImage2D imageSize should be 24");
+static_assert(offsetof(CompressedTexImage2D, data_shm_id) == 28,
+              "offset of CompressedTexImage2D data_shm_id should be 28");
+static_assert(offsetof(CompressedTexImage2D, data_shm_offset) == 32,
+              "offset of CompressedTexImage2D data_shm_offset should be 32");
+
+struct DeleteTexturesImmediate {
+  typedef DeleteTexturesImmediate ValueType;
+  static const CommandId kCmdId = kDeleteTexturesImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * _n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(_n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei _n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(_n));
+  }
+
+  void Init(GLsizei _n, const GLuint* _textures) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _textures, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, const GLuint* _textures) {
+    static_cast<ValueType*>(cmd)->Init(_n, _textures);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+static_assert(sizeof(DeleteTexturesImmediate) == 8,
+              "size of DeleteTexturesImmediate should be 8");
+static_assert(offsetof(DeleteTexturesImmediate, header) == 0,
+              "offset of DeleteTexturesImmediate header should be 0");
+static_assert(offsetof(DeleteTexturesImmediate, n) == 4,
+              "offset of DeleteTexturesImmediate n should be 4");
+
+struct Finish {
+  typedef Finish ValueType;
+  static const CommandId kCmdId = kFinish;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+static_assert(sizeof(Finish) == 4, "size of Finish should be 4");
+static_assert(offsetof(Finish, header) == 0,
+              "offset of Finish header should be 0");
+
+struct Flush {
+  typedef Flush ValueType;
+  static const CommandId kCmdId = kFlush;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+static_assert(sizeof(Flush) == 4, "size of Flush should be 4");
+static_assert(offsetof(Flush, header) == 0,
+              "offset of Flush header should be 0");
+
+struct GenTexturesImmediate {
+  typedef GenTexturesImmediate ValueType;
+  static const CommandId kCmdId = kGenTexturesImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * _n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(_n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei _n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(_n));
+  }
+
+  void Init(GLsizei _n, GLuint* _textures) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _textures, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, GLuint* _textures) {
+    static_cast<ValueType*>(cmd)->Init(_n, _textures);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+static_assert(sizeof(GenTexturesImmediate) == 8,
+              "size of GenTexturesImmediate should be 8");
+static_assert(offsetof(GenTexturesImmediate, header) == 0,
+              "offset of GenTexturesImmediate header should be 0");
+static_assert(offsetof(GenTexturesImmediate, n) == 4,
+              "offset of GenTexturesImmediate n should be 4");
+
+struct GetError {
+  typedef GetError ValueType;
+  static const CommandId kCmdId = kGetError;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef GLenum Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(uint32_t _result_shm_id, uint32_t _result_shm_offset) {
+    SetHeader();
+    result_shm_id = _result_shm_id;
+    result_shm_offset = _result_shm_offset;
+  }
+
+  void* Set(void* cmd, uint32_t _result_shm_id, uint32_t _result_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_result_shm_id, _result_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t result_shm_id;
+  uint32_t result_shm_offset;
+};
+
+static_assert(sizeof(GetError) == 12, "size of GetError should be 12");
+static_assert(offsetof(GetError, header) == 0,
+              "offset of GetError header should be 0");
+static_assert(offsetof(GetError, result_shm_id) == 4,
+              "offset of GetError result_shm_id should be 4");
+static_assert(offsetof(GetError, result_shm_offset) == 8,
+              "offset of GetError result_shm_offset should be 8");
+
+struct GetIntegerv {
+  typedef GetIntegerv ValueType;
+  static const CommandId kCmdId = kGetIntegerv;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef SizedResult<GLint> Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    SetHeader();
+    pname = _pname;
+    params_shm_id = _params_shm_id;
+    params_shm_offset = _params_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_pname, _params_shm_id,
+                                       _params_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t pname;
+  uint32_t params_shm_id;
+  uint32_t params_shm_offset;
+};
+
+static_assert(sizeof(GetIntegerv) == 16, "size of GetIntegerv should be 16");
+static_assert(offsetof(GetIntegerv, header) == 0,
+              "offset of GetIntegerv header should be 0");
+static_assert(offsetof(GetIntegerv, pname) == 4,
+              "offset of GetIntegerv pname should be 4");
+static_assert(offsetof(GetIntegerv, params_shm_id) == 8,
+              "offset of GetIntegerv params_shm_id should be 8");
+static_assert(offsetof(GetIntegerv, params_shm_offset) == 12,
+              "offset of GetIntegerv params_shm_offset should be 12");
+
+struct PixelStorei {
+  typedef PixelStorei ValueType;
+  static const CommandId kCmdId = kPixelStorei;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _pname, GLint _param) {
+    SetHeader();
+    pname = _pname;
+    param = _param;
+  }
+
+  void* Set(void* cmd, GLenum _pname, GLint _param) {
+    static_cast<ValueType*>(cmd)->Init(_pname, _param);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t pname;
+  int32_t param;
+};
+
+static_assert(sizeof(PixelStorei) == 12, "size of PixelStorei should be 12");
+static_assert(offsetof(PixelStorei, header) == 0,
+              "offset of PixelStorei header should be 0");
+static_assert(offsetof(PixelStorei, pname) == 4,
+              "offset of PixelStorei pname should be 4");
+static_assert(offsetof(PixelStorei, param) == 8,
+              "offset of PixelStorei param should be 8");
+
+struct TexImage2D {
+  typedef TexImage2D ValueType;
+  static const CommandId kCmdId = kTexImage2D;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(2);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLint _level,
+            GLint _internalformat,
+            GLsizei _width,
+            GLsizei _height,
+            GLenum _format,
+            GLenum _type,
+            uint32_t _pixels_shm_id,
+            uint32_t _pixels_shm_offset) {
+    SetHeader();
+    target = _target;
+    level = _level;
+    internalformat = _internalformat;
+    width = _width;
+    height = _height;
+    format = _format;
+    type = _type;
+    pixels_shm_id = _pixels_shm_id;
+    pixels_shm_offset = _pixels_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLint _level,
+            GLint _internalformat,
+            GLsizei _width,
+            GLsizei _height,
+            GLenum _format,
+            GLenum _type,
+            uint32_t _pixels_shm_id,
+            uint32_t _pixels_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_target, _level, _internalformat, _width,
+                                       _height, _format, _type, _pixels_shm_id,
+                                       _pixels_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t level;
+  int32_t internalformat;
+  int32_t width;
+  int32_t height;
+  uint32_t format;
+  uint32_t type;
+  uint32_t pixels_shm_id;
+  uint32_t pixels_shm_offset;
+  static const int32_t border = 0;
+};
+
+static_assert(sizeof(TexImage2D) == 40, "size of TexImage2D should be 40");
+static_assert(offsetof(TexImage2D, header) == 0,
+              "offset of TexImage2D header should be 0");
+static_assert(offsetof(TexImage2D, target) == 4,
+              "offset of TexImage2D target should be 4");
+static_assert(offsetof(TexImage2D, level) == 8,
+              "offset of TexImage2D level should be 8");
+static_assert(offsetof(TexImage2D, internalformat) == 12,
+              "offset of TexImage2D internalformat should be 12");
+static_assert(offsetof(TexImage2D, width) == 16,
+              "offset of TexImage2D width should be 16");
+static_assert(offsetof(TexImage2D, height) == 20,
+              "offset of TexImage2D height should be 20");
+static_assert(offsetof(TexImage2D, format) == 24,
+              "offset of TexImage2D format should be 24");
+static_assert(offsetof(TexImage2D, type) == 28,
+              "offset of TexImage2D type should be 28");
+static_assert(offsetof(TexImage2D, pixels_shm_id) == 32,
+              "offset of TexImage2D pixels_shm_id should be 32");
+static_assert(offsetof(TexImage2D, pixels_shm_offset) == 36,
+              "offset of TexImage2D pixels_shm_offset should be 36");
+
+struct TexParameteri {
+  typedef TexParameteri ValueType;
+  static const CommandId kCmdId = kTexParameteri;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target, GLenum _pname, GLint _param) {
+    SetHeader();
+    target = _target;
+    pname = _pname;
+    param = _param;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLenum _pname, GLint _param) {
+    static_cast<ValueType*>(cmd)->Init(_target, _pname, _param);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t pname;
+  int32_t param;
+};
+
+static_assert(sizeof(TexParameteri) == 16,
+              "size of TexParameteri should be 16");
+static_assert(offsetof(TexParameteri, header) == 0,
+              "offset of TexParameteri header should be 0");
+static_assert(offsetof(TexParameteri, target) == 4,
+              "offset of TexParameteri target should be 4");
+static_assert(offsetof(TexParameteri, pname) == 8,
+              "offset of TexParameteri pname should be 8");
+static_assert(offsetof(TexParameteri, param) == 12,
+              "offset of TexParameteri param should be 12");
+
+struct TexSubImage2D {
+  typedef TexSubImage2D ValueType;
+  static const CommandId kCmdId = kTexSubImage2D;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(2);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLint _level,
+            GLint _xoffset,
+            GLint _yoffset,
+            GLsizei _width,
+            GLsizei _height,
+            GLenum _format,
+            GLenum _type,
+            uint32_t _pixels_shm_id,
+            uint32_t _pixels_shm_offset,
+            GLboolean _internal) {
+    SetHeader();
+    target = _target;
+    level = _level;
+    xoffset = _xoffset;
+    yoffset = _yoffset;
+    width = _width;
+    height = _height;
+    format = _format;
+    type = _type;
+    pixels_shm_id = _pixels_shm_id;
+    pixels_shm_offset = _pixels_shm_offset;
+    internal = _internal;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLint _level,
+            GLint _xoffset,
+            GLint _yoffset,
+            GLsizei _width,
+            GLsizei _height,
+            GLenum _format,
+            GLenum _type,
+            uint32_t _pixels_shm_id,
+            uint32_t _pixels_shm_offset,
+            GLboolean _internal) {
+    static_cast<ValueType*>(cmd)->Init(
+        _target, _level, _xoffset, _yoffset, _width, _height, _format, _type,
+        _pixels_shm_id, _pixels_shm_offset, _internal);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t level;
+  int32_t xoffset;
+  int32_t yoffset;
+  int32_t width;
+  int32_t height;
+  uint32_t format;
+  uint32_t type;
+  uint32_t pixels_shm_id;
+  uint32_t pixels_shm_offset;
+  uint32_t internal;
+};
+
+static_assert(sizeof(TexSubImage2D) == 48,
+              "size of TexSubImage2D should be 48");
+static_assert(offsetof(TexSubImage2D, header) == 0,
+              "offset of TexSubImage2D header should be 0");
+static_assert(offsetof(TexSubImage2D, target) == 4,
+              "offset of TexSubImage2D target should be 4");
+static_assert(offsetof(TexSubImage2D, level) == 8,
+              "offset of TexSubImage2D level should be 8");
+static_assert(offsetof(TexSubImage2D, xoffset) == 12,
+              "offset of TexSubImage2D xoffset should be 12");
+static_assert(offsetof(TexSubImage2D, yoffset) == 16,
+              "offset of TexSubImage2D yoffset should be 16");
+static_assert(offsetof(TexSubImage2D, width) == 20,
+              "offset of TexSubImage2D width should be 20");
+static_assert(offsetof(TexSubImage2D, height) == 24,
+              "offset of TexSubImage2D height should be 24");
+static_assert(offsetof(TexSubImage2D, format) == 28,
+              "offset of TexSubImage2D format should be 28");
+static_assert(offsetof(TexSubImage2D, type) == 32,
+              "offset of TexSubImage2D type should be 32");
+static_assert(offsetof(TexSubImage2D, pixels_shm_id) == 36,
+              "offset of TexSubImage2D pixels_shm_id should be 36");
+static_assert(offsetof(TexSubImage2D, pixels_shm_offset) == 40,
+              "offset of TexSubImage2D pixels_shm_offset should be 40");
+static_assert(offsetof(TexSubImage2D, internal) == 44,
+              "offset of TexSubImage2D internal should be 44");
+
+struct TexStorage2DEXT {
+  typedef TexStorage2DEXT ValueType;
+  static const CommandId kCmdId = kTexStorage2DEXT;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(2);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLsizei _levels,
+            GLenum _internalFormat,
+            GLsizei _width,
+            GLsizei _height) {
+    SetHeader();
+    target = _target;
+    levels = _levels;
+    internalFormat = _internalFormat;
+    width = _width;
+    height = _height;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLsizei _levels,
+            GLenum _internalFormat,
+            GLsizei _width,
+            GLsizei _height) {
+    static_cast<ValueType*>(cmd)->Init(_target, _levels, _internalFormat,
+                                       _width, _height);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t levels;
+  uint32_t internalFormat;
+  int32_t width;
+  int32_t height;
+};
+
+static_assert(sizeof(TexStorage2DEXT) == 24,
+              "size of TexStorage2DEXT should be 24");
+static_assert(offsetof(TexStorage2DEXT, header) == 0,
+              "offset of TexStorage2DEXT header should be 0");
+static_assert(offsetof(TexStorage2DEXT, target) == 4,
+              "offset of TexStorage2DEXT target should be 4");
+static_assert(offsetof(TexStorage2DEXT, levels) == 8,
+              "offset of TexStorage2DEXT levels should be 8");
+static_assert(offsetof(TexStorage2DEXT, internalFormat) == 12,
+              "offset of TexStorage2DEXT internalFormat should be 12");
+static_assert(offsetof(TexStorage2DEXT, width) == 16,
+              "offset of TexStorage2DEXT width should be 16");
+static_assert(offsetof(TexStorage2DEXT, height) == 20,
+              "offset of TexStorage2DEXT height should be 20");
+
+struct GenQueriesEXTImmediate {
+  typedef GenQueriesEXTImmediate ValueType;
+  static const CommandId kCmdId = kGenQueriesEXTImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * _n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(_n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei _n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(_n));
+  }
+
+  void Init(GLsizei _n, GLuint* _queries) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _queries, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, GLuint* _queries) {
+    static_cast<ValueType*>(cmd)->Init(_n, _queries);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+static_assert(sizeof(GenQueriesEXTImmediate) == 8,
+              "size of GenQueriesEXTImmediate should be 8");
+static_assert(offsetof(GenQueriesEXTImmediate, header) == 0,
+              "offset of GenQueriesEXTImmediate header should be 0");
+static_assert(offsetof(GenQueriesEXTImmediate, n) == 4,
+              "offset of GenQueriesEXTImmediate n should be 4");
+
+struct DeleteQueriesEXTImmediate {
+  typedef DeleteQueriesEXTImmediate ValueType;
+  static const CommandId kCmdId = kDeleteQueriesEXTImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * _n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei _n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(_n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei _n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(_n));
+  }
+
+  void Init(GLsizei _n, const GLuint* _queries) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _queries, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, const GLuint* _queries) {
+    static_cast<ValueType*>(cmd)->Init(_n, _queries);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+static_assert(sizeof(DeleteQueriesEXTImmediate) == 8,
+              "size of DeleteQueriesEXTImmediate should be 8");
+static_assert(offsetof(DeleteQueriesEXTImmediate, header) == 0,
+              "offset of DeleteQueriesEXTImmediate header should be 0");
+static_assert(offsetof(DeleteQueriesEXTImmediate, n) == 4,
+              "offset of DeleteQueriesEXTImmediate n should be 4");
+
+struct BeginQueryEXT {
+  typedef BeginQueryEXT ValueType;
+  static const CommandId kCmdId = kBeginQueryEXT;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLuint _id,
+            uint32_t _sync_data_shm_id,
+            uint32_t _sync_data_shm_offset) {
+    SetHeader();
+    target = _target;
+    id = _id;
+    sync_data_shm_id = _sync_data_shm_id;
+    sync_data_shm_offset = _sync_data_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLuint _id,
+            uint32_t _sync_data_shm_id,
+            uint32_t _sync_data_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_target, _id, _sync_data_shm_id,
+                                       _sync_data_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t id;
+  uint32_t sync_data_shm_id;
+  uint32_t sync_data_shm_offset;
+};
+
+static_assert(sizeof(BeginQueryEXT) == 20,
+              "size of BeginQueryEXT should be 20");
+static_assert(offsetof(BeginQueryEXT, header) == 0,
+              "offset of BeginQueryEXT header should be 0");
+static_assert(offsetof(BeginQueryEXT, target) == 4,
+              "offset of BeginQueryEXT target should be 4");
+static_assert(offsetof(BeginQueryEXT, id) == 8,
+              "offset of BeginQueryEXT id should be 8");
+static_assert(offsetof(BeginQueryEXT, sync_data_shm_id) == 12,
+              "offset of BeginQueryEXT sync_data_shm_id should be 12");
+static_assert(offsetof(BeginQueryEXT, sync_data_shm_offset) == 16,
+              "offset of BeginQueryEXT sync_data_shm_offset should be 16");
+
+struct EndQueryEXT {
+  typedef EndQueryEXT ValueType;
+  static const CommandId kCmdId = kEndQueryEXT;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target, GLuint _submit_count) {
+    SetHeader();
+    target = _target;
+    submit_count = _submit_count;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLuint _submit_count) {
+    static_cast<ValueType*>(cmd)->Init(_target, _submit_count);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t submit_count;
+};
+
+static_assert(sizeof(EndQueryEXT) == 12, "size of EndQueryEXT should be 12");
+static_assert(offsetof(EndQueryEXT, header) == 0,
+              "offset of EndQueryEXT header should be 0");
+static_assert(offsetof(EndQueryEXT, target) == 4,
+              "offset of EndQueryEXT target should be 4");
+static_assert(offsetof(EndQueryEXT, submit_count) == 8,
+              "offset of EndQueryEXT submit_count should be 8");
+
+struct CopySubTextureCHROMIUM {
+  typedef CopySubTextureCHROMIUM ValueType;
+  static const CommandId kCmdId = kCopySubTextureCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(2);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _source_id,
+            GLint _source_level,
+            GLenum _dest_target,
+            GLuint _dest_id,
+            GLint _dest_level,
+            GLint _xoffset,
+            GLint _yoffset,
+            GLint _x,
+            GLint _y,
+            GLsizei _width,
+            GLsizei _height,
+            GLboolean _unpack_flip_y,
+            GLboolean _unpack_premultiply_alpha,
+            GLboolean _unpack_unmultiply_alpha) {
+    SetHeader();
+    source_id = _source_id;
+    source_level = _source_level;
+    dest_target = _dest_target;
+    dest_id = _dest_id;
+    dest_level = _dest_level;
+    xoffset = _xoffset;
+    yoffset = _yoffset;
+    x = _x;
+    y = _y;
+    width = _width;
+    height = _height;
+    unpack_flip_y = _unpack_flip_y;
+    unpack_premultiply_alpha = _unpack_premultiply_alpha;
+    unpack_unmultiply_alpha = _unpack_unmultiply_alpha;
+  }
+
+  void* Set(void* cmd,
+            GLuint _source_id,
+            GLint _source_level,
+            GLenum _dest_target,
+            GLuint _dest_id,
+            GLint _dest_level,
+            GLint _xoffset,
+            GLint _yoffset,
+            GLint _x,
+            GLint _y,
+            GLsizei _width,
+            GLsizei _height,
+            GLboolean _unpack_flip_y,
+            GLboolean _unpack_premultiply_alpha,
+            GLboolean _unpack_unmultiply_alpha) {
+    static_cast<ValueType*>(cmd)->Init(
+        _source_id, _source_level, _dest_target, _dest_id, _dest_level,
+        _xoffset, _yoffset, _x, _y, _width, _height, _unpack_flip_y,
+        _unpack_premultiply_alpha, _unpack_unmultiply_alpha);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t source_id;
+  int32_t source_level;
+  uint32_t dest_target;
+  uint32_t dest_id;
+  int32_t dest_level;
+  int32_t xoffset;
+  int32_t yoffset;
+  int32_t x;
+  int32_t y;
+  int32_t width;
+  int32_t height;
+  uint32_t unpack_flip_y;
+  uint32_t unpack_premultiply_alpha;
+  uint32_t unpack_unmultiply_alpha;
+};
+
+static_assert(sizeof(CopySubTextureCHROMIUM) == 60,
+              "size of CopySubTextureCHROMIUM should be 60");
+static_assert(offsetof(CopySubTextureCHROMIUM, header) == 0,
+              "offset of CopySubTextureCHROMIUM header should be 0");
+static_assert(offsetof(CopySubTextureCHROMIUM, source_id) == 4,
+              "offset of CopySubTextureCHROMIUM source_id should be 4");
+static_assert(offsetof(CopySubTextureCHROMIUM, source_level) == 8,
+              "offset of CopySubTextureCHROMIUM source_level should be 8");
+static_assert(offsetof(CopySubTextureCHROMIUM, dest_target) == 12,
+              "offset of CopySubTextureCHROMIUM dest_target should be 12");
+static_assert(offsetof(CopySubTextureCHROMIUM, dest_id) == 16,
+              "offset of CopySubTextureCHROMIUM dest_id should be 16");
+static_assert(offsetof(CopySubTextureCHROMIUM, dest_level) == 20,
+              "offset of CopySubTextureCHROMIUM dest_level should be 20");
+static_assert(offsetof(CopySubTextureCHROMIUM, xoffset) == 24,
+              "offset of CopySubTextureCHROMIUM xoffset should be 24");
+static_assert(offsetof(CopySubTextureCHROMIUM, yoffset) == 28,
+              "offset of CopySubTextureCHROMIUM yoffset should be 28");
+static_assert(offsetof(CopySubTextureCHROMIUM, x) == 32,
+              "offset of CopySubTextureCHROMIUM x should be 32");
+static_assert(offsetof(CopySubTextureCHROMIUM, y) == 36,
+              "offset of CopySubTextureCHROMIUM y should be 36");
+static_assert(offsetof(CopySubTextureCHROMIUM, width) == 40,
+              "offset of CopySubTextureCHROMIUM width should be 40");
+static_assert(offsetof(CopySubTextureCHROMIUM, height) == 44,
+              "offset of CopySubTextureCHROMIUM height should be 44");
+static_assert(offsetof(CopySubTextureCHROMIUM, unpack_flip_y) == 48,
+              "offset of CopySubTextureCHROMIUM unpack_flip_y should be 48");
+static_assert(
+    offsetof(CopySubTextureCHROMIUM, unpack_premultiply_alpha) == 52,
+    "offset of CopySubTextureCHROMIUM unpack_premultiply_alpha should be 52");
+static_assert(
+    offsetof(CopySubTextureCHROMIUM, unpack_unmultiply_alpha) == 56,
+    "offset of CopySubTextureCHROMIUM unpack_unmultiply_alpha should be 56");
+
+struct CompressedCopyTextureCHROMIUM {
+  typedef CompressedCopyTextureCHROMIUM ValueType;
+  static const CommandId kCmdId = kCompressedCopyTextureCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _source_id, GLuint _dest_id) {
+    SetHeader();
+    source_id = _source_id;
+    dest_id = _dest_id;
+  }
+
+  void* Set(void* cmd, GLuint _source_id, GLuint _dest_id) {
+    static_cast<ValueType*>(cmd)->Init(_source_id, _dest_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t source_id;
+  uint32_t dest_id;
+};
+
+static_assert(sizeof(CompressedCopyTextureCHROMIUM) == 12,
+              "size of CompressedCopyTextureCHROMIUM should be 12");
+static_assert(offsetof(CompressedCopyTextureCHROMIUM, header) == 0,
+              "offset of CompressedCopyTextureCHROMIUM header should be 0");
+static_assert(offsetof(CompressedCopyTextureCHROMIUM, source_id) == 4,
+              "offset of CompressedCopyTextureCHROMIUM source_id should be 4");
+static_assert(offsetof(CompressedCopyTextureCHROMIUM, dest_id) == 8,
+              "offset of CompressedCopyTextureCHROMIUM dest_id should be 8");
+
+struct ProduceTextureDirectCHROMIUMImmediate {
+  typedef ProduceTextureDirectCHROMIUMImmediate ValueType;
+  static const CommandId kCmdId = kProduceTextureDirectCHROMIUMImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);
+
+  static uint32_t ComputeDataSize() {
+    return static_cast<uint32_t>(sizeof(GLbyte) * 16);
+  }
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType) + ComputeDataSize());
+  }
+
+  void SetHeader() { header.SetCmdByTotalSize<ValueType>(ComputeSize()); }
+
+  void Init(GLuint _texture, const GLbyte* _mailbox) {
+    SetHeader();
+    texture = _texture;
+    memcpy(ImmediateDataAddress(this), _mailbox, ComputeDataSize());
+  }
+
+  void* Set(void* cmd, GLuint _texture, const GLbyte* _mailbox) {
+    static_cast<ValueType*>(cmd)->Init(_texture, _mailbox);
+    const uint32_t size = ComputeSize();
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture;
+};
+
+static_assert(sizeof(ProduceTextureDirectCHROMIUMImmediate) == 8,
+              "size of ProduceTextureDirectCHROMIUMImmediate should be 8");
+static_assert(
+    offsetof(ProduceTextureDirectCHROMIUMImmediate, header) == 0,
+    "offset of ProduceTextureDirectCHROMIUMImmediate header should be 0");
+static_assert(
+    offsetof(ProduceTextureDirectCHROMIUMImmediate, texture) == 4,
+    "offset of ProduceTextureDirectCHROMIUMImmediate texture should be 4");
+
+struct BindTexImage2DCHROMIUM {
+  typedef BindTexImage2DCHROMIUM ValueType;
+  static const CommandId kCmdId = kBindTexImage2DCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target, GLint _imageId) {
+    SetHeader();
+    target = _target;
+    imageId = _imageId;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLint _imageId) {
+    static_cast<ValueType*>(cmd)->Init(_target, _imageId);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t imageId;
+};
+
+static_assert(sizeof(BindTexImage2DCHROMIUM) == 12,
+              "size of BindTexImage2DCHROMIUM should be 12");
+static_assert(offsetof(BindTexImage2DCHROMIUM, header) == 0,
+              "offset of BindTexImage2DCHROMIUM header should be 0");
+static_assert(offsetof(BindTexImage2DCHROMIUM, target) == 4,
+              "offset of BindTexImage2DCHROMIUM target should be 4");
+static_assert(offsetof(BindTexImage2DCHROMIUM, imageId) == 8,
+              "offset of BindTexImage2DCHROMIUM imageId should be 8");
+
+struct ReleaseTexImage2DCHROMIUM {
+  typedef ReleaseTexImage2DCHROMIUM ValueType;
+  static const CommandId kCmdId = kReleaseTexImage2DCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target, GLint _imageId) {
+    SetHeader();
+    target = _target;
+    imageId = _imageId;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLint _imageId) {
+    static_cast<ValueType*>(cmd)->Init(_target, _imageId);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  int32_t imageId;
+};
+
+static_assert(sizeof(ReleaseTexImage2DCHROMIUM) == 12,
+              "size of ReleaseTexImage2DCHROMIUM should be 12");
+static_assert(offsetof(ReleaseTexImage2DCHROMIUM, header) == 0,
+              "offset of ReleaseTexImage2DCHROMIUM header should be 0");
+static_assert(offsetof(ReleaseTexImage2DCHROMIUM, target) == 4,
+              "offset of ReleaseTexImage2DCHROMIUM target should be 4");
+static_assert(offsetof(ReleaseTexImage2DCHROMIUM, imageId) == 8,
+              "offset of ReleaseTexImage2DCHROMIUM imageId should be 8");
+
+struct TraceBeginCHROMIUM {
+  typedef TraceBeginCHROMIUM ValueType;
+  static const CommandId kCmdId = kTraceBeginCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _category_bucket_id, GLuint _name_bucket_id) {
+    SetHeader();
+    category_bucket_id = _category_bucket_id;
+    name_bucket_id = _name_bucket_id;
+  }
+
+  void* Set(void* cmd, GLuint _category_bucket_id, GLuint _name_bucket_id) {
+    static_cast<ValueType*>(cmd)->Init(_category_bucket_id, _name_bucket_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t category_bucket_id;
+  uint32_t name_bucket_id;
+};
+
+static_assert(sizeof(TraceBeginCHROMIUM) == 12,
+              "size of TraceBeginCHROMIUM should be 12");
+static_assert(offsetof(TraceBeginCHROMIUM, header) == 0,
+              "offset of TraceBeginCHROMIUM header should be 0");
+static_assert(offsetof(TraceBeginCHROMIUM, category_bucket_id) == 4,
+              "offset of TraceBeginCHROMIUM category_bucket_id should be 4");
+static_assert(offsetof(TraceBeginCHROMIUM, name_bucket_id) == 8,
+              "offset of TraceBeginCHROMIUM name_bucket_id should be 8");
+
+struct TraceEndCHROMIUM {
+  typedef TraceEndCHROMIUM ValueType;
+  static const CommandId kCmdId = kTraceEndCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+static_assert(sizeof(TraceEndCHROMIUM) == 4,
+              "size of TraceEndCHROMIUM should be 4");
+static_assert(offsetof(TraceEndCHROMIUM, header) == 0,
+              "offset of TraceEndCHROMIUM header should be 0");
+
+struct LoseContextCHROMIUM {
+  typedef LoseContextCHROMIUM ValueType;
+  static const CommandId kCmdId = kLoseContextCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(1);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _current, GLenum _other) {
+    SetHeader();
+    current = _current;
+    other = _other;
+  }
+
+  void* Set(void* cmd, GLenum _current, GLenum _other) {
+    static_cast<ValueType*>(cmd)->Init(_current, _other);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t current;
+  uint32_t other;
+};
+
+static_assert(sizeof(LoseContextCHROMIUM) == 12,
+              "size of LoseContextCHROMIUM should be 12");
+static_assert(offsetof(LoseContextCHROMIUM, header) == 0,
+              "offset of LoseContextCHROMIUM header should be 0");
+static_assert(offsetof(LoseContextCHROMIUM, current) == 4,
+              "offset of LoseContextCHROMIUM current should be 4");
+static_assert(offsetof(LoseContextCHROMIUM, other) == 8,
+              "offset of LoseContextCHROMIUM other should be 8");
+
+struct WaitSyncTokenCHROMIUM {
+  typedef WaitSyncTokenCHROMIUM ValueType;
+  static const CommandId kCmdId = kWaitSyncTokenCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLint _namespace_id,
+            GLuint64 _command_buffer_id,
+            GLuint64 _release_count) {
+    SetHeader();
+    namespace_id = _namespace_id;
+    gles2::GLES2Util::MapUint64ToTwoUint32(
+        static_cast<uint64_t>(_command_buffer_id), &command_buffer_id_0,
+        &command_buffer_id_1);
+    gles2::GLES2Util::MapUint64ToTwoUint32(
+        static_cast<uint64_t>(_release_count), &release_count_0,
+        &release_count_1);
+  }
+
+  void* Set(void* cmd,
+            GLint _namespace_id,
+            GLuint64 _command_buffer_id,
+            GLuint64 _release_count) {
+    static_cast<ValueType*>(cmd)->Init(_namespace_id, _command_buffer_id,
+                                       _release_count);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  GLuint64 command_buffer_id() const volatile {
+    return static_cast<GLuint64>(gles2::GLES2Util::MapTwoUint32ToUint64(
+        command_buffer_id_0, command_buffer_id_1));
+  }
+
+  GLuint64 release_count() const volatile {
+    return static_cast<GLuint64>(gles2::GLES2Util::MapTwoUint32ToUint64(
+        release_count_0, release_count_1));
+  }
+
+  gpu::CommandHeader header;
+  int32_t namespace_id;
+  uint32_t command_buffer_id_0;
+  uint32_t command_buffer_id_1;
+  uint32_t release_count_0;
+  uint32_t release_count_1;
+};
+
+static_assert(sizeof(WaitSyncTokenCHROMIUM) == 24,
+              "size of WaitSyncTokenCHROMIUM should be 24");
+static_assert(offsetof(WaitSyncTokenCHROMIUM, header) == 0,
+              "offset of WaitSyncTokenCHROMIUM header should be 0");
+static_assert(offsetof(WaitSyncTokenCHROMIUM, namespace_id) == 4,
+              "offset of WaitSyncTokenCHROMIUM namespace_id should be 4");
+static_assert(
+    offsetof(WaitSyncTokenCHROMIUM, command_buffer_id_0) == 8,
+    "offset of WaitSyncTokenCHROMIUM command_buffer_id_0 should be 8");
+static_assert(
+    offsetof(WaitSyncTokenCHROMIUM, command_buffer_id_1) == 12,
+    "offset of WaitSyncTokenCHROMIUM command_buffer_id_1 should be 12");
+static_assert(offsetof(WaitSyncTokenCHROMIUM, release_count_0) == 16,
+              "offset of WaitSyncTokenCHROMIUM release_count_0 should be 16");
+static_assert(offsetof(WaitSyncTokenCHROMIUM, release_count_1) == 20,
+              "offset of WaitSyncTokenCHROMIUM release_count_1 should be 20");
+
+struct InitializeDiscardableTextureCHROMIUM {
+  typedef InitializeDiscardableTextureCHROMIUM ValueType;
+  static const CommandId kCmdId = kInitializeDiscardableTextureCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _texture_id, uint32_t _shm_id, uint32_t _shm_offset) {
+    SetHeader();
+    texture_id = _texture_id;
+    shm_id = _shm_id;
+    shm_offset = _shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _texture_id,
+            uint32_t _shm_id,
+            uint32_t _shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_texture_id, _shm_id, _shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture_id;
+  uint32_t shm_id;
+  uint32_t shm_offset;
+};
+
+static_assert(sizeof(InitializeDiscardableTextureCHROMIUM) == 16,
+              "size of InitializeDiscardableTextureCHROMIUM should be 16");
+static_assert(
+    offsetof(InitializeDiscardableTextureCHROMIUM, header) == 0,
+    "offset of InitializeDiscardableTextureCHROMIUM header should be 0");
+static_assert(
+    offsetof(InitializeDiscardableTextureCHROMIUM, texture_id) == 4,
+    "offset of InitializeDiscardableTextureCHROMIUM texture_id should be 4");
+static_assert(
+    offsetof(InitializeDiscardableTextureCHROMIUM, shm_id) == 8,
+    "offset of InitializeDiscardableTextureCHROMIUM shm_id should be 8");
+static_assert(
+    offsetof(InitializeDiscardableTextureCHROMIUM, shm_offset) == 12,
+    "offset of InitializeDiscardableTextureCHROMIUM shm_offset should be 12");
+
+struct UnlockDiscardableTextureCHROMIUM {
+  typedef UnlockDiscardableTextureCHROMIUM ValueType;
+  static const CommandId kCmdId = kUnlockDiscardableTextureCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _texture_id) {
+    SetHeader();
+    texture_id = _texture_id;
+  }
+
+  void* Set(void* cmd, GLuint _texture_id) {
+    static_cast<ValueType*>(cmd)->Init(_texture_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture_id;
+};
+
+static_assert(sizeof(UnlockDiscardableTextureCHROMIUM) == 8,
+              "size of UnlockDiscardableTextureCHROMIUM should be 8");
+static_assert(offsetof(UnlockDiscardableTextureCHROMIUM, header) == 0,
+              "offset of UnlockDiscardableTextureCHROMIUM header should be 0");
+static_assert(
+    offsetof(UnlockDiscardableTextureCHROMIUM, texture_id) == 4,
+    "offset of UnlockDiscardableTextureCHROMIUM texture_id should be 4");
+
+struct LockDiscardableTextureCHROMIUM {
+  typedef LockDiscardableTextureCHROMIUM ValueType;
+  static const CommandId kCmdId = kLockDiscardableTextureCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _texture_id) {
+    SetHeader();
+    texture_id = _texture_id;
+  }
+
+  void* Set(void* cmd, GLuint _texture_id) {
+    static_cast<ValueType*>(cmd)->Init(_texture_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture_id;
+};
+
+static_assert(sizeof(LockDiscardableTextureCHROMIUM) == 8,
+              "size of LockDiscardableTextureCHROMIUM should be 8");
+static_assert(offsetof(LockDiscardableTextureCHROMIUM, header) == 0,
+              "offset of LockDiscardableTextureCHROMIUM header should be 0");
+static_assert(
+    offsetof(LockDiscardableTextureCHROMIUM, texture_id) == 4,
+    "offset of LockDiscardableTextureCHROMIUM texture_id should be 4");
+
+struct BeginRasterCHROMIUM {
+  typedef BeginRasterCHROMIUM ValueType;
+  static const CommandId kCmdId = kBeginRasterCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _texture_id,
+            GLuint _sk_color,
+            GLuint _msaa_sample_count,
+            GLboolean _can_use_lcd_text,
+            GLboolean _use_distance_field_text,
+            GLint _pixel_config) {
+    SetHeader();
+    texture_id = _texture_id;
+    sk_color = _sk_color;
+    msaa_sample_count = _msaa_sample_count;
+    can_use_lcd_text = _can_use_lcd_text;
+    use_distance_field_text = _use_distance_field_text;
+    pixel_config = _pixel_config;
+  }
+
+  void* Set(void* cmd,
+            GLuint _texture_id,
+            GLuint _sk_color,
+            GLuint _msaa_sample_count,
+            GLboolean _can_use_lcd_text,
+            GLboolean _use_distance_field_text,
+            GLint _pixel_config) {
+    static_cast<ValueType*>(cmd)->Init(_texture_id, _sk_color,
+                                       _msaa_sample_count, _can_use_lcd_text,
+                                       _use_distance_field_text, _pixel_config);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t texture_id;
+  uint32_t sk_color;
+  uint32_t msaa_sample_count;
+  uint32_t can_use_lcd_text;
+  uint32_t use_distance_field_text;
+  int32_t pixel_config;
+};
+
+static_assert(sizeof(BeginRasterCHROMIUM) == 28,
+              "size of BeginRasterCHROMIUM should be 28");
+static_assert(offsetof(BeginRasterCHROMIUM, header) == 0,
+              "offset of BeginRasterCHROMIUM header should be 0");
+static_assert(offsetof(BeginRasterCHROMIUM, texture_id) == 4,
+              "offset of BeginRasterCHROMIUM texture_id should be 4");
+static_assert(offsetof(BeginRasterCHROMIUM, sk_color) == 8,
+              "offset of BeginRasterCHROMIUM sk_color should be 8");
+static_assert(offsetof(BeginRasterCHROMIUM, msaa_sample_count) == 12,
+              "offset of BeginRasterCHROMIUM msaa_sample_count should be 12");
+static_assert(offsetof(BeginRasterCHROMIUM, can_use_lcd_text) == 16,
+              "offset of BeginRasterCHROMIUM can_use_lcd_text should be 16");
+static_assert(
+    offsetof(BeginRasterCHROMIUM, use_distance_field_text) == 20,
+    "offset of BeginRasterCHROMIUM use_distance_field_text should be 20");
+static_assert(offsetof(BeginRasterCHROMIUM, pixel_config) == 24,
+              "offset of BeginRasterCHROMIUM pixel_config should be 24");
+
+struct RasterCHROMIUM {
+  typedef RasterCHROMIUM ValueType;
+  static const CommandId kCmdId = kRasterCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLsizeiptr _size,
+            uint32_t _list_shm_id,
+            uint32_t _list_shm_offset) {
+    SetHeader();
+    size = _size;
+    list_shm_id = _list_shm_id;
+    list_shm_offset = _list_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLsizeiptr _size,
+            uint32_t _list_shm_id,
+            uint32_t _list_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_size, _list_shm_id, _list_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  int32_t size;
+  uint32_t list_shm_id;
+  uint32_t list_shm_offset;
+};
+
+static_assert(sizeof(RasterCHROMIUM) == 16,
+              "size of RasterCHROMIUM should be 16");
+static_assert(offsetof(RasterCHROMIUM, header) == 0,
+              "offset of RasterCHROMIUM header should be 0");
+static_assert(offsetof(RasterCHROMIUM, size) == 4,
+              "offset of RasterCHROMIUM size should be 4");
+static_assert(offsetof(RasterCHROMIUM, list_shm_id) == 8,
+              "offset of RasterCHROMIUM list_shm_id should be 8");
+static_assert(offsetof(RasterCHROMIUM, list_shm_offset) == 12,
+              "offset of RasterCHROMIUM list_shm_offset should be 12");
+
+struct EndRasterCHROMIUM {
+  typedef EndRasterCHROMIUM ValueType;
+  static const CommandId kCmdId = kEndRasterCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+static_assert(sizeof(EndRasterCHROMIUM) == 4,
+              "size of EndRasterCHROMIUM should be 4");
+static_assert(offsetof(EndRasterCHROMIUM, header) == 0,
+              "offset of EndRasterCHROMIUM header should be 0");
+
+struct CreateTransferCacheEntryINTERNAL {
+  typedef CreateTransferCacheEntryINTERNAL ValueType;
+  static const CommandId kCmdId = kCreateTransferCacheEntryINTERNAL;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _entry_type,
+            GLuint _entry_id,
+            GLuint _handle_shm_id,
+            GLuint _handle_shm_offset,
+            GLuint _data_shm_id,
+            GLuint _data_shm_offset,
+            GLuint _data_size) {
+    SetHeader();
+    entry_type = _entry_type;
+    entry_id = _entry_id;
+    handle_shm_id = _handle_shm_id;
+    handle_shm_offset = _handle_shm_offset;
+    data_shm_id = _data_shm_id;
+    data_shm_offset = _data_shm_offset;
+    data_size = _data_size;
+  }
+
+  void* Set(void* cmd,
+            GLuint _entry_type,
+            GLuint _entry_id,
+            GLuint _handle_shm_id,
+            GLuint _handle_shm_offset,
+            GLuint _data_shm_id,
+            GLuint _data_shm_offset,
+            GLuint _data_size) {
+    static_cast<ValueType*>(cmd)->Init(_entry_type, _entry_id, _handle_shm_id,
+                                       _handle_shm_offset, _data_shm_id,
+                                       _data_shm_offset, _data_size);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t entry_type;
+  uint32_t entry_id;
+  uint32_t handle_shm_id;
+  uint32_t handle_shm_offset;
+  uint32_t data_shm_id;
+  uint32_t data_shm_offset;
+  uint32_t data_size;
+};
+
+static_assert(sizeof(CreateTransferCacheEntryINTERNAL) == 32,
+              "size of CreateTransferCacheEntryINTERNAL should be 32");
+static_assert(offsetof(CreateTransferCacheEntryINTERNAL, header) == 0,
+              "offset of CreateTransferCacheEntryINTERNAL header should be 0");
+static_assert(
+    offsetof(CreateTransferCacheEntryINTERNAL, entry_type) == 4,
+    "offset of CreateTransferCacheEntryINTERNAL entry_type should be 4");
+static_assert(
+    offsetof(CreateTransferCacheEntryINTERNAL, entry_id) == 8,
+    "offset of CreateTransferCacheEntryINTERNAL entry_id should be 8");
+static_assert(
+    offsetof(CreateTransferCacheEntryINTERNAL, handle_shm_id) == 12,
+    "offset of CreateTransferCacheEntryINTERNAL handle_shm_id should be 12");
+static_assert(offsetof(CreateTransferCacheEntryINTERNAL, handle_shm_offset) ==
+                  16,
+              "offset of CreateTransferCacheEntryINTERNAL handle_shm_offset "
+              "should be 16");
+static_assert(
+    offsetof(CreateTransferCacheEntryINTERNAL, data_shm_id) == 20,
+    "offset of CreateTransferCacheEntryINTERNAL data_shm_id should be 20");
+static_assert(
+    offsetof(CreateTransferCacheEntryINTERNAL, data_shm_offset) == 24,
+    "offset of CreateTransferCacheEntryINTERNAL data_shm_offset should be 24");
+static_assert(
+    offsetof(CreateTransferCacheEntryINTERNAL, data_size) == 28,
+    "offset of CreateTransferCacheEntryINTERNAL data_size should be 28");
+
+struct DeleteTransferCacheEntryINTERNAL {
+  typedef DeleteTransferCacheEntryINTERNAL ValueType;
+  static const CommandId kCmdId = kDeleteTransferCacheEntryINTERNAL;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _entry_type, GLuint _entry_id) {
+    SetHeader();
+    entry_type = _entry_type;
+    entry_id = _entry_id;
+  }
+
+  void* Set(void* cmd, GLuint _entry_type, GLuint _entry_id) {
+    static_cast<ValueType*>(cmd)->Init(_entry_type, _entry_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t entry_type;
+  uint32_t entry_id;
+};
+
+static_assert(sizeof(DeleteTransferCacheEntryINTERNAL) == 12,
+              "size of DeleteTransferCacheEntryINTERNAL should be 12");
+static_assert(offsetof(DeleteTransferCacheEntryINTERNAL, header) == 0,
+              "offset of DeleteTransferCacheEntryINTERNAL header should be 0");
+static_assert(
+    offsetof(DeleteTransferCacheEntryINTERNAL, entry_type) == 4,
+    "offset of DeleteTransferCacheEntryINTERNAL entry_type should be 4");
+static_assert(
+    offsetof(DeleteTransferCacheEntryINTERNAL, entry_id) == 8,
+    "offset of DeleteTransferCacheEntryINTERNAL entry_id should be 8");
+
+struct UnlockTransferCacheEntryINTERNAL {
+  typedef UnlockTransferCacheEntryINTERNAL ValueType;
+  static const CommandId kCmdId = kUnlockTransferCacheEntryINTERNAL;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _entry_type, GLuint _entry_id) {
+    SetHeader();
+    entry_type = _entry_type;
+    entry_id = _entry_id;
+  }
+
+  void* Set(void* cmd, GLuint _entry_type, GLuint _entry_id) {
+    static_cast<ValueType*>(cmd)->Init(_entry_type, _entry_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t entry_type;
+  uint32_t entry_id;
+};
+
+static_assert(sizeof(UnlockTransferCacheEntryINTERNAL) == 12,
+              "size of UnlockTransferCacheEntryINTERNAL should be 12");
+static_assert(offsetof(UnlockTransferCacheEntryINTERNAL, header) == 0,
+              "offset of UnlockTransferCacheEntryINTERNAL header should be 0");
+static_assert(
+    offsetof(UnlockTransferCacheEntryINTERNAL, entry_type) == 4,
+    "offset of UnlockTransferCacheEntryINTERNAL entry_type should be 4");
+static_assert(
+    offsetof(UnlockTransferCacheEntryINTERNAL, entry_id) == 8,
+    "offset of UnlockTransferCacheEntryINTERNAL entry_id should be 8");
+
+struct TexStorage2DImageCHROMIUM {
+  typedef TexStorage2DImageCHROMIUM ValueType;
+  static const CommandId kCmdId = kTexStorage2DImageCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target,
+            GLenum _internalFormat,
+            GLsizei _width,
+            GLsizei _height) {
+    SetHeader();
+    target = _target;
+    internalFormat = _internalFormat;
+    width = _width;
+    height = _height;
+  }
+
+  void* Set(void* cmd,
+            GLenum _target,
+            GLenum _internalFormat,
+            GLsizei _width,
+            GLsizei _height) {
+    static_cast<ValueType*>(cmd)->Init(_target, _internalFormat, _width,
+                                       _height);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t internalFormat;
+  int32_t width;
+  int32_t height;
+  static const uint32_t bufferUsage = GL_SCANOUT_CHROMIUM;
+};
+
+static_assert(sizeof(TexStorage2DImageCHROMIUM) == 20,
+              "size of TexStorage2DImageCHROMIUM should be 20");
+static_assert(offsetof(TexStorage2DImageCHROMIUM, header) == 0,
+              "offset of TexStorage2DImageCHROMIUM header should be 0");
+static_assert(offsetof(TexStorage2DImageCHROMIUM, target) == 4,
+              "offset of TexStorage2DImageCHROMIUM target should be 4");
+static_assert(offsetof(TexStorage2DImageCHROMIUM, internalFormat) == 8,
+              "offset of TexStorage2DImageCHROMIUM internalFormat should be 8");
+static_assert(offsetof(TexStorage2DImageCHROMIUM, width) == 12,
+              "offset of TexStorage2DImageCHROMIUM width should be 12");
+static_assert(offsetof(TexStorage2DImageCHROMIUM, height) == 16,
+              "offset of TexStorage2DImageCHROMIUM height should be 16");
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/raster_cmd_format_test.cc b/gpu/command_buffer/common/raster_cmd_format_test.cc
new file mode 100644
index 0000000..fa15cc2
--- /dev/null
+++ b/gpu/command_buffer/common/raster_cmd_format_test.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for raster commmands
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "gpu/command_buffer/common/raster_cmd_format.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace raster {
+
+class RasterFormatTest : public testing::Test {
+ protected:
+  static const unsigned char kInitialValue = 0xBD;
+
+  void SetUp() override { memset(buffer_, kInitialValue, sizeof(buffer_)); }
+
+  void TearDown() override {}
+
+  template <typename T>
+  T* GetBufferAs() {
+    return static_cast<T*>(static_cast<void*>(&buffer_));
+  }
+
+  void CheckBytesWritten(const void* end,
+                         size_t expected_size,
+                         size_t written_size) {
+    size_t actual_size = static_cast<const unsigned char*>(end) -
+                         GetBufferAs<const unsigned char>();
+    EXPECT_LT(actual_size, sizeof(buffer_));
+    EXPECT_GT(actual_size, 0u);
+    EXPECT_EQ(expected_size, actual_size);
+    EXPECT_EQ(kInitialValue, buffer_[written_size]);
+    EXPECT_NE(kInitialValue, buffer_[written_size - 1]);
+  }
+
+  void CheckBytesWrittenMatchesExpectedSize(const void* end,
+                                            size_t expected_size) {
+    CheckBytesWritten(end, expected_size, expected_size);
+  }
+
+ private:
+  unsigned char buffer_[1024];
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef _MSC_VER
+const unsigned char RasterFormatTest::kInitialValue;
+#endif
+
+#include "gpu/command_buffer/common/raster_cmd_format_test_autogen.h"
+
+}  // namespace raster
+}  // namespace gpu
diff --git a/gpu/command_buffer/common/raster_cmd_format_test_autogen.h b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
new file mode 100644
index 0000000..4e22c41
--- /dev/null
+++ b/gpu/command_buffer/common/raster_cmd_format_test_autogen.h
@@ -0,0 +1,602 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_raster_cmd_buffer.py
+// It's formatted by clang-format using chromium coding style:
+//    clang-format -i -style=chromium filename
+// DO NOT EDIT!
+
+// This file contains unit tests for raster commmands
+// It is included by raster_cmd_format_test.cc
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_TEST_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_TEST_AUTOGEN_H_
+
+TEST_F(RasterFormatTest, ActiveTexture) {
+  cmds::ActiveTexture& cmd = *GetBufferAs<cmds::ActiveTexture>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::ActiveTexture::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.texture);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, BindTexture) {
+  cmds::BindTexture& cmd = *GetBufferAs<cmds::BindTexture>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BindTexture::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.texture);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, CompressedTexImage2DBucket) {
+  cmds::CompressedTexImage2DBucket& cmd =
+      *GetBufferAs<cmds::CompressedTexImage2DBucket>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLint>(12),
+              static_cast<GLenum>(13), static_cast<GLsizei>(14),
+              static_cast<GLsizei>(15), static_cast<GLuint>(16));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::CompressedTexImage2DBucket::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.internalformat);
+  EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+  EXPECT_EQ(static_cast<GLuint>(16), cmd.bucket_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, CompressedTexImage2D) {
+  cmds::CompressedTexImage2D& cmd = *GetBufferAs<cmds::CompressedTexImage2D>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLint>(12),
+              static_cast<GLenum>(13), static_cast<GLsizei>(14),
+              static_cast<GLsizei>(15), static_cast<GLsizei>(16),
+              static_cast<uint32_t>(17), static_cast<uint32_t>(18));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::CompressedTexImage2D::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.internalformat);
+  EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+  EXPECT_EQ(static_cast<GLsizei>(16), cmd.imageSize);
+  EXPECT_EQ(static_cast<uint32_t>(17), cmd.data_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(18), cmd.data_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, DeleteTexturesImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::DeleteTexturesImmediate& cmd =
+      *GetBufferAs<cmds::DeleteTexturesImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::DeleteTexturesImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  EXPECT_EQ(0, memcmp(ids, ImmediateDataAddress(&cmd), sizeof(ids)));
+}
+
+TEST_F(RasterFormatTest, Finish) {
+  cmds::Finish& cmd = *GetBufferAs<cmds::Finish>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::Finish::kCmdId), cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, Flush) {
+  cmds::Flush& cmd = *GetBufferAs<cmds::Flush>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::Flush::kCmdId), cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, GenTexturesImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::GenTexturesImmediate& cmd = *GetBufferAs<cmds::GenTexturesImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GenTexturesImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  EXPECT_EQ(0, memcmp(ids, ImmediateDataAddress(&cmd), sizeof(ids)));
+}
+
+TEST_F(RasterFormatTest, GetError) {
+  cmds::GetError& cmd = *GetBufferAs<cmds::GetError>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<uint32_t>(11), static_cast<uint32_t>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetError::kCmdId), cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<uint32_t>(11), cmd.result_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.result_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, GetIntegerv) {
+  cmds::GetIntegerv& cmd = *GetBufferAs<cmds::GetIntegerv>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<uint32_t>(12),
+              static_cast<uint32_t>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetIntegerv::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.pname);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.params_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.params_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, PixelStorei) {
+  cmds::PixelStorei& cmd = *GetBufferAs<cmds::PixelStorei>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::PixelStorei::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.pname);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.param);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, TexImage2D) {
+  cmds::TexImage2D& cmd = *GetBufferAs<cmds::TexImage2D>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLint>(12),
+              static_cast<GLint>(13), static_cast<GLsizei>(14),
+              static_cast<GLsizei>(15), static_cast<GLenum>(16),
+              static_cast<GLenum>(17), static_cast<uint32_t>(18),
+              static_cast<uint32_t>(19));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::TexImage2D::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+  EXPECT_EQ(static_cast<GLint>(13), cmd.internalformat);
+  EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+  EXPECT_EQ(static_cast<GLenum>(16), cmd.format);
+  EXPECT_EQ(static_cast<GLenum>(17), cmd.type);
+  EXPECT_EQ(static_cast<uint32_t>(18), cmd.pixels_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(19), cmd.pixels_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, TexParameteri) {
+  cmds::TexParameteri& cmd = *GetBufferAs<cmds::TexParameteri>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11),
+                           static_cast<GLenum>(12), static_cast<GLint>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::TexParameteri::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+  EXPECT_EQ(static_cast<GLint>(13), cmd.param);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, TexSubImage2D) {
+  cmds::TexSubImage2D& cmd = *GetBufferAs<cmds::TexSubImage2D>();
+  void* next_cmd = cmd.Set(
+      &cmd, static_cast<GLenum>(11), static_cast<GLint>(12),
+      static_cast<GLint>(13), static_cast<GLint>(14), static_cast<GLsizei>(15),
+      static_cast<GLsizei>(16), static_cast<GLenum>(17),
+      static_cast<GLenum>(18), static_cast<uint32_t>(19),
+      static_cast<uint32_t>(20), static_cast<GLboolean>(21));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::TexSubImage2D::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+  EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset);
+  EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset);
+  EXPECT_EQ(static_cast<GLsizei>(15), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(16), cmd.height);
+  EXPECT_EQ(static_cast<GLenum>(17), cmd.format);
+  EXPECT_EQ(static_cast<GLenum>(18), cmd.type);
+  EXPECT_EQ(static_cast<uint32_t>(19), cmd.pixels_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(20), cmd.pixels_shm_offset);
+  EXPECT_EQ(static_cast<GLboolean>(21), cmd.internal);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, TexStorage2DEXT) {
+  cmds::TexStorage2DEXT& cmd = *GetBufferAs<cmds::TexStorage2DEXT>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11),
+                           static_cast<GLsizei>(12), static_cast<GLenum>(13),
+                           static_cast<GLsizei>(14), static_cast<GLsizei>(15));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::TexStorage2DEXT::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLsizei>(12), cmd.levels);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.internalFormat);
+  EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, GenQueriesEXTImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::GenQueriesEXTImmediate& cmd =
+      *GetBufferAs<cmds::GenQueriesEXTImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GenQueriesEXTImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  EXPECT_EQ(0, memcmp(ids, ImmediateDataAddress(&cmd), sizeof(ids)));
+}
+
+TEST_F(RasterFormatTest, DeleteQueriesEXTImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::DeleteQueriesEXTImmediate& cmd =
+      *GetBufferAs<cmds::DeleteQueriesEXTImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::DeleteQueriesEXTImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  EXPECT_EQ(0, memcmp(ids, ImmediateDataAddress(&cmd), sizeof(ids)));
+}
+
+TEST_F(RasterFormatTest, BeginQueryEXT) {
+  cmds::BeginQueryEXT& cmd = *GetBufferAs<cmds::BeginQueryEXT>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLuint>(12),
+              static_cast<uint32_t>(13), static_cast<uint32_t>(14));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BeginQueryEXT::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.sync_data_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.sync_data_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, EndQueryEXT) {
+  cmds::EndQueryEXT& cmd = *GetBufferAs<cmds::EndQueryEXT>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::EndQueryEXT::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.submit_count);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, CopySubTextureCHROMIUM) {
+  cmds::CopySubTextureCHROMIUM& cmd =
+      *GetBufferAs<cmds::CopySubTextureCHROMIUM>();
+  void* next_cmd = cmd.Set(
+      &cmd, static_cast<GLuint>(11), static_cast<GLint>(12),
+      static_cast<GLenum>(13), static_cast<GLuint>(14), static_cast<GLint>(15),
+      static_cast<GLint>(16), static_cast<GLint>(17), static_cast<GLint>(18),
+      static_cast<GLint>(19), static_cast<GLsizei>(20),
+      static_cast<GLsizei>(21), static_cast<GLboolean>(22),
+      static_cast<GLboolean>(23), static_cast<GLboolean>(24));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::CopySubTextureCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.source_id);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.source_level);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.dest_target);
+  EXPECT_EQ(static_cast<GLuint>(14), cmd.dest_id);
+  EXPECT_EQ(static_cast<GLint>(15), cmd.dest_level);
+  EXPECT_EQ(static_cast<GLint>(16), cmd.xoffset);
+  EXPECT_EQ(static_cast<GLint>(17), cmd.yoffset);
+  EXPECT_EQ(static_cast<GLint>(18), cmd.x);
+  EXPECT_EQ(static_cast<GLint>(19), cmd.y);
+  EXPECT_EQ(static_cast<GLsizei>(20), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(21), cmd.height);
+  EXPECT_EQ(static_cast<GLboolean>(22), cmd.unpack_flip_y);
+  EXPECT_EQ(static_cast<GLboolean>(23), cmd.unpack_premultiply_alpha);
+  EXPECT_EQ(static_cast<GLboolean>(24), cmd.unpack_unmultiply_alpha);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, CompressedCopyTextureCHROMIUM) {
+  cmds::CompressedCopyTextureCHROMIUM& cmd =
+      *GetBufferAs<cmds::CompressedCopyTextureCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::CompressedCopyTextureCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.source_id);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.dest_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, ProduceTextureDirectCHROMIUMImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLbyte data[] = {
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 0),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 1),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 2),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 3),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 4),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 5),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 6),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 7),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 8),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 9),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 10),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 11),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 12),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 13),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 14),
+      static_cast<GLbyte>(kSomeBaseValueToTestWith + 15),
+  };
+  cmds::ProduceTextureDirectCHROMIUMImmediate& cmd =
+      *GetBufferAs<cmds::ProduceTextureDirectCHROMIUMImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), data);
+  EXPECT_EQ(static_cast<uint32_t>(
+                cmds::ProduceTextureDirectCHROMIUMImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+}
+
+TEST_F(RasterFormatTest, BindTexImage2DCHROMIUM) {
+  cmds::BindTexImage2DCHROMIUM& cmd =
+      *GetBufferAs<cmds::BindTexImage2DCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BindTexImage2DCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.imageId);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, ReleaseTexImage2DCHROMIUM) {
+  cmds::ReleaseTexImage2DCHROMIUM& cmd =
+      *GetBufferAs<cmds::ReleaseTexImage2DCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::ReleaseTexImage2DCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLint>(12), cmd.imageId);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, TraceBeginCHROMIUM) {
+  cmds::TraceBeginCHROMIUM& cmd = *GetBufferAs<cmds::TraceBeginCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::TraceBeginCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.category_bucket_id);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.name_bucket_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, TraceEndCHROMIUM) {
+  cmds::TraceEndCHROMIUM& cmd = *GetBufferAs<cmds::TraceEndCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::TraceEndCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, LoseContextCHROMIUM) {
+  cmds::LoseContextCHROMIUM& cmd = *GetBufferAs<cmds::LoseContextCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLenum>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::LoseContextCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.current);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.other);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, WaitSyncTokenCHROMIUM) {
+  cmds::WaitSyncTokenCHROMIUM& cmd =
+      *GetBufferAs<cmds::WaitSyncTokenCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLint>(11), static_cast<GLuint64>(12),
+              static_cast<GLuint64>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::WaitSyncTokenCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLint>(11), cmd.namespace_id);
+  EXPECT_EQ(static_cast<GLuint64>(12), cmd.command_buffer_id());
+  EXPECT_EQ(static_cast<GLuint64>(13), cmd.release_count());
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, InitializeDiscardableTextureCHROMIUM) {
+  cmds::InitializeDiscardableTextureCHROMIUM& cmd =
+      *GetBufferAs<cmds::InitializeDiscardableTextureCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12),
+              static_cast<uint32_t>(13));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::InitializeDiscardableTextureCHROMIUM::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture_id);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, UnlockDiscardableTextureCHROMIUM) {
+  cmds::UnlockDiscardableTextureCHROMIUM& cmd =
+      *GetBufferAs<cmds::UnlockDiscardableTextureCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::UnlockDiscardableTextureCHROMIUM::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, LockDiscardableTextureCHROMIUM) {
+  cmds::LockDiscardableTextureCHROMIUM& cmd =
+      *GetBufferAs<cmds::LockDiscardableTextureCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::LockDiscardableTextureCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, BeginRasterCHROMIUM) {
+  cmds::BeginRasterCHROMIUM& cmd = *GetBufferAs<cmds::BeginRasterCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12),
+              static_cast<GLuint>(13), static_cast<GLboolean>(14),
+              static_cast<GLboolean>(15), static_cast<GLint>(16));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BeginRasterCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.texture_id);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.sk_color);
+  EXPECT_EQ(static_cast<GLuint>(13), cmd.msaa_sample_count);
+  EXPECT_EQ(static_cast<GLboolean>(14), cmd.can_use_lcd_text);
+  EXPECT_EQ(static_cast<GLboolean>(15), cmd.use_distance_field_text);
+  EXPECT_EQ(static_cast<GLint>(16), cmd.pixel_config);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, RasterCHROMIUM) {
+  cmds::RasterCHROMIUM& cmd = *GetBufferAs<cmds::RasterCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLsizeiptr>(11), static_cast<uint32_t>(12),
+              static_cast<uint32_t>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::RasterCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizeiptr>(11), cmd.size);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.list_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.list_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, EndRasterCHROMIUM) {
+  cmds::EndRasterCHROMIUM& cmd = *GetBufferAs<cmds::EndRasterCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::EndRasterCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, CreateTransferCacheEntryINTERNAL) {
+  cmds::CreateTransferCacheEntryINTERNAL& cmd =
+      *GetBufferAs<cmds::CreateTransferCacheEntryINTERNAL>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
+                           static_cast<GLuint>(12), static_cast<GLuint>(13),
+                           static_cast<GLuint>(14), static_cast<GLuint>(15),
+                           static_cast<GLuint>(16), static_cast<GLuint>(17));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::CreateTransferCacheEntryINTERNAL::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.entry_type);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.entry_id);
+  EXPECT_EQ(static_cast<GLuint>(13), cmd.handle_shm_id);
+  EXPECT_EQ(static_cast<GLuint>(14), cmd.handle_shm_offset);
+  EXPECT_EQ(static_cast<GLuint>(15), cmd.data_shm_id);
+  EXPECT_EQ(static_cast<GLuint>(16), cmd.data_shm_offset);
+  EXPECT_EQ(static_cast<GLuint>(17), cmd.data_size);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, DeleteTransferCacheEntryINTERNAL) {
+  cmds::DeleteTransferCacheEntryINTERNAL& cmd =
+      *GetBufferAs<cmds::DeleteTransferCacheEntryINTERNAL>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::DeleteTransferCacheEntryINTERNAL::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.entry_type);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.entry_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, UnlockTransferCacheEntryINTERNAL) {
+  cmds::UnlockTransferCacheEntryINTERNAL& cmd =
+      *GetBufferAs<cmds::UnlockTransferCacheEntryINTERNAL>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::UnlockTransferCacheEntryINTERNAL::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.entry_type);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.entry_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(RasterFormatTest, TexStorage2DImageCHROMIUM) {
+  cmds::TexStorage2DImageCHROMIUM& cmd =
+      *GetBufferAs<cmds::TexStorage2DImageCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLenum>(12),
+              static_cast<GLsizei>(13), static_cast<GLsizei>(14));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::TexStorage2DImageCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.internalFormat);
+  EXPECT_EQ(static_cast<GLsizei>(13), cmd.width);
+  EXPECT_EQ(static_cast<GLsizei>(14), cmd.height);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/raster_cmd_ids.h b/gpu/command_buffer/common/raster_cmd_ids.h
new file mode 100644
index 0000000..6e9c7e6
--- /dev/null
+++ b/gpu/command_buffer/common/raster_cmd_ids.h
@@ -0,0 +1,22 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the raster command buffer commands.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_H_
+#define GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_H_
+
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+
+namespace gpu {
+namespace raster {
+
+#include "gpu/command_buffer/common/raster_cmd_ids_autogen.h"
+
+const char* GetCommandName(CommandId command_id);
+
+}  // namespace raster
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_H_
diff --git a/gpu/command_buffer/common/raster_cmd_ids_autogen.h b/gpu/command_buffer/common/raster_cmd_ids_autogen.h
new file mode 100644
index 0000000..22361e23
--- /dev/null
+++ b/gpu/command_buffer/common/raster_cmd_ids_autogen.h
@@ -0,0 +1,64 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_raster_cmd_buffer.py
+// It's formatted by clang-format using chromium coding style:
+//    clang-format -i -style=chromium filename
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_AUTOGEN_H_
+
+#define RASTER_COMMAND_LIST(OP)                       \
+  OP(ActiveTexture)                         /* 256 */ \
+  OP(BindTexture)                           /* 257 */ \
+  OP(CompressedTexImage2DBucket)            /* 258 */ \
+  OP(CompressedTexImage2D)                  /* 259 */ \
+  OP(DeleteTexturesImmediate)               /* 260 */ \
+  OP(Finish)                                /* 261 */ \
+  OP(Flush)                                 /* 262 */ \
+  OP(GenTexturesImmediate)                  /* 263 */ \
+  OP(GetError)                              /* 264 */ \
+  OP(GetIntegerv)                           /* 265 */ \
+  OP(PixelStorei)                           /* 266 */ \
+  OP(TexImage2D)                            /* 267 */ \
+  OP(TexParameteri)                         /* 268 */ \
+  OP(TexSubImage2D)                         /* 269 */ \
+  OP(TexStorage2DEXT)                       /* 270 */ \
+  OP(GenQueriesEXTImmediate)                /* 271 */ \
+  OP(DeleteQueriesEXTImmediate)             /* 272 */ \
+  OP(BeginQueryEXT)                         /* 273 */ \
+  OP(EndQueryEXT)                           /* 274 */ \
+  OP(CopySubTextureCHROMIUM)                /* 275 */ \
+  OP(CompressedCopyTextureCHROMIUM)         /* 276 */ \
+  OP(ProduceTextureDirectCHROMIUMImmediate) /* 277 */ \
+  OP(BindTexImage2DCHROMIUM)                /* 278 */ \
+  OP(ReleaseTexImage2DCHROMIUM)             /* 279 */ \
+  OP(TraceBeginCHROMIUM)                    /* 280 */ \
+  OP(TraceEndCHROMIUM)                      /* 281 */ \
+  OP(LoseContextCHROMIUM)                   /* 282 */ \
+  OP(WaitSyncTokenCHROMIUM)                 /* 283 */ \
+  OP(InitializeDiscardableTextureCHROMIUM)  /* 284 */ \
+  OP(UnlockDiscardableTextureCHROMIUM)      /* 285 */ \
+  OP(LockDiscardableTextureCHROMIUM)        /* 286 */ \
+  OP(BeginRasterCHROMIUM)                   /* 287 */ \
+  OP(RasterCHROMIUM)                        /* 288 */ \
+  OP(EndRasterCHROMIUM)                     /* 289 */ \
+  OP(CreateTransferCacheEntryINTERNAL)      /* 290 */ \
+  OP(DeleteTransferCacheEntryINTERNAL)      /* 291 */ \
+  OP(UnlockTransferCacheEntryINTERNAL)      /* 292 */ \
+  OP(TexStorage2DImageCHROMIUM)             /* 293 */
+
+enum CommandId {
+  kOneBeforeStartPoint =
+      cmd::kLastCommonId,  // All Raster commands start after this.
+#define RASTER_CMD_OP(name) k##name,
+  RASTER_COMMAND_LIST(RASTER_CMD_OP)
+#undef RASTER_CMD_OP
+      kNumCommands,
+  kFirstRasterCommand = kOneBeforeStartPoint + 1
+};
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_RASTER_CMD_IDS_AUTOGEN_H_
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index dcb3f91..02175ac1 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -19,6 +19,7 @@
 #include "gpu/config/gpu_util.h"
 #include "gpu/ipc/service/gpu_watchdog_thread.h"
 #include "gpu/ipc/service/switches.h"
+#include "ui/base/ui_base_switches_util.h"
 #include "ui/gfx/switches.h"
 #include "ui/gl/gl_features.h"
 #include "ui/gl/gl_implementation.h"
@@ -312,6 +313,9 @@
       gles2::PassthroughCommandDecoderSupported();
 
   init_successful_ = true;
+#if defined(USE_OZONE)
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
+#endif
   return true;
 }
 
@@ -324,7 +328,9 @@
 #if defined(USE_OZONE)
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
+  params.using_mojo = switches::IsMusHostingViz();
   ui::OzonePlatform::InitializeForGPU(params);
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
   if (gpu_info) {
diff --git a/ios/chrome/browser/autofill/form_structure_browsertest.mm b/ios/chrome/browser/autofill/form_structure_browsertest.mm
index e2cb06c..b4daff792 100644
--- a/ios/chrome/browser/autofill/form_structure_browsertest.mm
+++ b/ios/chrome/browser/autofill/form_structure_browsertest.mm
@@ -159,7 +159,7 @@
 
 void FormStructureBrowserTest::GenerateResults(const std::string& input,
                                                std::string* output) {
-  LoadHtml(input);
+  ASSERT_TRUE(LoadHtml(input));
   base::TaskScheduler::GetInstance()->FlushForTesting();
   AutofillManager* autofill_manager =
       AutofillDriverIOS::FromWebState(web_state())->autofill_manager();
diff --git a/ios/chrome/browser/ntp_snippets/BUILD.gn b/ios/chrome/browser/ntp_snippets/BUILD.gn
index 83f64df..1edd553 100644
--- a/ios/chrome/browser/ntp_snippets/BUILD.gn
+++ b/ios/chrome/browser/ntp_snippets/BUILD.gn
@@ -33,6 +33,5 @@
     "//ios/chrome/common",
     "//ios/web",
     "//net",
-    "//services/identity/public/cpp",
   ]
 }
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc
index 9e1e0832..c2467bc 100644
--- a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc
+++ b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.cc
@@ -15,7 +15,6 @@
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
-#include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/signin/oauth2_token_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 
@@ -47,7 +46,6 @@
     : BrowserStateKeyedServiceFactory(
           "ContentSuggestionsService",
           BrowserStateDependencyManager::GetInstance()) {
-  DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(ios::HistoryServiceFactory::GetInstance());
   DependsOn(IOSChromeLargeIconServiceFactory::GetInstance());
   DependsOn(OAuth2TokenServiceFactory::GetInstance());
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
index 22885e65..1a87e99 100644
--- a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
+++ b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
@@ -45,7 +45,7 @@
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
-#include "ios/chrome/browser/signin/identity_manager_factory.h"
+#include "ios/chrome/browser/signin/oauth2_token_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/browser_state.h"
@@ -161,8 +161,9 @@
   PrefService* prefs = chrome_browser_state->GetPrefs();
   SigninManager* signin_manager =
       ios::SigninManagerFactory::GetForBrowserState(chrome_browser_state);
-  identity::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForBrowserState(chrome_browser_state);
+
+  OAuth2TokenService* token_service =
+      OAuth2TokenServiceFactory::GetForBrowserState(chrome_browser_state);
   scoped_refptr<net::URLRequestContextGetter> request_context =
       browser_state->GetRequestContext();
   base::FilePath database_dir(
@@ -177,7 +178,7 @@
                                 : google_apis::GetNonStableAPIKey();
   }
   auto suggestions_fetcher = std::make_unique<RemoteSuggestionsFetcherImpl>(
-      identity_manager, request_context, prefs, nullptr,
+      signin_manager, token_service, request_context, prefs, nullptr,
       base::BindRepeating(&ParseJson), GetFetchEndpoint(GetChannel()), api_key,
       service->user_classifier());
 
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 1e79baa5..5e99dda 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -1333,7 +1333,7 @@
 }
 
 - (void)shieldWasTapped:(id)sender {
-  [self.primaryToolbarCoordinator cancelOmniboxEdit];
+  [self.dispatcher cancelOmniboxEdit];
 }
 
 - (void)userEnteredTabSwitcher {
@@ -1420,7 +1420,7 @@
   // Present voice search.
   [_voiceSearchBar prepareToPresentVoiceSearch];
   _voiceSearchController->StartRecognition(self, [_model currentTab]);
-  [self.primaryToolbarCoordinator cancelOmniboxEdit];
+  [self.dispatcher cancelOmniboxEdit];
 }
 
 - (void)clearPresentedStateWithCompletion:(ProceduralBlock)completion
@@ -1429,7 +1429,7 @@
   [_bookmarkInteractionController dismissBookmarkModalControllerAnimated:NO];
   [_bookmarkInteractionController dismissSnackbar];
   if (dismissOmnibox) {
-    [self.primaryToolbarCoordinator cancelOmniboxEdit];
+    [self.dispatcher cancelOmniboxEdit];
   }
   [_dialogPresenter cancelAllDialogs];
   [self.dispatcher hidePageInfo];
@@ -1978,8 +1978,9 @@
   self.sideSwipeController.toolbarInteractionHandler =
       self.primaryToolbarCoordinator;
 
-  [_dispatcher startDispatchingToTarget:self.primaryToolbarCoordinator
-                            forProtocol:@protocol(OmniboxFocuser)];
+  [_dispatcher
+      startDispatchingToTarget:self.primaryToolbarCoordinator.omniboxFocuser
+                   forProtocol:@protocol(OmniboxFocuser)];
   [_dispatcher startDispatchingToTarget:self.primaryToolbarCoordinator
                             forProtocol:@protocol(FakeboxFocuser)];
   [self.legacyToolbarCoordinator setTabCount:[_model count]];
@@ -2194,12 +2195,14 @@
   contentFrame.origin.y = marginWithHeader;
   [_contentArea setFrame:contentFrame];
 
-  // Adjust the infobar container to be either at the bottom of the screen
-  // (iPhone) or on the lower toolbar edge (iPad).
-  CGRect infoBarFrame = contentFrame;
-  infoBarFrame.origin.y = CGRectGetMaxY(contentFrame);
-  infoBarFrame.size.height = 0;
-  [infoBarContainerView setFrame:infoBarFrame];
+  if (initialLayout) {
+    // Adjust the infobar container to be either at the bottom of the screen
+    // (iPhone) or on the lower toolbar edge (iPad).
+    CGRect infoBarFrame = contentFrame;
+    infoBarFrame.origin.y = CGRectGetMaxY(contentFrame);
+    infoBarFrame.size.height = 0;
+    [infoBarContainerView setFrame:infoBarFrame];
+  }
 
   // Attach the typing shield to the content area but have it hidden.
   [self.typingShield setFrame:[_contentArea frame]];
@@ -3794,7 +3797,7 @@
     NewTabPageController* pageController =
         [[NewTabPageController alloc] initWithUrl:url
                                            loader:self
-                                          focuser:self.primaryToolbarCoordinator
+                                          focuser:self.dispatcher
                                      browserState:_browserState
                                   toolbarDelegate:self.toolbarInterface
                                          tabModel:_model
@@ -4307,7 +4310,7 @@
   DCHECK(self.visible || self.dismissingModal);
 
   // Dismiss the omnibox (if open).
-  [self.primaryToolbarCoordinator cancelOmniboxEdit];
+  [self.dispatcher cancelOmniboxEdit];
   // Dismiss the soft keyboard (if open).
   [[_model currentTab].webController dismissKeyboard];
   // Dismiss Find in Page focus.
@@ -5429,7 +5432,7 @@
 - (void)prepareForTabHistoryPresentation {
   DCHECK(self.visible || self.dismissingModal);
   [[self.tabModel currentTab].webController dismissKeyboard];
-  [self.primaryToolbarCoordinator cancelOmniboxEdit];
+  [self.dispatcher cancelOmniboxEdit];
 }
 
 #pragma mark - CaptivePortalDetectorTabHelperDelegate
@@ -5449,7 +5452,7 @@
 
 - (void)prepareForPageInfoPresentation {
   // Dismiss the omnibox (if open).
-  [self.primaryToolbarCoordinator cancelOmniboxEdit];
+  [self.dispatcher cancelOmniboxEdit];
 }
 
 - (CGPoint)convertToPresentationCoordinatesForOrigin:(CGPoint)origin {
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn
index 567423a8..26b3dc7 100644
--- a/ios/chrome/browser/ui/download/BUILD.gn
+++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -5,6 +5,8 @@
 source_set("download") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "download_manager_view_controller.h",
+    "download_manager_view_controller.mm",
     "legacy_download_manager_controller.h",
     "legacy_download_manager_controller.mm",
     "pass_kit_coordinator.h",
@@ -28,6 +30,7 @@
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
+    "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web:web_internal",
     "//ios/third_party/material_components_ios",
     "//ios/third_party/material_roboto_font_loader_ios",
@@ -44,6 +47,7 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
+    "download_manager_view_controller_unittest.mm",
     "legacy_download_manager_controller_unittest.mm",
     "pass_kit_coordinator_unittest.mm",
   ]
diff --git a/ios/chrome/browser/ui/download/download_manager_view_controller.h b/ios/chrome/browser/ui/download/download_manager_view_controller.h
new file mode 100644
index 0000000..b47745bf
--- /dev/null
+++ b/ios/chrome/browser/ui/download/download_manager_view_controller.h
@@ -0,0 +1,75 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_DOWNLOAD_DOWNLOAD_MANAGER_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_DOWNLOAD_DOWNLOAD_MANAGER_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+@class DownloadManagerViewController;
+
+typedef NS_ENUM(NSInteger, DownloadManagerState) {
+  // Download has not started yet.
+  kDownloadManagerStateNotStarted = 0,
+  // Download is actively progressing.
+  kDownloadManagerStateInProgress,
+  // Download is completely finished without errors.
+  kDownloadManagerStateSuceeded,
+  // Download has failed with an error.
+  kDownloadManagerStateFailed,
+};
+
+@protocol DownloadManagerViewControllerDelegate<NSObject>
+@optional
+// Called when close button was tapped. Delegate may dismiss presentation.
+- (void)downloadManagerViewControllerDidClose:
+    (DownloadManagerViewController*)controller;
+
+// Called when Download or Restart button was tapped. Delegate should start the
+// download.
+- (void)downloadManagerViewControllerDidStartDownload:
+    (DownloadManagerViewController*)controller;
+
+// Called when "Open In.." button was tapped. Delegate should present system's
+// OpenIn dialog from |layoutGuide|.
+- (void)downloadManagerViewController:(DownloadManagerViewController*)controller
+     presentOpenInMenuWithLayoutGuide:(UILayoutGuide*)layoutGuide;
+
+@end
+
+// Presents bottom bar UI for a single download task.
+@interface DownloadManagerViewController : UIViewController
+
+@property(nonatomic, weak) id<DownloadManagerViewControllerDelegate> delegate;
+
+// Name of the file being downloaded.
+@property(nonatomic, copy) NSString* fileName;
+
+// The received size of the file being downloaded in bytes.
+@property(nonatomic) int64_t countOfBytesReceived;
+
+// The expected size of the file being downloaded in bytes.
+@property(nonatomic) int64_t countOfBytesExpectedToReceive;
+
+// State of the download task. Default is kDownloadManagerStateNotStarted.
+@property(nonatomic) DownloadManagerState state;
+
+@end
+
+// All UI elements presend in view controller's view.
+@interface DownloadManagerViewController (UIElements)
+
+// Button to dismiss the download toolbar.
+@property(nonatomic, readonly) UIButton* closeButton;
+
+// Label that describes the current download status.
+@property(nonatomic, readonly) UILabel* statusLabel;
+
+// Button appropriate for the current download status ("Download", "Open In..",
+// "Try Again").
+@property(nonatomic, readonly) UIButton* actionButton;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_DOWNLOAD_DOWNLOAD_MANAGER_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/download/download_manager_view_controller.mm b/ios/chrome/browser/ui/download/download_manager_view_controller.mm
new file mode 100644
index 0000000..df03534e
--- /dev/null
+++ b/ios/chrome/browser/ui/download/download_manager_view_controller.mm
@@ -0,0 +1,339 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
+
+#include "base/logging.h"
+#include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/ui/util/named_guide.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// Layout Guide name for action button UILayoutGuide.
+GuideName* const kActionButtonGuide = @"kDownloadManagerActionButtonGuide";
+
+// A margin for every control element (status label, action button, close
+// button). Defines the minimal distance between elements.
+const CGFloat kElementMargin = 16;
+
+// Returns formatted size string.
+NSString* GetSizeString(long long size_in_bytes) {
+  return [NSByteCountFormatter
+      stringFromByteCount:size_in_bytes
+               countStyle:NSByteCountFormatterCountStyleFile];
+}
+}  // namespace
+
+@interface DownloadManagerViewController () {
+  UIButton* _closeButton;
+  UILabel* _statusLabel;
+  UIButton* _actionButton;
+}
+// Shadow view sits on top of background view. Union of shadow and background
+// views fills self.view area. The shadow is dropped to web page, not to white
+// Download Manager background.
+@property(nonatomic, readonly) UIImageView* shadow;
+@property(nonatomic, readonly) UIView* background;
+@end
+
+@implementation DownloadManagerViewController
+
+@synthesize delegate = _delegate;
+@synthesize fileName = _fileName;
+@synthesize countOfBytesReceived = _countOfBytesReceived;
+@synthesize countOfBytesExpectedToReceive = _countOfBytesExpectedToReceive;
+@synthesize state = _state;
+@synthesize shadow = _shadow;
+@synthesize background = _background;
+
+#pragma mark - UIViewController overrides
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+
+  [self.view addSubview:self.shadow];
+  [self.view addSubview:self.background];
+  [self.view addSubview:self.closeButton];
+  [self.view addSubview:self.statusLabel];
+  [self.view addSubview:self.actionButton];
+
+  AddNamedGuide(kActionButtonGuide, self.view);
+  ConstrainNamedGuideToView(kActionButtonGuide, self.actionButton);
+
+  if (@available(iOS 11, *)) {
+    self.view.directionalLayoutMargins = NSDirectionalEdgeInsetsMake(
+        kElementMargin, kElementMargin, kElementMargin, kElementMargin);
+  } else {
+    self.view.layoutMargins = UIEdgeInsetsMake(kElementMargin, kElementMargin,
+                                               kElementMargin, kElementMargin);
+  }
+}
+
+- (void)updateViewConstraints {
+  [super updateViewConstraints];
+
+  // self.view constraints.
+  UIView* view = self.view;
+  view.translatesAutoresizingMaskIntoConstraints = NO;
+  UILabel* statusLabel = self.statusLabel;
+  [NSLayoutConstraint activateConstraints:@[
+    [view.layoutMarginsGuide.heightAnchor
+        constraintEqualToAnchor:statusLabel.heightAnchor],
+  ]];
+
+  // shadow constraints.
+  UIImageView* shadow = self.shadow;
+  [NSLayoutConstraint activateConstraints:@[
+    [shadow.leadingAnchor constraintEqualToAnchor:view.leadingAnchor],
+    [shadow.trailingAnchor constraintEqualToAnchor:view.trailingAnchor],
+    [shadow.topAnchor constraintEqualToAnchor:view.topAnchor],
+  ]];
+
+  // background constraints.
+  UIView* background = self.background;
+  [NSLayoutConstraint activateConstraints:@[
+    [background.leadingAnchor constraintEqualToAnchor:view.leadingAnchor],
+    [background.trailingAnchor constraintEqualToAnchor:view.trailingAnchor],
+    [background.bottomAnchor constraintEqualToAnchor:view.bottomAnchor],
+    [background.topAnchor constraintEqualToAnchor:shadow.bottomAnchor],
+  ]];
+
+  // close button constraints.
+  UIButton* closeButton = self.closeButton;
+  [NSLayoutConstraint activateConstraints:@[
+    [closeButton.centerYAnchor constraintEqualToAnchor:view.centerYAnchor],
+    [closeButton.trailingAnchor
+        constraintEqualToAnchor:view.layoutMarginsGuide.trailingAnchor],
+  ]];
+
+  // status label constraints.
+  UIButton* actionButton = self.actionButton;
+  [NSLayoutConstraint activateConstraints:@[
+    [statusLabel.centerYAnchor constraintEqualToAnchor:view.centerYAnchor],
+    [statusLabel.leadingAnchor
+        constraintEqualToAnchor:view.layoutMarginsGuide.leadingAnchor],
+    [statusLabel.trailingAnchor
+        constraintLessThanOrEqualToAnchor:actionButton.leadingAnchor
+                                 constant:-kElementMargin],
+  ]];
+
+  // action button constraints.
+  [NSLayoutConstraint activateConstraints:@[
+    [actionButton.centerYAnchor constraintEqualToAnchor:view.centerYAnchor],
+    [actionButton.trailingAnchor
+        constraintEqualToAnchor:closeButton.leadingAnchor
+                       constant:-kElementMargin],
+  ]];
+}
+
+#pragma mark - Public Properties
+
+- (void)setFileName:(NSString*)fileName {
+  if (![_fileName isEqual:fileName]) {
+    _fileName = [fileName copy];
+    [self updateStatusLabel];
+  }
+}
+
+- (void)setCountOfBytesReceived:(int64_t)value {
+  if (_countOfBytesReceived != value) {
+    _countOfBytesReceived = value;
+    [self updateStatusLabel];
+  }
+}
+
+- (void)setCountOfBytesExpectedToReceive:(int64_t)value {
+  if (_countOfBytesExpectedToReceive != value) {
+    _countOfBytesExpectedToReceive = value;
+    [self updateStatusLabel];
+  }
+}
+
+- (void)setState:(DownloadManagerState)state {
+  if (_state != state) {
+    _state = state;
+    [self updateStatusLabel];
+    [self updateActionButton];
+  }
+}
+
+#pragma mark - UI elements
+
+- (UIImageView*)shadow {
+  if (!_shadow) {
+    UIImage* shadowImage = [UIImage imageNamed:@"infobar_shadow"];
+    _shadow = [[UIImageView alloc] initWithImage:shadowImage];
+    _shadow.translatesAutoresizingMaskIntoConstraints = NO;
+  }
+  return _shadow;
+}
+
+- (UIView*)background {
+  if (!_background) {
+    _background = [[UIView alloc] initWithFrame:CGRectZero];
+    _background.translatesAutoresizingMaskIntoConstraints = NO;
+    _background.backgroundColor = [UIColor whiteColor];
+  }
+  return _background;
+}
+
+- (UIButton*)closeButton {
+  if (!_closeButton) {
+    _closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
+    _closeButton.translatesAutoresizingMaskIntoConstraints = NO;
+    _closeButton.exclusiveTouch = YES;
+    _closeButton.accessibilityLabel = l10n_util::GetNSString(IDS_CLOSE);
+
+    // TODO(crbug.com/228611): Add IDR_ constant and use GetNativeImageNamed().
+    UIImage* image = [UIImage imageNamed:@"infobar_close"];
+    [_closeButton setImage:image forState:UIControlStateNormal];
+
+    [_closeButton addTarget:self
+                     action:@selector(didTapCloseButton)
+           forControlEvents:UIControlEventTouchUpInside];
+  }
+  return _closeButton;
+}
+
+- (UILabel*)statusLabel {
+  if (!_statusLabel) {
+    _statusLabel = [[UILabel alloc] initWithFrame:CGRectZero];
+    _statusLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    _statusLabel.font = [MDCTypography subheadFont];
+    [self updateStatusLabel];
+  }
+  return _statusLabel;
+}
+
+- (UIButton*)actionButton {
+  if (!_actionButton) {
+    _actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
+    _actionButton.translatesAutoresizingMaskIntoConstraints = NO;
+    _actionButton.exclusiveTouch = YES;
+    [_actionButton setTitleColor:[MDCPalette bluePalette].tint500
+                        forState:UIControlStateNormal];
+
+    [_actionButton addTarget:self
+                      action:@selector(didTapActionButton)
+            forControlEvents:UIControlEventTouchUpInside];
+    [self updateActionButton];
+  }
+  return _actionButton;
+}
+
+#pragma mark - Actions
+
+- (void)didTapCloseButton {
+  SEL selector = @selector(downloadManagerViewControllerDidClose:);
+  if ([_delegate respondsToSelector:selector]) {
+    [_delegate downloadManagerViewControllerDidClose:self];
+  }
+}
+
+- (void)didTapActionButton {
+  switch (self.state) {
+    case kDownloadManagerStateNotStarted: {
+      SEL selector = @selector(downloadManagerViewControllerDidStartDownload:);
+      if ([_delegate respondsToSelector:selector]) {
+        [_delegate downloadManagerViewControllerDidStartDownload:self];
+      }
+      break;
+    }
+    case kDownloadManagerStateInProgress: {
+      // The button should not be visible.
+      NOTREACHED();
+      break;
+    }
+    case kDownloadManagerStateSuceeded: {
+      SEL selector = @selector
+          (downloadManagerViewController:presentOpenInMenuWithLayoutGuide:);
+      if ([_delegate respondsToSelector:selector]) {
+        UILayoutGuide* guide = FindNamedGuide(kActionButtonGuide, self.view);
+        [_delegate downloadManagerViewController:self
+                presentOpenInMenuWithLayoutGuide:guide];
+      }
+      break;
+    }
+    case kDownloadManagerStateFailed: {
+      SEL selector = @selector(downloadManagerViewControllerDidStartDownload:);
+      if ([_delegate respondsToSelector:selector]) {
+        [_delegate downloadManagerViewControllerDidStartDownload:self];
+      }
+      break;
+    }
+  }
+}
+
+#pragma mark - UI Updates
+
+// Updates status label text depending on |state|.
+- (void)updateStatusLabel {
+  NSString* statusText = nil;
+  switch (self.state) {
+    case kDownloadManagerStateNotStarted:
+      statusText = self.fileName;
+      if (self.countOfBytesExpectedToReceive != -1) {
+        statusText = [statusText
+            stringByAppendingFormat:@" - %@",
+                                    GetSizeString(
+                                        self.countOfBytesExpectedToReceive)];
+      }
+      break;
+    case kDownloadManagerStateInProgress:
+      // TODO(crbug.com/805533): Localize this string.
+      statusText =
+          [NSString stringWithFormat:@"Downloading... %@",
+                                     GetSizeString(self.countOfBytesReceived)];
+      if (self.countOfBytesExpectedToReceive != -1) {
+        statusText = [statusText
+            stringByAppendingFormat:@"/%@",
+                                    GetSizeString(
+                                        self.countOfBytesExpectedToReceive)];
+      }
+      break;
+    case kDownloadManagerStateSuceeded:
+      statusText = self.fileName;
+      break;
+    case kDownloadManagerStateFailed:
+      // TODO(crbug.com/805533): Localize this string.
+      statusText = @"Couldn't Download";
+      break;
+  }
+
+  self.statusLabel.text = statusText;
+  [self.statusLabel sizeToFit];
+}
+
+// Updates title and hidden state for action button depending on |state|.
+- (void)updateActionButton {
+  NSString* title = nil;
+  switch (self.state) {
+    case kDownloadManagerStateNotStarted:
+      // TODO(crbug.com/805533): Localize this string.
+      title = @"Download";
+      break;
+    case kDownloadManagerStateInProgress:
+      break;
+    case kDownloadManagerStateSuceeded:
+      // TODO(crbug.com/805533): Localize this string.
+      title = @"Open In...";
+      break;
+    case kDownloadManagerStateFailed:
+      // TODO(crbug.com/805533): Localize this string.
+      title = @"Try Again";
+      break;
+  }
+
+  [self.actionButton setTitle:title forState:UIControlStateNormal];
+  self.actionButton.hidden = self.state == kDownloadManagerStateInProgress;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/download/download_manager_view_controller_unittest.mm b/ios/chrome/browser/ui/download/download_manager_view_controller_unittest.mm
new file mode 100644
index 0000000..b9cf43b
--- /dev/null
+++ b/ios/chrome/browser/ui/download/download_manager_view_controller_unittest.mm
@@ -0,0 +1,166 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
+
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Test fixture for testing DownloadManagerViewController class.
+class DownloadManagerViewControllerTest : public PlatformTest {
+ protected:
+  DownloadManagerViewControllerTest()
+      : view_controller_([[DownloadManagerViewController alloc] init]) {}
+  DownloadManagerViewController* view_controller_;
+};
+
+// Tests default state for the new view controller.
+TEST_F(DownloadManagerViewControllerTest, Init) {
+  EXPECT_FALSE(view_controller_.delegate);
+  EXPECT_FALSE(view_controller_.fileName);
+  EXPECT_EQ(0, view_controller_.countOfBytesReceived);
+  EXPECT_EQ(0, view_controller_.countOfBytesExpectedToReceive);
+  EXPECT_EQ(kDownloadManagerStateNotStarted, view_controller_.state);
+}
+
+// Tests label and button titles with kDownloadManagerStateNotStarted state
+// and long file name.
+TEST_F(DownloadManagerViewControllerTest, NotStartedWithLongFileName) {
+  view_controller_.state = kDownloadManagerStateNotStarted;
+  view_controller_.fileName = @"longfilenamesolongthatitbarelyfitwidthlimit";
+  view_controller_.countOfBytesExpectedToReceive = 1024;
+
+  EXPECT_NSEQ(@"longfilenamesolongthatitbarelyfitwidthlimit - 1 KB",
+              view_controller_.statusLabel.text);
+  EXPECT_NSEQ(@"Download", [view_controller_.actionButton
+                               titleForState:UIControlStateNormal]);
+}
+
+// Tests label and button titles with kDownloadManagerStateNotStarted state
+// and large file size.
+TEST_F(DownloadManagerViewControllerTest,
+       NotStartedWithLongCountOfExpectedBytes) {
+  view_controller_.state = kDownloadManagerStateNotStarted;
+  view_controller_.fileName = @"file.zip";
+  view_controller_.countOfBytesExpectedToReceive = 1000 * 1024 * 1024;
+
+  EXPECT_NSEQ(@"file.zip - 1.05 GB", view_controller_.statusLabel.text);
+  EXPECT_NSEQ(@"Download", [view_controller_.actionButton
+                               titleForState:UIControlStateNormal]);
+}
+
+// Tests label and button hidden state with kDownloadManagerStateInProgress
+// state and long file name.
+TEST_F(DownloadManagerViewControllerTest, InProgressWithLongFileName) {
+  view_controller_.state = kDownloadManagerStateInProgress;
+  view_controller_.fileName = @"longfilenamesolongthatitbarelyfitwidthlimit";
+  view_controller_.countOfBytesExpectedToReceive = 10 * 1024;
+
+  EXPECT_NSEQ(@"Downloading... Zero KB/10 KB",
+              view_controller_.statusLabel.text);
+  EXPECT_TRUE(view_controller_.actionButton.hidden);
+}
+
+// Tests label and button hidden state with kDownloadManagerStateInProgress
+// state and unknown download size.
+TEST_F(DownloadManagerViewControllerTest,
+       InProgressWithUnknownCountOfExpectedBytes) {
+  view_controller_.state = kDownloadManagerStateInProgress;
+  view_controller_.fileName = @"file.zip";
+  view_controller_.countOfBytesReceived = 900;
+  view_controller_.countOfBytesExpectedToReceive = -1;
+
+  EXPECT_NSEQ(@"Downloading... 900 bytes", view_controller_.statusLabel.text);
+  EXPECT_TRUE(view_controller_.actionButton.hidden);
+}
+
+// Tests label and button titles with kDownloadManagerStateSuceeded state.
+TEST_F(DownloadManagerViewControllerTest, SuceededWithWithLongFileName) {
+  view_controller_.state = kDownloadManagerStateSuceeded;
+  view_controller_.fileName = @"file.txt";
+  view_controller_.countOfBytesReceived = 1024;
+
+  EXPECT_NSEQ(@"file.txt", view_controller_.statusLabel.text);
+  EXPECT_NSEQ(@"Open In...", [view_controller_.actionButton
+                                 titleForState:UIControlStateNormal]);
+}
+
+// Tests label and button titles with kDownloadManagerStateFailed state.
+TEST_F(DownloadManagerViewControllerTest, Failed) {
+  view_controller_.state = kDownloadManagerStateFailed;
+  view_controller_.fileName = @"file.txt";
+  view_controller_.countOfBytesReceived = 1024;
+
+  EXPECT_NSEQ(@"Couldn't Download", view_controller_.statusLabel.text);
+  EXPECT_NSEQ(@"Try Again", [view_controller_.actionButton
+                                titleForState:UIControlStateNormal]);
+}
+
+// Tests that tapping close button calls downloadManagerViewControllerDidClose:.
+TEST_F(DownloadManagerViewControllerTest, Close) {
+  id delegate =
+      OCMStrictProtocolMock(@protocol(DownloadManagerViewControllerDelegate));
+  OCMExpect([delegate downloadManagerViewControllerDidClose:view_controller_]);
+
+  view_controller_.state = kDownloadManagerStateNotStarted;
+  view_controller_.delegate = delegate;
+  [view_controller_.closeButton
+      sendActionsForControlEvents:UIControlEventTouchUpInside];
+
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that tapping Download button calls
+// downloadManagerViewControllerDidStartDownload:.
+TEST_F(DownloadManagerViewControllerTest, Start) {
+  id delegate =
+      OCMStrictProtocolMock(@protocol(DownloadManagerViewControllerDelegate));
+  OCMExpect([delegate
+      downloadManagerViewControllerDidStartDownload:view_controller_]);
+
+  view_controller_.state = kDownloadManagerStateNotStarted;
+  view_controller_.delegate = delegate;
+  [view_controller_.actionButton
+      sendActionsForControlEvents:UIControlEventTouchUpInside];
+
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that tapping Open In... button calls
+// downloadManagerViewController:presentOpenInMenuWithLayoutGuide:.
+TEST_F(DownloadManagerViewControllerTest, OpenIn) {
+  id delegate =
+      OCMStrictProtocolMock(@protocol(DownloadManagerViewControllerDelegate));
+  OCMExpect([delegate downloadManagerViewController:view_controller_
+                   presentOpenInMenuWithLayoutGuide:[OCMArg any]]);
+
+  view_controller_.state = kDownloadManagerStateSuceeded;
+  view_controller_.delegate = delegate;
+  [view_controller_.actionButton
+      sendActionsForControlEvents:UIControlEventTouchUpInside];
+
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that tapping Restart button calls
+// downloadManagerViewControllerDidStartDownload:.
+TEST_F(DownloadManagerViewControllerTest, Restart) {
+  id delegate =
+      OCMStrictProtocolMock(@protocol(DownloadManagerViewControllerDelegate));
+  OCMExpect([delegate
+      downloadManagerViewControllerDidStartDownload:view_controller_]);
+
+  view_controller_.state = kDownloadManagerStateFailed;
+  view_controller_.delegate = delegate;
+  [view_controller_.actionButton
+      sendActionsForControlEvents:UIControlEventTouchUpInside];
+
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
diff --git a/ios/chrome/browser/ui/download/pass_kit_coordinator.mm b/ios/chrome/browser/ui/download/pass_kit_coordinator.mm
index aa006549..d88f6396 100644
--- a/ios/chrome/browser/ui/download/pass_kit_coordinator.mm
+++ b/ios/chrome/browser/ui/download/pass_kit_coordinator.mm
@@ -102,6 +102,8 @@
   UMA_HISTOGRAM_ENUMERATION(kUmaPresentAddPassesDialogResult,
                             GetUmaResult(self.baseViewController),
                             PresentAddPassesDialogResult::kCount);
+  if (_viewController)
+    return;
 
   _viewController = [[PKAddPassesViewController alloc] initWithPass:self.pass];
   _viewController.delegate = self;
diff --git a/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm b/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
index 88e3323..9bd0c9dc 100644
--- a/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
@@ -144,6 +144,12 @@
           PresentAddPassesDialogResult::
               kAnotherAddPassesViewControllerIsPresented),
       1);
+
+  // Previously presented view controller can be dismissed.
+  [coordinator_ stop];
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{
+    return base_view_controller_.presentedViewController == nil;
+  }));
 }
 
 // Tests presenting valid PKPass object, while another view controller is
diff --git a/ios/chrome/browser/ui/fullscreen/BUILD.gn b/ios/chrome/browser/ui/fullscreen/BUILD.gn
index e175fd9c..163a49d7 100644
--- a/ios/chrome/browser/ui/fullscreen/BUILD.gn
+++ b/ios/chrome/browser/ui/fullscreen/BUILD.gn
@@ -18,6 +18,7 @@
 source_set("new_fullscreen") {
   sources = [
     "animated_scoped_fullscreen_disabler.h",
+    "animated_scoped_fullscreen_disabler.mm",
     "fullscreen_controller.h",
     "fullscreen_controller_factory.h",
     "fullscreen_controller_observer.h",
@@ -37,6 +38,7 @@
     "//components/keyed_service/ios",
     "//ios/chrome/browser/ui/browser_list",
     "//ios/chrome/browser/web_state_list",
+    "//ios/chrome/common",
   ]
 }
 
diff --git a/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.h b/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.h
index e1524355..38811eb 100644
--- a/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.h
+++ b/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.h
@@ -15,6 +15,7 @@
 class AnimatedScopedFullscreenDisabler {
  public:
   explicit AnimatedScopedFullscreenDisabler(FullscreenController* controller);
+  ~AnimatedScopedFullscreenDisabler();
 
  private:
   // The FullscreenController being disabled by this object.
diff --git a/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.mm b/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.mm
index a2f4a60..60ef64f 100644
--- a/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.mm
+++ b/ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.h"
 
+#include "base/logging.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #import "ios/chrome/common/material_timing.h"
 
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index 3fa455d..7fb6203 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -33,6 +33,7 @@
     "//ios/chrome/browser/ui/toolbar/keyboard_assist:keyboard_assist",
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/toolbar/public:toolbar_base_feature",
+    "//ios/chrome/browser/web_state_list:web_state_list",
     "//ios/chrome/common:timing",
     "//ios/third_party/material_components_ios",
     "//ios/third_party/material_roboto_font_loader_ios",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.h b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.h
index ffedeef..35b8cd5 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.h
@@ -9,6 +9,7 @@
 
 #import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h"
 #include "ios/chrome/browser/ui/location_bar/location_bar_view.h"
+#import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 
 namespace ios {
 class ChromeBrowserState;
@@ -19,7 +20,8 @@
 @protocol ToolbarCoordinatorDelegate;
 class LocationBarControllerImpl;
 
-@interface LocationBarCoordinator : NSObject<LocationBarURLLoader>
+@interface LocationBarCoordinator
+    : NSObject<LocationBarURLLoader, OmniboxFocuser>
 
 // LocationBarView containing the omnibox.
 @property(nonatomic, strong) LocationBarView* locationBarView;
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 3570fb09..5b2043c 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -131,8 +131,12 @@
 // methods are already necessary though.
 #pragma mark - OmniboxFocuser
 
-- (void)cancelOmniboxEdit {
-  _locationBarController->HideKeyboardAndEndEditing();
+- (void)focusOmnibox {
+  [self.locationBarView.textField becomeFirstResponder];
 }
 
+- (void)cancelOmniboxEdit {
+  _locationBarController->HideKeyboardAndEndEditing();
+  [self updateOmniboxState];
+}
 @end
diff --git a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
index 0d262ed..bbfa4d6c 100644
--- a/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller_egtest.mm
@@ -422,7 +422,7 @@
                          referrer:web::Referrer()
                        transition:transition
                 rendererInitiated:NO];
-          [self cancelOmniboxEdit];
+          [static_cast<LocationBarCoordinator*>(self) cancelOmniboxEdit];
         };
 
     load_GURL_from_location_bar_swizzler_.reset(
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
index c58f521..6f637e6 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
@@ -81,6 +81,10 @@
   return self.viewController;
 }
 
+- (id<OmniboxFocuser>)omniboxFocuser {
+  return self.locationBarCoordinator;
+}
+
 - (void)showPrerenderingAnimation {
   [self.viewController showPrerenderingAnimation];
 }
@@ -104,18 +108,7 @@
   [super updateToolbarState];
 }
 
-#pragma mark - OmniboxFocuser
-
-- (void)focusOmnibox {
-  [self.locationBarCoordinator.locationBarView.textField becomeFirstResponder];
-}
-
-- (void)cancelOmniboxEdit {
-  _locationBar->HideKeyboardAndEndEditing();
-  _locationBar->SetShouldShowHintText(
-      [self.delegate toolbarModelIOS]->ShouldDisplayHintText());
-  _locationBar->OnToolbarUpdated();
-}
+#pragma mark - FakeboxFocuser
 
 - (void)focusFakebox {
   // TODO(crbug.com/803372): Implement that.
@@ -131,36 +124,6 @@
 
 #pragma mark - LocationBarDelegate
 
-- (void)loadGURLFromLocationBar:(const GURL&)url
-                     transition:(ui::PageTransition)transition {
-  if (url.SchemeIs(url::kJavaScriptScheme)) {
-    // Evaluate the URL as JavaScript if its scheme is JavaScript.
-    NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
-        stringByRemovingPercentEncoding];
-    [self.URLLoader loadJavaScriptFromLocationBar:jsToEval];
-  } else {
-    // When opening a URL, force the omnibox to resign first responder.  This
-    // will also close the popup.
-
-    // TODO(crbug.com/785244): Is it ok to call |cancelOmniboxEdit| after
-    // |loadURL|?  It doesn't seem to be causing major problems.  If we call
-    // cancel before load, then any prerendered pages get destroyed before the
-    // call to load.
-    [self.URLLoader loadURL:url
-                   referrer:web::Referrer()
-                 transition:transition
-          rendererInitiated:NO];
-
-    if (google_util::IsGoogleSearchUrl(url)) {
-      UMA_HISTOGRAM_ENUMERATION(
-          kOmniboxQueryLocationAuthorizationStatusHistogram,
-          [CLLocationManager authorizationStatus],
-          kLocationAuthorizationStatusCount);
-    }
-  }
-  [self cancelOmniboxEdit];
-}
-
 - (void)locationBarHasBecomeFirstResponder {
   [self.delegate locationBarDidBecomeFirstResponder];
 }
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
index 6d9a0164..2241092 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
@@ -29,8 +29,7 @@
 }
 
 // Coordinator to run a toolbar -- a UI element housing controls.
-@interface ToolbarCoordinator : NSObject<OmniboxFocuser,
-                                         FakeboxFocuser,
+@interface ToolbarCoordinator : NSObject<FakeboxFocuser,
                                          QRScannerResultLoading,
                                          ToolsMenuPresentationProvider,
                                          VoiceSearchControllerDelegate>
@@ -57,6 +56,9 @@
 // Returns the ActivityServicePositioner for this toolbar.
 - (id<ActivityServicePositioner>)activityServicePositioner;
 
+// Returns the OmniboxFocuser for this toolbar.
+- (id<OmniboxFocuser>)omniboxFocuser;
+
 // Start this coordinator.
 - (void)start;
 // Stop this coordinator.
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
index 73f9d92..6faa2f3 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -153,11 +153,11 @@
 
   self.buttonUpdater = [[ToolbarButtonUpdater alloc] init];
   self.buttonUpdater.factory = factory;
-  self.toolbarViewController =
-      [[ToolbarViewController alloc] initWithDispatcher:self.dispatcher
-                                          buttonFactory:factory
-                                          buttonUpdater:self.buttonUpdater
-                                         omniboxFocuser:self];
+  self.toolbarViewController = [[ToolbarViewController alloc]
+      initWithDispatcher:self.dispatcher
+           buttonFactory:factory
+           buttonUpdater:self.buttonUpdater
+          omniboxFocuser:self.locationBarCoordinator];
   self.toolbarViewController.locationBarView =
       self.locationBarCoordinator.locationBarView;
   self.toolbarViewController.dispatcher = self.dispatcher;
@@ -214,6 +214,10 @@
   return self.toolbarViewController;
 }
 
+- (id<OmniboxFocuser>)omniboxFocuser {
+  return self.locationBarCoordinator;
+}
+
 - (void)updateToolbarState {
   // TODO(crbug.com/803383): This should be done inside the location bar.
   // Updates the omnibox.
@@ -321,17 +325,6 @@
   return toolbarModelIOS ? toolbarModelIOS->GetToolbarModel() : nullptr;
 }
 
-#pragma mark - OmniboxFocuser
-
-- (void)focusOmnibox {
-  [self.locationBarCoordinator.locationBarView.textField becomeFirstResponder];
-}
-
-- (void)cancelOmniboxEdit {
-  _locationBar->HideKeyboardAndEndEditing();
-  [self updateToolbarState];
-}
-
 #pragma mark - FakeboxFocuser
 
 - (void)focusFakebox {
@@ -349,7 +342,7 @@
     [self expandOmniboxAnimated:NO];
   }
 
-  [self focusOmnibox];
+  [self.locationBarCoordinator focusOmnibox];
 }
 
 - (void)onFakeboxBlur {
@@ -380,7 +373,7 @@
   if (load) {
     [self loadURLForQuery:result];
   } else {
-    [self focusOmnibox];
+    [self.locationBarCoordinator focusOmnibox];
     [self.locationBarCoordinator.locationBarView.textField
         insertTextWhileEditing:result];
     // The call to |setText| shouldn't be needed, but without it the "Go" button
diff --git a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
index d39bf1f5..1f7b5c8d 100644
--- a/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.mm
@@ -104,6 +104,10 @@
   return self.toolbarController;
 }
 
+- (id<OmniboxFocuser>)omniboxFocuser {
+  return self.toolbarController;
+}
+
 #pragma mark - WebToolbarController public interface
 
 - (void)setToolbarController:(id<Toolbar>)toolbarController {
@@ -163,16 +167,6 @@
   [self.toolbarController triggerToolsMenuButtonAnimation];
 }
 
-#pragma mark - OmniboxFocuser
-
-- (void)focusOmnibox {
-  [self.toolbarController focusOmnibox];
-}
-
-- (void)cancelOmniboxEdit {
-  [self.toolbarController cancelOmniboxEdit];
-}
-
 #pragma mark - FakeboxFocuser
 
 - (void)focusFakebox {
@@ -288,7 +282,7 @@
 #pragma mark - Toolbar Commands
 
 - (void)contractToolbar {
-  [self cancelOmniboxEdit];
+  [self.toolbarController cancelOmniboxEdit];
 }
 
 #pragma mark - Fullscreen helpers
diff --git a/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h
index 1571f2d..492b2c1 100644
--- a/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h
+++ b/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h
@@ -17,9 +17,7 @@
 
 // Protocol defining a primary toolbar, in a paradigm where the toolbar can be
 // split between primary and secondary.
-@protocol PrimaryToolbarCoordinator<OmniboxFocuser,
-                                    FakeboxFocuser,
-                                    SideSwipeToolbarInteracting>
+@protocol PrimaryToolbarCoordinator<FakeboxFocuser, SideSwipeToolbarInteracting>
 
 @property(nonatomic, strong, readonly) UIViewController* viewController;
 
@@ -29,6 +27,7 @@
 - (id<QRScannerResultLoading>)QRScannerResultLoader;
 - (id<TabHistoryUIUpdater>)tabHistoryUIUpdater;
 - (id<ActivityServicePositioner>)activityServicePositioner;
+- (id<OmniboxFocuser>)omniboxFocuser;
 
 // Stops the coordinator.
 - (void)stop;
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
index d115fff..949b740c 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
@@ -137,11 +137,11 @@
 #pragma mark - OmniboxFocuser
 
 - (void)focusOmnibox {
-  [self.toolbarCoordinator focusOmnibox];
+  [self.toolbarCoordinator.omniboxFocuser focusOmnibox];
 }
 
 - (void)cancelOmniboxEdit {
-  [self.toolbarCoordinator cancelOmniboxEdit];
+  [self.toolbarCoordinator.omniboxFocuser cancelOmniboxEdit];
 }
 
 #pragma mark - FakeboxFocuser
diff --git a/ios/third_party/material_text_accessibility_ios/BUILD.gn b/ios/third_party/material_text_accessibility_ios/BUILD.gn
index 697ba9d..e992bb4 100644
--- a/ios/third_party/material_text_accessibility_ios/BUILD.gn
+++ b/ios/third_party/material_text_accessibility_ios/BUILD.gn
@@ -23,7 +23,10 @@
     "src/src/private/NSArray+MDFUtils.h",
     "src/src/private/NSArray+MDFUtils.m",
   ]
-  public_configs = [ ":config" ]
+  public_configs = [
+    ":config",
+    "//build/config/compiler:default_include_dirs",
+  ]
   configs -= [ "//build/config/compiler:chromium_code" ]
   configs += [
     ":private_config",
diff --git a/ios/third_party/motion_animator_objc/BUILD.gn b/ios/third_party/motion_animator_objc/BUILD.gn
index 43a0e89a..e8b60624 100644
--- a/ios/third_party/motion_animator_objc/BUILD.gn
+++ b/ios/third_party/motion_animator_objc/BUILD.gn
@@ -56,7 +56,10 @@
     "//build/config/compiler:enable_arc",
     "//build/config/compiler:no_chromium_code",
   ]
-  public_configs = [ ":config" ]
+  public_configs = [
+    ":config",
+    "//build/config/compiler:default_include_dirs",
+  ]
 
   public_deps = [
     "//ios/third_party/motion_interchange_objc",
diff --git a/ios/third_party/motion_interchange_objc/BUILD.gn b/ios/third_party/motion_interchange_objc/BUILD.gn
index 5bfe480..ef4d3e09 100644
--- a/ios/third_party/motion_interchange_objc/BUILD.gn
+++ b/ios/third_party/motion_interchange_objc/BUILD.gn
@@ -62,5 +62,8 @@
     "//build/config/compiler:enable_arc",
     "//build/config/compiler:no_chromium_code",
   ]
-  public_configs = [ ":config" ]
+  public_configs = [
+    ":config",
+    "//build/config/compiler:default_include_dirs",
+  ]
 }
diff --git a/ios/third_party/motion_transitioning_objc/BUILD.gn b/ios/third_party/motion_transitioning_objc/BUILD.gn
index 80aa775..25c586d7 100644
--- a/ios/third_party/motion_transitioning_objc/BUILD.gn
+++ b/ios/third_party/motion_transitioning_objc/BUILD.gn
@@ -51,5 +51,8 @@
     "//build/config/compiler:enable_arc",
     "//build/config/compiler:no_chromium_code",
   ]
-  public_configs = [ ":config" ]
+  public_configs = [
+    ":config",
+    "//build/config/compiler:default_include_dirs",
+  ]
 }
diff --git a/ios/web/public/test/web_test_with_web_state.h b/ios/web/public/test/web_test_with_web_state.h
index b513f73..b63bd1d 100644
--- a/ios/web/public/test/web_test_with_web_state.h
+++ b/ios/web/public/test/web_test_with_web_state.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/compiler_specific.h"
 #import "base/ios/block_types.h"
 #include "base/message_loop/message_loop.h"
 #include "ios/web/public/test/web_test.h"
@@ -42,7 +43,7 @@
   // Loads the specified HTML content into the WebState, using test url name.
   void LoadHtml(NSString* html);
   // Loads the specified HTML content into the WebState, using test url name.
-  void LoadHtml(const std::string& html);
+  bool LoadHtml(const std::string& html) WARN_UNUSED_RESULT;
   // Blocks until both known NSRunLoop-based and known message-loop-based
   // background tasks have completed
   void WaitForBackgroundTasks();
diff --git a/ios/web/public/test/web_test_with_web_state.mm b/ios/web/public/test/web_test_with_web_state.mm
index 5df7782..a1f2290f 100644
--- a/ios/web/public/test/web_test_with_web_state.mm
+++ b/ios/web/public/test/web_test_with_web_state.mm
@@ -136,8 +136,10 @@
   LoadHtml(html, url);
 }
 
-void WebTestWithWebState::LoadHtml(const std::string& html) {
+bool WebTestWithWebState::LoadHtml(const std::string& html) {
   LoadHtml(base::SysUTF8ToNSString(html));
+  // TODO(crbug.com/780062): LoadHtml(NSString*) should return bool.
+  return true;
 }
 
 void WebTestWithWebState::WaitForBackgroundTasks() {
diff --git a/ios/web/web_state/js/context_menu_js_unittest.mm b/ios/web/web_state/js/context_menu_js_unittest.mm
index 2ca3ca2c..2872769d 100644
--- a/ios/web/web_state/js/context_menu_js_unittest.mm
+++ b/ios/web/web_state/js/context_menu_js_unittest.mm
@@ -165,7 +165,7 @@
       "<a href='%s'><img width=400 height=400 src='foo'></img></a>";
 
   // A page with a link to a destination URL.
-  LoadHtml(base::StringPrintf(image, "http://destination"));
+  ASSERT_TRUE(LoadHtml(base::StringPrintf(image, "http://destination")));
   ExecuteJavaScript(@"document.getElementsByTagName('img')");  // Force layout.
 
   id result = ExecuteGetElementFromPointJavaScript(20, 20);
@@ -178,7 +178,8 @@
   EXPECT_NSEQ(expected_result, result);
 
   // A page with a link with some JavaScript that does not result in a NOP.
-  LoadHtml(base::StringPrintf(image, "javascript:console.log('whatever')"));
+  ASSERT_TRUE(LoadHtml(
+      base::StringPrintf(image, "javascript:console.log('whatever')")));
   result = ExecuteGetElementFromPointJavaScript(20, 20);
   expected_result = @{
     kContextMenuElementSource :
@@ -197,7 +198,7 @@
   for (auto js : nop_javascripts) {
     // A page with a link with some JavaScript that results in a NOP.
     const std::string javascript = std::string("javascript:") + js;
-    LoadHtml(base::StringPrintf(image, javascript.c_str()));
+    ASSERT_TRUE(LoadHtml(base::StringPrintf(image, javascript.c_str())));
     result = ExecuteGetElementFromPointJavaScript(20, 20);
     expected_result = @{
       kContextMenuElementSource :
@@ -219,7 +220,7 @@
       "</a>";
 
   // A page with a link to a destination URL.
-  LoadHtml(base::StringPrintf(image_html, "http://destination"));
+  ASSERT_TRUE(LoadHtml(base::StringPrintf(image_html, "http://destination")));
   ExecuteJavaScript(@"document.getElementsByTagName('img')");  // Force layout.
   id result = ExecuteGetElementFromPointJavaScript(5, 5);
   NSDictionary* expected_result = @{
@@ -239,7 +240,7 @@
       "<img width=400 height=400 src='foo'></img>";
 
   // Load the invalid meta tag
-  LoadHtml(kInvalidReferrerTag);
+  ASSERT_TRUE(LoadHtml(kInvalidReferrerTag));
   ExecuteJavaScript(@"document.getElementsByTagName('img')");  // Force layout
   id result = ExecuteGetElementFromPointJavaScript(20, 20);
   ASSERT_TRUE([result isKindOfClass:[NSDictionary class]]);
@@ -260,7 +261,7 @@
       " <div style='height:4000px'></div>"
       " <div><a href='http://destination'>link</a></div>"
       "</body></html>";
-  LoadHtml(kHtml);
+  ASSERT_TRUE(LoadHtml(kHtml));
 
   // Scroll the webView to the bottom to make the link accessible.
   CGFloat content_height = GetWebViewContentSize().height;
@@ -288,7 +289,7 @@
 TEST_F(ContextMenuJsTest, LinkOfTextWithoutCalloutProperty) {
   const char kLinkHtml[] = "<a href='%s'>link</a>";
 
-  LoadHtml(base::StringPrintf(kLinkHtml, "http://destination"));
+  ASSERT_TRUE(LoadHtml(base::StringPrintf(kLinkHtml, "http://destination")));
   ExecuteJavaScript(@"document.getElementsByTagName('a')");  // Force layout.
 
   id result = ExecuteGetElementFromPointJavaScript(1, 1);
@@ -313,7 +314,7 @@
   const char kLinkHtml[] =
       "<a href='%s' style='-webkit-touch-callout:default;'>link</a>";
 
-  LoadHtml(base::StringPrintf(kLinkHtml, "http://destination"));
+  ASSERT_TRUE(LoadHtml(base::StringPrintf(kLinkHtml, "http://destination")));
   ExecuteJavaScript(@"document.getElementsByTagName('a')");  // Force layout.
 
   id result = ExecuteGetElementFromPointJavaScript(1, 1);
@@ -332,7 +333,7 @@
   const char kLinkHtml[] =
       "<a href='%s' style='-webkit-touch-callout:none;'>link</a>";
 
-  LoadHtml(base::StringPrintf(kLinkHtml, "http://destination"));
+  ASSERT_TRUE(LoadHtml(base::StringPrintf(kLinkHtml, "http://destination")));
   ExecuteJavaScript(@"document.getElementsByTagName('a')");  // Force layout.
 
   id result = ExecuteGetElementFromPointJavaScript(1, 1);
@@ -348,7 +349,7 @@
       " <a href='%s'>link</a>"
       "</body>";
 
-  LoadHtml(base::StringPrintf(kLinkHtml, "http://destination"));
+  ASSERT_TRUE(LoadHtml(base::StringPrintf(kLinkHtml, "http://destination")));
   ExecuteJavaScript(@"document.getElementsByTagName('a')");  // Force layout.
 
   id result = ExecuteGetElementFromPointJavaScript(1, 1);
@@ -364,7 +365,7 @@
       " <a href='%s' style='-webkit-touch-callout: default'>link</a>"
       "</body>";
 
-  LoadHtml(base::StringPrintf(kLinkHtml, "http://destination"));
+  ASSERT_TRUE(LoadHtml(base::StringPrintf(kLinkHtml, "http://destination")));
   ExecuteJavaScript(@"document.getElementsByTagName('a')");  // Force layout.
 
   id result = ExecuteGetElementFromPointJavaScript(1, 1);
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm
index 729a5c5..92e805c 100644
--- a/ios/web/web_state/web_state_unittest.mm
+++ b/ios/web/web_state/web_state_unittest.mm
@@ -31,7 +31,7 @@
 
 // Tests script execution with and without callback.
 TEST_F(WebStateTest, ScriptExecution) {
-  LoadHtml("<html></html>");
+  ASSERT_TRUE(LoadHtml("<html></html>"));
 
   // Execute script without callback.
   web_state()->ExecuteJavaScript(base::UTF8ToUTF16("window.foo = 'bar'"));
@@ -61,7 +61,7 @@
   web_state()->SetDelegate(&delegate);
   ASSERT_TRUE(delegate.child_windows().empty());
 
-  LoadHtml("<html></html>");
+  ASSERT_TRUE(LoadHtml("<html></html>"));
   web_state()->ExecuteUserJavaScript(@"window.open('', target='_blank');");
 
   web::TestWebStateDelegate* delegate_ptr = &delegate;
@@ -77,7 +77,7 @@
 // Tests loading progress.
 TEST_F(WebStateTest, LoadingProgress) {
   EXPECT_FLOAT_EQ(0.0, web_state()->GetLoadingProgress());
-  LoadHtml("<html></html>");
+  ASSERT_TRUE(LoadHtml("<html></html>"));
   WaitForCondition(^bool() {
     return web_state()->GetLoadingProgress() == 1.0;
   });
@@ -97,11 +97,11 @@
 
   // Load the page which overrides window.webkit object and wait until the
   // test message is received.
-  LoadHtml(
+  ASSERT_TRUE(LoadHtml(
       "<script>"
       "  webkit = undefined;"
       "  __gCrWeb.message.invokeOnHost({'command': 'test.webkit-overriding'});"
-      "</script>");
+      "</script>"));
 
   WaitForCondition(^{
     return message_received;
@@ -143,9 +143,9 @@
 
 // Tests that the snapshot method returns an image of a rendered html page.
 TEST_F(WebStateTest, Snapshot) {
-  LoadHtml(
-      "<html><div style='background-color:#FF0000; width:50%; "
-      "height:100%;'></div></html>");
+  ASSERT_TRUE(
+      LoadHtml("<html><div style='background-color:#FF0000; width:50%; "
+               "height:100%;'></div></html>"));
   __block bool snapshot_complete = false;
   [[[UIApplication sharedApplication] keyWindow]
       addSubview:web_state()->GetView()];
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
index 4666c9e..79a09fb 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -37,6 +37,7 @@
 import org.chromium.base.VisibleForTesting;
 
 import java.io.IOException;
+import java.net.Socket;
 import java.util.Arrays;
 
 import javax.annotation.concurrent.GuardedBy;
@@ -283,11 +284,20 @@
         protected boolean vpnAccessible(Network network) {
             // Determine if the VPN applies to the current user by seeing if a socket can be bound
             // to the VPN.
+            Socket s = new Socket();
             try {
-                network.getSocketFactory().createSocket().close();
+                // Avoid using network.getSocketFactory().createSocket() because it leaks.
+                // https://crbug.com/805424
+                network.bindSocket(s);
             } catch (IOException e) {
                 // Failed to bind so this VPN isn't for the current user to use.
                 return false;
+            } finally {
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    // Not worth taking action on a failed close.
+                }
             }
             return true;
         }
diff --git a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
index 999f399..e86b5de 100644
--- a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
+++ b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
@@ -21,6 +21,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.os.Build;
+import android.os.StrictMode;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.MediumTest;
@@ -973,4 +974,40 @@
         ConnectivityManager.setProcessDefaultNetwork(null);
         Assert.assertFalse(NetworkChangeNotifier.isProcessBoundToNetwork());
     }
+
+    /**
+     * Regression test for crbug.com/805424 where ConnectivityManagerDelegate.vpnAccessible() was
+     * found to leak.
+     */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP)
+    public void testVpnAccessibleDoesNotLeak() {
+        ConnectivityManagerDelegate connectivityManagerDelegate = new ConnectivityManagerDelegate(
+                InstrumentationRegistry.getInstrumentation().getTargetContext());
+        StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
+        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+                                       .detectLeakedClosableObjects()
+                                       .penaltyDeath()
+                                       .penaltyLog()
+                                       .build());
+        try {
+            // Test non-existent Network (NetIds only go to 65535).
+            connectivityManagerDelegate.vpnAccessible(Helper.netIdToNetwork(65537));
+            // Test existing Networks.
+            for (Network network : connectivityManagerDelegate.getAllNetworksUnfiltered()) {
+                connectivityManagerDelegate.vpnAccessible(network);
+            }
+
+            // Run GC and finalizers a few times to pick up leaked closeables
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                System.runFinalization();
+            }
+            System.gc();
+            System.runFinalization();
+        } finally {
+            StrictMode.setVmPolicy(oldPolicy);
+        }
+    }
 }
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index fde705f..5500de3 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -114,6 +114,8 @@
     SpdySessionPool::TimeFunc time_func;
     // Whether to enable HTTP/2 Alt-Svc entries.
     bool enable_http2_alternative_service;
+    // Whether to enable Websocket over HTTP/2.
+    bool enable_websocket_over_http2;
 
     // Enables QUIC support.
     bool enable_quic;
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index f7eef53..55eac530 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -1887,19 +1887,6 @@
                    : NetLogEventType::SSL_HANDSHAKE_MESSAGE_RECEIVED,
           base::Bind(&NetLogSSLMessageCallback, !!is_write, buf, len));
       break;
-    case SSL3_RT_HEADER: {
-      if (is_write)
-        return;
-      if (len != 5) {
-        NOTREACHED();
-        return;
-      }
-      const uint8_t* buf_bytes = reinterpret_cast<const uint8_t*>(buf);
-      uint16_t record_len = (uint16_t(buf_bytes[3]) << 8) | buf_bytes[4];
-      // See RFC 5246 section 6.2.3 for the maximum record size in TLS.
-      UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SSLRecordSizeRead", record_len, 1,
-                                  16384 + 2048, 50);
-    }
     default:
       return;
   }
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index ee6fb9c5..a7884aa 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -147,6 +147,8 @@
     case SETTINGS_MAX_HEADER_LIST_SIZE:
       // There is no initial limit on the size of the header list.
       return false;
+    case SETTINGS_ENABLE_CONNECT_PROTOCOL:
+      return value == 0;
     default:
       // Undefined parameters have no initial value.
       return false;
@@ -786,6 +788,7 @@
       enable_ping_based_connection_checking_(
           enable_ping_based_connection_checking),
       support_ietf_format_quic_altsvc_(support_ietf_format_quic_altsvc),
+      support_websocket_(false),
       connection_at_risk_of_loss_time_(
           base::TimeDelta::FromSeconds(kDefaultConnectionAtRiskOfLossSeconds)),
       hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
@@ -2230,6 +2233,16 @@
           NetLog::IntCallback("delta_window_size", delta_window_size));
       break;
     }
+    case SETTINGS_ENABLE_CONNECT_PROTOCOL:
+      if ((value != 0 && value != 1) || (support_websocket_ && value == 0)) {
+        DoDrainSession(ERR_SPDY_PROTOCOL_ERROR,
+                       "Invalid value for SETTINGS_ENABLE_CONNECT_PROTOCOL.");
+        return;
+      }
+      if (value == 1) {
+        support_websocket_ = true;
+      }
+      break;
   }
 }
 
diff --git a/net/spdy/chromium/spdy_session.h b/net/spdy/chromium/spdy_session.h
index dae7d2a..0357e132 100644
--- a/net/spdy/chromium/spdy_session.h
+++ b/net/spdy/chromium/spdy_session.h
@@ -456,6 +456,9 @@
     return !active_streams_.empty() || !created_streams_.empty();
   }
 
+  // True if the server supports WebSocket protocol.
+  bool support_websocket() const { return support_websocket_; }
+
   // Returns true if no stream in the session can send data due to
   // session flow control.
   bool IsSendStalled() const { return session_send_window_size_ == 0; }
@@ -1043,6 +1046,11 @@
   // If true, alt-svc headers advertising QUIC in IETF format will be supported.
   bool support_ietf_format_quic_altsvc_;
 
+  // True if the server has advertised WebSocket support via
+  // SETTINGS_ENABLE_CONNECT_PROTOCOL, see
+  // https://tools.ietf.org/html/draft-ietf-httpbis-h2-websockets-00.
+  bool support_websocket_;
+
   // |connection_at_risk_of_loss_time_| is an optimization to avoid sending
   // wasteful preface pings (when we just got some data).
   //
diff --git a/net/spdy/chromium/spdy_session_unittest.cc b/net/spdy/chromium/spdy_session_unittest.cc
index 93695dcc..4659010 100644
--- a/net/spdy/chromium/spdy_session_unittest.cc
+++ b/net/spdy/chromium/spdy_session_unittest.cc
@@ -5778,6 +5778,121 @@
   EXPECT_FALSE(OnUnknownFrame(8, 0));
 }
 
+TEST_F(SpdySessionTest, EnableWebsocket) {
+  SettingsMap settings_map;
+  settings_map[SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
+  SpdySerializedFrame settings(spdy_util_.ConstructSpdySettings(settings_map));
+  MockRead reads[] = {CreateMockRead(settings, 0),
+                      MockRead(ASYNC, ERR_IO_PENDING, 2),
+                      MockRead(ASYNC, 0, 3)};
+
+  SpdySerializedFrame ack(spdy_util_.ConstructSpdySettingsAck());
+  MockWrite writes[] = {CreateMockWrite(ack, 1)};
+
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+  AddSSLSocketData();
+
+  CreateNetworkSession();
+  CreateSpdySession();
+
+  EXPECT_FALSE(session_->support_websocket());
+
+  // Read SETTINGS frame.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(session_->support_websocket());
+
+  // Read EOF.
+  data.Resume();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_FALSE(session_);
+}
+
+TEST_F(SpdySessionTest, DisableWebsocketDoesNothing) {
+  SettingsMap settings_map;
+  settings_map[SETTINGS_ENABLE_CONNECT_PROTOCOL] = 0;
+  SpdySerializedFrame settings(spdy_util_.ConstructSpdySettings(settings_map));
+  MockRead reads[] = {CreateMockRead(settings, 0),
+                      MockRead(ASYNC, ERR_IO_PENDING, 2),
+                      MockRead(ASYNC, 0, 3)};
+
+  SpdySerializedFrame ack(spdy_util_.ConstructSpdySettingsAck());
+  MockWrite writes[] = {CreateMockWrite(ack, 1)};
+
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+  AddSSLSocketData();
+
+  CreateNetworkSession();
+  CreateSpdySession();
+
+  EXPECT_FALSE(session_->support_websocket());
+
+  // Read SETTINGS frame.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(session_->support_websocket());
+
+  // Read EOF.
+  data.Resume();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_FALSE(session_);
+}
+
+TEST_F(SpdySessionTest, EnableWebsocketThenDisableIsProtocolError) {
+  SettingsMap settings_map1;
+  settings_map1[SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
+  SpdySerializedFrame settings1(
+      spdy_util_.ConstructSpdySettings(settings_map1));
+  SettingsMap settings_map2;
+  settings_map2[SETTINGS_ENABLE_CONNECT_PROTOCOL] = 0;
+  SpdySerializedFrame settings2(
+      spdy_util_.ConstructSpdySettings(settings_map2));
+  MockRead reads[] = {CreateMockRead(settings1, 0),
+                      MockRead(ASYNC, ERR_IO_PENDING, 2),
+                      CreateMockRead(settings2, 3)};
+
+  SpdySerializedFrame ack1(spdy_util_.ConstructSpdySettingsAck());
+  SpdySerializedFrame ack2(spdy_util_.ConstructSpdySettingsAck());
+  SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
+      0, ERROR_CODE_PROTOCOL_ERROR,
+      "Invalid value for SETTINGS_ENABLE_CONNECT_PROTOCOL."));
+  MockWrite writes[] = {CreateMockWrite(ack1, 1), CreateMockWrite(ack2, 4),
+                        CreateMockWrite(goaway, 5)};
+
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+  AddSSLSocketData();
+
+  CreateNetworkSession();
+  CreateSpdySession();
+
+  EXPECT_FALSE(session_->support_websocket());
+
+  // Read first SETTINGS frame.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(session_->support_websocket());
+
+  // Read second SETTINGS frame.
+  data.Resume();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
+  EXPECT_FALSE(session_);
+}
+
 enum ReadIfReadySupport {
   // ReadIfReady() field trial is enabled, and ReadIfReady() is implemented.
   READ_IF_READY_ENABLED_SUPPORTED,
diff --git a/net/spdy/chromium/spdy_test_util_common.cc b/net/spdy/chromium/spdy_test_util_common.cc
index 534686d..7a0f9c4 100644
--- a/net/spdy/chromium/spdy_test_util_common.cc
+++ b/net/spdy/chromium/spdy_test_util_common.cc
@@ -325,6 +325,7 @@
       session_max_recv_window_size(kDefaultInitialWindowSize),
       time_func(&base::TimeTicks::Now),
       enable_http2_alternative_service(false),
+      enable_websocket_over_http2(false),
       net_log(nullptr),
       http_09_on_non_default_ports_enabled(false),
       disable_idle_sockets_close_on_memory_pressure(false) {
@@ -379,6 +380,8 @@
   params.time_func = session_deps->time_func;
   params.enable_http2_alternative_service =
       session_deps->enable_http2_alternative_service;
+  params.enable_websocket_over_http2 =
+      session_deps->enable_websocket_over_http2;
   params.http_09_on_non_default_ports_enabled =
       session_deps->http_09_on_non_default_ports_enabled;
   params.disable_idle_sockets_close_on_memory_pressure =
diff --git a/net/spdy/chromium/spdy_test_util_common.h b/net/spdy/chromium/spdy_test_util_common.h
index 0c2e28a7..64b8ec4b 100644
--- a/net/spdy/chromium/spdy_test_util_common.h
+++ b/net/spdy/chromium/spdy_test_util_common.h
@@ -219,6 +219,7 @@
   SpdySession::TimeFunc time_func;
   std::unique_ptr<ProxyDelegate> proxy_delegate;
   bool enable_http2_alternative_service;
+  bool enable_websocket_over_http2;
   NetLog* net_log;
   bool http_09_on_non_default_ports_enabled;
   bool disable_idle_sockets_close_on_memory_pressure;
diff --git a/net/spdy/core/spdy_protocol.cc b/net/spdy/core/spdy_protocol.cc
index 3b57e36..78af0aee8 100644
--- a/net/spdy/core/spdy_protocol.cc
+++ b/net/spdy/core/spdy_protocol.cc
@@ -158,6 +158,9 @@
     case SETTINGS_MAX_HEADER_LIST_SIZE:
       *settings_id_string = "SETTINGS_MAX_HEADER_LIST_SIZE";
       return true;
+    case SETTINGS_ENABLE_CONNECT_PROTOCOL:
+      *settings_id_string = "SETTINGS_ENABLE_CONNECT_PROTOCOL";
+      return true;
   }
 
   *settings_id_string = "SETTINGS_UNKNOWN";
diff --git a/net/spdy/core/spdy_protocol.h b/net/spdy/core/spdy_protocol.h
index be15a0a..48622b8 100644
--- a/net/spdy/core/spdy_protocol.h
+++ b/net/spdy/core/spdy_protocol.h
@@ -156,7 +156,10 @@
   SETTINGS_MAX_FRAME_SIZE = 0x5,
   // The maximum size of header list that the sender is prepared to accept.
   SETTINGS_MAX_HEADER_LIST_SIZE = 0x6,
-  SETTINGS_MAX = SETTINGS_MAX_HEADER_LIST_SIZE
+  // Enable Websockets over HTTP/2, see
+  // https://tools.ietf.org/html/draft-ietf-httpbis-h2-websockets-00.
+  SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x8,
+  SETTINGS_MAX = SETTINGS_ENABLE_CONNECT_PROTOCOL
 };
 
 // This explicit operator is needed, otherwise compiler finds
diff --git a/net/spdy/core/spdy_protocol_test.cc b/net/spdy/core/spdy_protocol_test.cc
index a3463063..b2620d3d 100644
--- a/net/spdy/core/spdy_protocol_test.cc
+++ b/net/spdy/core/spdy_protocol_test.cc
@@ -118,7 +118,9 @@
   EXPECT_EQ(SETTINGS_MAX_FRAME_SIZE, setting_id);
   EXPECT_TRUE(ParseSettingsId(6, &setting_id));
   EXPECT_EQ(SETTINGS_MAX_HEADER_LIST_SIZE, setting_id);
-  EXPECT_FALSE(ParseSettingsId(7, &setting_id));
+  EXPECT_TRUE(ParseSettingsId(8, &setting_id));
+  EXPECT_EQ(SETTINGS_ENABLE_CONNECT_PROTOCOL, setting_id);
+  EXPECT_FALSE(ParseSettingsId(9, &setting_id));
 }
 
 TEST(SpdyProtocolTest, SettingsIdToString) {
@@ -135,7 +137,10 @@
       {SETTINGS_INITIAL_WINDOW_SIZE, true, "SETTINGS_INITIAL_WINDOW_SIZE"},
       {SETTINGS_MAX_FRAME_SIZE, true, "SETTINGS_MAX_FRAME_SIZE"},
       {SETTINGS_MAX_HEADER_LIST_SIZE, true, "SETTINGS_MAX_HEADER_LIST_SIZE"},
-      {static_cast<SpdySettingsIds>(7), false, "SETTINGS_UNKNOWN"}};
+      {static_cast<SpdySettingsIds>(7), false, "SETTINGS_UNKNOWN"},
+      {SETTINGS_ENABLE_CONNECT_PROTOCOL, true,
+       "SETTINGS_ENABLE_CONNECT_PROTOCOL"},
+      {static_cast<SpdySettingsIds>(9), false, "SETTINGS_UNKNOWN"}};
   for (auto test_case : test_cases) {
     const char* settings_id_string;
     EXPECT_EQ(test_case.expected_bool,
diff --git a/services/test/run_all_service_tests.cc b/services/test/run_all_service_tests.cc
index deb9fc3..d9bfbce 100644
--- a/services/test/run_all_service_tests.cc
+++ b/services/test/run_all_service_tests.cc
@@ -36,6 +36,7 @@
     ui::OzonePlatform::InitParams params;
     params.single_process = true;
     ui::OzonePlatform::InitializeForGPU(params);
+    ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
     // base::TestSuite and ViewsInit both try to load icu. That's ok for tests.
diff --git a/services/viz/privileged/interfaces/struct_traits_unittest.cc b/services/viz/privileged/interfaces/struct_traits_unittest.cc
index 978538f..929df52 100644
--- a/services/viz/privileged/interfaces/struct_traits_unittest.cc
+++ b/services/viz/privileged/interfaces/struct_traits_unittest.cc
@@ -18,12 +18,10 @@
 
 using StructTraitsTest = testing::Test;
 
-constexpr size_t kArbitrarySize = 32;
 constexpr bool kArbitraryBool = true;
 
 TEST_F(StructTraitsTest, RendererSettings) {
   ResourceSettings arbitrary_resource_settings;
-  arbitrary_resource_settings.texture_id_allocation_chunk_size = kArbitrarySize;
   arbitrary_resource_settings.use_gpu_memory_buffer_resources = kArbitraryBool;
 
   RendererSettings input;
@@ -45,8 +43,6 @@
   RendererSettings output;
   mojom::RendererSettings::Deserialize(
       mojom::RendererSettings::Serialize(&input), &output);
-  EXPECT_EQ(input.resource_settings.texture_id_allocation_chunk_size,
-            output.resource_settings.texture_id_allocation_chunk_size);
   EXPECT_EQ(input.resource_settings.use_gpu_memory_buffer_resources,
             output.resource_settings.use_gpu_memory_buffer_resources);
   EXPECT_EQ(input.allow_antialiasing, output.allow_antialiasing);
diff --git a/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc b/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc
index 9b7f173..120e577 100644
--- a/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc
@@ -10,8 +10,6 @@
 bool StructTraits<viz::mojom::ResourceSettingsDataView, viz::ResourceSettings>::
     Read(viz::mojom::ResourceSettingsDataView data,
          viz::ResourceSettings* out) {
-  out->texture_id_allocation_chunk_size =
-      data.texture_id_allocation_chunk_size();
   out->use_gpu_memory_buffer_resources = data.use_gpu_memory_buffer_resources();
 
   return true;
diff --git a/services/viz/public/cpp/compositing/resource_settings_struct_traits.h b/services/viz/public/cpp/compositing/resource_settings_struct_traits.h
index 44e3493..e108439 100644
--- a/services/viz/public/cpp/compositing/resource_settings_struct_traits.h
+++ b/services/viz/public/cpp/compositing/resource_settings_struct_traits.h
@@ -17,11 +17,6 @@
 template <>
 struct StructTraits<viz::mojom::ResourceSettingsDataView,
                     viz::ResourceSettings> {
-  static size_t texture_id_allocation_chunk_size(
-      const viz::ResourceSettings& input) {
-    return input.texture_id_allocation_chunk_size;
-  }
-
   static bool use_gpu_memory_buffer_resources(
       const viz::ResourceSettings& input) {
     return input.use_gpu_memory_buffer_resources;
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 6cf37de..072b8b17 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -385,17 +385,13 @@
 }
 
 TEST_F(StructTraitsTest, ResourceSettings) {
-  constexpr size_t kArbitrarySize = 32;
   constexpr bool kArbitraryBool = true;
   ResourceSettings input;
-  input.texture_id_allocation_chunk_size = kArbitrarySize;
   input.use_gpu_memory_buffer_resources = kArbitraryBool;
 
   ResourceSettings output;
   SerializeAndDeserialize<mojom::ResourceSettings>(input, &output);
 
-  EXPECT_EQ(input.texture_id_allocation_chunk_size,
-            output.texture_id_allocation_chunk_size);
   EXPECT_EQ(input.use_gpu_memory_buffer_resources,
             output.use_gpu_memory_buffer_resources);
 }
diff --git a/services/viz/public/interfaces/compositing/resource_settings.mojom b/services/viz/public/interfaces/compositing/resource_settings.mojom
index 62e571e..0ea14a2 100644
--- a/services/viz/public/interfaces/compositing/resource_settings.mojom
+++ b/services/viz/public/interfaces/compositing/resource_settings.mojom
@@ -7,6 +7,5 @@
 // Corresponds to |viz::ResourceSettings| in
 // components/viz/common/resources/resource_settings.h
 struct ResourceSettings {
-  uint32 texture_id_allocation_chunk_size;
   bool use_gpu_memory_buffer_resources;
 };
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 569b996..e15a13d 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -970,8 +970,7 @@
       },
       {
         "args": [
-          "--mus",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mus.content_browsertests.filter"
+          "--mus"
         ],
         "name": "mus_content_browsertests",
         "swarming": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index b9ff652f..2483a07efe 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4549,8 +4549,7 @@
       },
       {
         "args": [
-          "--mus",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mus.content_browsertests.filter"
+          "--mus"
         ],
         "name": "mus_content_browsertests",
         "swarming": {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index e1032f4..b2a1d8d 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -1190,16 +1190,6 @@
     ],
     "isolated_scripts": [
       {
-        "args": [
-          "--filter=__main__.ChromeDriverTest.testLoadUrl"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
         "swarming": {
@@ -1950,16 +1940,6 @@
     ],
     "isolated_scripts": [
       {
-        "args": [
-          "--filter=__main__.ChromeDriverTest.testLoadUrl"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
         "swarming": {
@@ -2452,16 +2432,6 @@
     ],
     "isolated_scripts": [
       {
-        "args": [
-          "--filter=__main__.ChromeDriverTest.testLoadUrl"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 6846ac3c..d299362 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -996,8 +996,7 @@
       },
       {
         "args": [
-          "--mus",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mus.content_browsertests.filter"
+          "--mus"
         ],
         "name": "mus_content_browsertests",
         "swarming": {
diff --git a/testing/buildbot/chromium.sandbox.json b/testing/buildbot/chromium.sandbox.json
index 2699882..91a5863 100644
--- a/testing/buildbot/chromium.sandbox.json
+++ b/testing/buildbot/chromium.sandbox.json
@@ -576,16 +576,6 @@
     ],
     "isolated_scripts": [
       {
-        "args": [
-          "--filter=__main__.ChromeDriverTest.testLoadUrl"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
-      },
-      {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
         "swarming": {
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 12f156f..7dc3897 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -45,7 +45,6 @@
     "//testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter",
     "//testing/buildbot/filters/site-per-process.content_browsertests.filter",
     "//testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter",
-    "//testing/buildbot/filters/mus.content_browsertests.filter",
     "//testing/buildbot/filters/viz.content_browsertests.filter",
   ]
 }
diff --git a/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
index 4018cd9..6b57151 100644
--- a/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter
@@ -16,7 +16,6 @@
 -ContentBrowserTestSanityTest.SingleProcess
 -DomSerializerTests.*
 -IndexedDBBrowserTestSingleProcess.RenderThreadShutdownTest
--InProcessGpuTest.*
 -RenderThreadImplDiscardableMemoryBrowserTest.*
 -RenderViewBrowserTest.ConfirmCacheInformationPlumbed
 -ResourceFetcherTests.*
diff --git a/testing/buildbot/filters/mus.content_browsertests.filter b/testing/buildbot/filters/mus.content_browsertests.filter
deleted file mode 100644
index 26f456d..0000000
--- a/testing/buildbot/filters/mus.content_browsertests.filter
+++ /dev/null
@@ -1,2 +0,0 @@
-# Crash during shutdown on wrong thread http://crbug.com/785023
--InProcessGpuTest.*
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter
index 4018cd9..aee4a11 100644
--- a/testing/buildbot/filters/viz.content_browsertests.filter
+++ b/testing/buildbot/filters/viz.content_browsertests.filter
@@ -16,7 +16,6 @@
 -ContentBrowserTestSanityTest.SingleProcess
 -DomSerializerTests.*
 -IndexedDBBrowserTestSingleProcess.RenderThreadShutdownTest
--InProcessGpuTest.*
 -RenderThreadImplDiscardableMemoryBrowserTest.*
 -RenderViewBrowserTest.ConfirmCacheInformationPlumbed
 -ResourceFetcherTests.*
@@ -26,10 +25,10 @@
 
 # WaitForChildFrameSurfaceReady doesn't work http://crbug.com/763452
 -PointerLockBrowserTest.*
--SitePerProcessGestureBrowserTest.*
--SitePerProcessHighDPIBrowserTest.*
--SitePerProcessInternalsBrowserTest.*
--SitePerProcessMouseWheelBrowserTest.*
+-SitePerProcessGestureHitTestBrowserTest.*
+-SitePerProcessHighDPIHitTestBrowserTest.*
+-SitePerProcessInternalsHitTestBrowserTest.*
+-SitePerProcessMouseWheelHitTestBrowserTest.*
 -TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.*
 
 # Waiting for CompositorFrames times out http://crbug.com/787941
@@ -38,33 +37,33 @@
 -SitePerProcessBrowserTest.HiddenOOPIFWillNotGenerateCompositorFramesAfterNavigation
 
 # Further WaitForChildFrameSurfaceReady doesn't work http://crbug.com/787945
--SitePerProcessBrowserTest.AsynchronousHitTestChildTimeout
--SitePerProcessBrowserTest.CancelWheelScrollBubblingOnWheelTargetDeletion
--SitePerProcessBrowserTest.CreateContextMenuTest
--SitePerProcessBrowserTest.CrossProcessMouseCapture
--SitePerProcessBrowserTest.CrossProcessMouseEnterAndLeaveTest
--SitePerProcessBrowserTest.CursorUpdateReceivedCrossSiteIframe
 -SitePerProcessBrowserTest.GestureFlingStartEventsBubble
--SitePerProcessBrowserTest.InputEventRouterGesturePreventDefaultTargetMapTest
--SitePerProcessBrowserTest.InputEventRouterGestureTargetMapTest
--SitePerProcessBrowserTest.InputEventRouterTouchpadGestureTargetTest
--SitePerProcessBrowserTest.InputEventRouterWheelCoalesceTest
--SitePerProcessBrowserTest.HitTestLayerSquashing
--SitePerProcessBrowserTest.HitTestNestedFrames
--SitePerProcessBrowserTest.HitTestWatermark
 -SitePerProcessBrowserTest.NavigateCrashedSubframeToSameSite
--SitePerProcessBrowserTest.NestedSurfaceHitTestTest
--SitePerProcessBrowserTest.OverlapSurfaceHitTestTest
--SitePerProcessBrowserTest.PopupMenuTest
--SitePerProcessBrowserTest.RootConsumesScrollDuringOverscrollGesture
 -SitePerProcessBrowserTest.ScrollBubblingFromNestedOOPIFTest
 -SitePerProcessBrowserTest.ScrollBubblingFromOOPIFTest
--SitePerProcessBrowserTest.ScrollEventToOOPIF
--SitePerProcessBrowserTest.SubframeTouchEventRouting
--SitePerProcessBrowserTest.SurfaceHitTestPointerEventsNone
--SitePerProcessBrowserTest.SurfaceHitTestTest
 -SitePerProcessBrowserTest.TwoSubframesCreatePopupMenuWidgetsSimultaneously
 -SitePerProcessBrowserTest.ViewBoundsInNestedFrameTest
+-SitePerProcessHitTestBrowserTest.AsynchronousHitTestChildTimeout
+-SitePerProcessHitTestBrowserTest.CancelWheelScrollBubblingOnWheelTargetDeletion
+-SitePerProcessHitTestBrowserTest.CreateContextMenuTest
+-SitePerProcessHitTestBrowserTest.CrossProcessMouseCapture
+-SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest
+-SitePerProcessHitTestBrowserTest.CursorUpdateReceivedFromCrossSiteIframe
+-SitePerProcessHitTestBrowserTest.InputEventRouterGesturePreventDefaultTargetMapTest
+-SitePerProcessHitTestBrowserTest.InputEventRouterGestureTargetMapTest
+-SitePerProcessHitTestBrowserTest.InputEventRouterTouchpadGestureTargetTest
+-SitePerProcessHitTestBrowserTest.InputEventRouterWheelCoalesceTest
+-SitePerProcessHitTestBrowserTest.HitTestLayerSquashing
+-SitePerProcessHitTestBrowserTest.HitTestNestedFrames
+-SitePerProcessHitTestBrowserTest.HitTestWatermark
+-SitePerProcessHitTestBrowserTest.NestedSurfaceHitTestTest
+-SitePerProcessHitTestBrowserTest.OverlapSurfaceHitTestTest
+-SitePerProcessHitTestBrowserTest.PopupMenuTest
+-SitePerProcessHitTestBrowserTest.RootConsumesScrollDuringOverscrollGesture
+-SitePerProcessHitTestBrowserTest.ScrollEventToOOPIF
+-SitePerProcessHitTestBrowserTest.SubframeTouchEventRouting
+-SitePerProcessHitTestBrowserTest.SurfaceHitTestPointerEventsNone
+-SitePerProcessHitTestBrowserTest.SurfaceHitTestTest
 
 # Copy Surface timing out http://crbug.com/785257
 -GLAndSoftwareCompositing/CompositingRenderWidgetHostViewBrowserTest.*
@@ -101,3 +100,6 @@
 # Tests failures related to surface sync. http://crbug.com/793302
 -RenderWidgetInitialSizeTest.InitialSize
 -RenderWidgetTest.OnResize
+
+# Flaky Result on Windows-7 http://crbug.com/883463
+-MainThreadEventQueueBrowserTest.MouseMove
\ No newline at end of file
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 0d8c1ed..7509ea5 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -311,16 +311,6 @@
     "label": "//chrome/test/chromedriver:chromedriver",
     "type": "additional_compile_target",
   },
-  "chromedriver_py_tests": {
-    "label": "//chrome/test/chromedriver:chromedriver_py_tests",
-    "type": "script",
-    "script": "//testing/xvfb.py",
-    "args": [
-      "../../chrome/test/chromedriver/test/run_py_tests.py",
-      "--chromedriver=chromedriver",
-      "--log-path=${ISOLATED_OUTDIR}/chromedriver.log",
-    ],
-  },
   "chromedriver_unittests": {
     "label": "//chrome/test/chromedriver:chromedriver_unittests",
     "type": "windowed_test_launcher",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 34a9258..702bdd8d 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -327,18 +327,6 @@
     },
   },
 
-  'chromedriver_py_tests_isolated_scripts': {
-    'chromedriver_py_tests': {
-      "args": [
-        # TODO(johnchen@chromium.org): As the initial step of adding
-        # ChromeDriver tests to commit queue, the following filter is used to
-        # enable a single test case as a smoke test. Many more test cases will
-        # be enabled in the future.
-        "--filter=__main__.ChromeDriverTest.testLoadUrl",
-      ],
-    },
-  },
-
   'chromium_android_asan_gtests': {
     # TODO(kbr): reduce duplication among these tests, and with other
     # test suites.
@@ -1087,7 +1075,6 @@
     'mus_content_browsertests': {
       'args': [
         '--mus',
-        '--test-launcher-filter-file=../../testing/buildbot/filters/mus.content_browsertests.filter',
       ],
       'swarming': {
         'shards': 2,
@@ -1953,7 +1940,6 @@
   ],
 
   'chromium_linux_isolated_scripts': [
-    'chromedriver_py_tests_isolated_scripts',
     'desktop_chromium_isolated_scripts',
     'linux_specific_chromium_isolated_scripts',
     'telemetry_perf_unittests_isolated_scripts',
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index cda20cb..84bdd67 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -80,7 +80,7 @@
 crbug.com/591099 accessibility/canvas-fallback-content.html [ Failure ]
 crbug.com/591099 accessibility/color-well.html [ Failure ]
 crbug.com/591099 accessibility/computed-name.html [ Crash Timeout ]
-crbug.com/591099 accessibility/computed-role.html [ Crash Timeout ]
+crbug.com/591099 accessibility/computed-role.html [ Crash Pass Timeout ]
 crbug.com/591099 accessibility/corresponding-control-deleted-crash.html [ Crash Pass ]
 crbug.com/714962 accessibility/css-first-letter-children.html [ Failure ]
 crbug.com/591099 accessibility/css-generated-content.html [ Failure ]
@@ -211,6 +211,7 @@
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-with-box-shadow.html [ Failure ]
 crbug.com/714962 compositing/gestures/gesture-tapHighlight-with-squashing.html [ Pass ]
 crbug.com/591099 compositing/iframes/composited-iframe-alignment.html [ Failure ]
+crbug.com/591099 compositing/iframes/fixed-position-iframe.html [ Failure ]
 crbug.com/591099 compositing/iframes/floating-self-painting-frame.html [ Failure ]
 crbug.com/591099 compositing/iframes/iframe-in-composited-layer.html [ Failure ]
 crbug.com/591099 compositing/iframes/layout-on-compositing-change.html [ Failure ]
@@ -711,16 +712,11 @@
 crbug.com/591099 css3/filters/effect-invert.html [ Failure ]
 crbug.com/591099 css3/filters/effect-opacity-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-opacity.html [ Failure ]
-crbug.com/714962 css3/filters/effect-reference-image-lazy-attach.html [ Failure Pass ]
-crbug.com/714962 css3/filters/effect-reference-image.html [ Failure Pass ]
-crbug.com/714962 css3/filters/effect-reference-on-transparent-element.html [ Failure Pass ]
 crbug.com/714962 css3/filters/effect-reference-zoom-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-saturate-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-saturate.html [ Failure ]
 crbug.com/591099 css3/filters/effect-sepia-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-sepia.html [ Failure ]
-crbug.com/714962 css3/filters/empty-element-with-filter.html [ Failure Pass ]
-crbug.com/714962 css3/filters/filterRegions.html [ Failure Pass ]
 crbug.com/591099 css3/filters/filtered-inline.html [ Failure ]
 crbug.com/714962 css3/filters/nested-filter.html [ Failure ]
 crbug.com/591099 css3/filters/regions-expanding.html [ Failure ]
@@ -1010,7 +1006,7 @@
 crbug.com/591099 editing/deleting/merge-no-br.html [ Failure ]
 crbug.com/591099 editing/deleting/merge-whitespace-pre.html [ Failure ]
 crbug.com/591099 editing/deleting/table-cells.html [ Failure ]
-crbug.com/591099 editing/deleting/transpose-empty.html [ Failure Pass ]
+crbug.com/591099 editing/deleting/transpose-empty.html [ Failure ]
 crbug.com/591099 editing/deleting/type-delete-after-quote.html [ Failure ]
 crbug.com/591099 editing/execCommand/12244.html [ Failure ]
 crbug.com/591099 editing/execCommand/4580583-1.html [ Failure ]
@@ -1316,7 +1312,7 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDH.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDSA.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_HMAC.worker.html [ Timeout ]
-crbug.com/714962 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.html [ Timeout ]
+crbug.com/714962 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.html [ Timeout ]
@@ -1324,6 +1320,7 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.worker.html [ Timeout ]
 crbug.com/709227 external/wpt/WebCryptoAPI/import_export/symmetric_importKey.worker.html [ Failure ]
 crbug.com/714962 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/acid/acid3/numbered-tests.html [ Crash ]
 crbug.com/591099 external/wpt/acid/acid3/test.html [ Crash ]
 crbug.com/591099 external/wpt/compat/webkit-text-fill-color-property-005.html [ Pass ]
 crbug.com/591099 external/wpt/credential-management/federatedcredential-framed-get.sub.https.html [ Pass ]
@@ -1354,7 +1351,7 @@
 crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-004.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-color-5.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-image-5.html [ Failure ]
-crbug.com/714962 external/wpt/css/css-backgrounds/background-image-003.html [ Failure ]
+crbug.com/714962 external/wpt/css/css-backgrounds/background-image-003.html [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-image-004.html [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-image-005.html [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-image-006.html [ Failure Pass ]
@@ -1364,6 +1361,8 @@
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-table-001-inline.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-table-002-none.html [ Crash ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-text-inherit.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-flexbox/flex-minimum-height-flex-items-004.xht [ Pass ]
+crbug.com/591099 external/wpt/css/css-flexbox/flex-minimum-width-flex-items-004.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-003.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-display/font-display.html [ Failure ]
@@ -1644,11 +1643,11 @@
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-017.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-018.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-019.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-style-attr/style-attr-urls-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-style-attr/style-attr-urls-001.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-style-attr/style-attr-urls-002.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-tables/html5-table-formatting-fixed-layout-1.html [ Crash ]
-crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-tables/visibility-collapse-rowcol-001.html [ Crash ]
 crbug.com/591099 external/wpt/css/css-tables/visibility-collapse-rowspan-crash.html [ Crash ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-color-001.xht [ Failure ]
@@ -1721,62 +1720,62 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-011.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-013.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-015.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-017.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-019.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-017.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-019.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-021.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-023.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-025.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-027.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-029.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-027.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-029.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-031.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-033.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-035.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-037.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-039.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-039.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-041.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-043.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-045.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-047.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-049.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-051.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-049.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-051.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-053.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-055.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-057.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-059.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-061.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-063.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-065.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-067.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-063.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-065.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-067.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-069.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-071.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-073.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-075.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-077.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-077.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-079.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-081.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-083.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-083.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-085.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-087.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-089.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-091.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-093.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-095.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-093.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-095.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-097.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-103.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-105.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-107.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-107.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-109.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-111.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-113.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-115.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-117.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-117.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-119.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-121.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-121.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-123.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-125.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-127.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-127.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-129.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-131.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-131.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-133.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-135.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-137.xht [ Failure ]
@@ -1796,27 +1795,27 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-165.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-167.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-169.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-171.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-173.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-171.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-173.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-175.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-177.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-179.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-179.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-181.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-183.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-183.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-185.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-187.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-189.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-191.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-193.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-195.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-197.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-197.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-199.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-201.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-201.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-203.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-205.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-205.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-207.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-209.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-211.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-211.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-213.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-215.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-217.xht [ Failure ]
@@ -1830,10 +1829,10 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-004.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-006.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-008.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-010.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-010.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-012.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-014.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-016.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-016.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-018.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-020.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-022.xht [ Failure ]
@@ -1857,7 +1856,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-058.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-060.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-062.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-064.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-064.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-066.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-068.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-070.xht [ Failure ]
@@ -1895,7 +1894,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-138.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-140.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-142.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-144.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-144.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-146.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-148.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-150.xht [ Failure ]
@@ -1903,13 +1902,13 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-154.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-156.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-158.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-160.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-160.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-162.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-164.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-166.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-168.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-170.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-172.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-172.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-174.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-176.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-178.xht [ Failure ]
@@ -1955,7 +1954,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/direction-vlr-003.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/direction-vlr-005.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/direction-vrl-002.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/direction-vrl-004.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/direction-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-006.xht [ Failure ]
@@ -1963,10 +1962,10 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/float-lft-orthog-htb-in-vrl-002.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/float-shrink-to-fit-vrl-008.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/float-vlr-005.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/float-vlr-007.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/float-vlr-007.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vlr-013.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-004.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-006.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-006.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/float-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-012.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/horizontal-rule-vrl-002.xht [ Failure ]
@@ -2032,17 +2031,17 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/table-column-order-005.xht [ Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-003.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-005.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-007.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-009.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-007.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-009.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-align-vlr-011.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-013.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-015.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-017.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-019.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-002.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-002.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-004.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-006.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-008.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-008.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-010.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-012.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-014.xht [ Failure Pass ]
@@ -2056,8 +2055,8 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-005.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-011.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-013.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/text-indent-vrl-002.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/text-indent-vrl-004.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/text-indent-vrl-002.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/text-indent-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-indent-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-indent-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-indent-vrl-010.xht [ Failure ]
@@ -2116,6 +2115,7 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-font-face-01.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-font-face-02.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001.html [ Failure ]
+crbug.com/591099 external/wpt/custom-elements/builtin-coverage.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/interfaces.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Document-contentType/contentType/contenttype_datauri_02.html [ Pass ]
 crbug.com/591099 external/wpt/dom/nodes/Element-classlist.html [ Timeout ]
@@ -4909,7 +4909,7 @@
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-border-box-sized-cell-with-collapsed-border-on-table.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-border-box-sized-cell-with-collapsed-border.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-content-box-sized-cell.html [ Failure ]
-crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure ]
+crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure Pass ]
 crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure Pass ]
 crbug.com/591099 fast/table/percent-widths-stretch-vertical.html [ Failure ]
 crbug.com/591099 fast/table/recalc-section-first-body-crash-main.html [ Failure ]
@@ -5292,7 +5292,7 @@
 crbug.com/591099 fullscreen/full-screen-css.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-element-stack.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-iframe-not-allowed.html [ Failure ]
-crbug.com/591099 fullscreen/full-screen-remove-ancestor-after.html [ Crash ]
+crbug.com/591099 fullscreen/full-screen-remove-ancestor-after.html [ Crash Pass ]
 crbug.com/591099 fullscreen/full-screen-ruleset-crash.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-twice-newapi.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-with-css-reference-filter.html [ Crash ]
@@ -5437,7 +5437,7 @@
 crbug.com/591099 http/tests/devtools/console/console-search.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/console/console-uncaught-promise.js [ Failure ]
 crbug.com/591099 http/tests/devtools/console/console-viewport-control.js [ Failure ]
-crbug.com/591099 http/tests/devtools/console/shadow-element.js [ Crash Timeout ]
+crbug.com/591099 http/tests/devtools/console/shadow-element.js [ Crash Pass Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout ]
 crbug.com/714962 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Timeout ]
@@ -5485,7 +5485,7 @@
 crbug.com/714962 http/tests/devtools/elements/inspect-pseudo-element.js [ Timeout ]
 crbug.com/714962 http/tests/devtools/elements/modify-chardata.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/navigate-styles-sidebar-with-arrow-keys.js [ Crash Pass ]
-crbug.com/714962 http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js [ Crash ]
+crbug.com/714962 http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/shadow/create-shadow-root.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-1.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/shadow/inspect-deep-shadow-element.js [ Crash ]
@@ -5501,7 +5501,7 @@
 crbug.com/591099 http/tests/devtools/elements/styles-1/edit-name-with-trimmed-value.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/edit-value-inside-property.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/styles-1/edit-value-url-with-color.js [ Crash ]
-crbug.com/714962 http/tests/devtools/elements/styles-2/force-pseudo-state.js [ Crash ]
+crbug.com/714962 http/tests/devtools/elements/styles-2/force-pseudo-state.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-2/inject-stylesheet.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-2/page-reload-update-sidebar.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/styles-2/paste-property.js [ Crash Pass ]
@@ -5567,7 +5567,9 @@
 crbug.com/591099 http/tests/devtools/sources/debugger-ui/debugger-inline-values.js [ Crash ]
 crbug.com/591099 http/tests/devtools/sources/debugger-ui/watch-expressions-panel-switch.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Crash Pass ]
+crbug.com/591099 http/tests/devtools/startup/sources/debugger/script-formatter-breakpoints-1.js [ Crash ]
 crbug.com/591099 http/tests/devtools/text-autosizing-override.js [ Failure ]
+crbug.com/591099 http/tests/devtools/tracing/scroll-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Failure ]
@@ -5863,7 +5865,7 @@
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-input.js [ Timeout ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-labelledby.js [ Timeout ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-visiblity.js [ Timeout ]
-crbug.com/591099 inspector-protocol/css/css-add-rule.js [ Pass Timeout ]
+crbug.com/591099 inspector-protocol/css/css-add-rule.js [ Timeout ]
 crbug.com/714962 inspector-protocol/css/css-get-platform-fonts.js [ Failure ]
 crbug.com/591099 inspector-protocol/css/css-set-style-text.js [ Pass Timeout ]
 crbug.com/714962 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-viewport.js [ Failure ]
@@ -6593,6 +6595,7 @@
 crbug.com/591099 paint/markers/suggestion-marker-basic.html [ Failure ]
 crbug.com/591099 paint/markers/suggestion-marker-split.html [ Failure ]
 crbug.com/591099 paint/overflow/composited-scroll-vertical-rl.html [ Failure ]
+crbug.com/591099 paint/overflow/fixed-background-scroll-in-frame.html [ Failure ]
 crbug.com/591099 paint/overflow/non-composited-fixed-position-descendant.html [ Failure ]
 crbug.com/591099 paint/pagination/composited-paginated-inline.html [ Failure ]
 crbug.com/591099 paint/pagination/pagination-change-clip-crash.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 842e0d4..6f88ced 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -1,6 +1,11 @@
 # These tests currently fail when they run with --site-per-process.
 # See https://crbug.com/477150.
 
+# https://crbug.com/803672: Test expects cross-origin XHR to work!?
+# https://crbug.com/736308: Test also disabled in LayoutTests/TestExpectations
+crbug.com/803672 external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Timeout ]
+crbug.com/803672 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Timeout ]
+
 # https://crbug.com/794631: Recent regression.
 crbug.com/794631 virtual/unified-autoplay/external/wpt/feature-policy/autoplay-allowed-by-feature-policy-attribute.https.sub.html [ Failure ]
 crbug.com/794631 virtual/unified-autoplay/external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html [ Failure ]
@@ -170,6 +175,8 @@
 Bug(none) external/wpt/html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-same-origin-domain.sub.html [ Failure ]
 Bug(none) external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html [ Timeout ]
 Bug(none) external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html [ Timeout ]
+Bug(none) virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html [ Timeout ]
+Bug(none) virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-similar-but-cross-origin-success.sub.html [ Timeout ]
 Bug(none) external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/windows-1251.html [ Crash ]
 Bug(none) external/wpt/html/semantics/embedded-content/media-elements/error-codes/error.html [ Timeout ]
 Bug(none) external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 348fcdaa..34e4d43 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -81,7 +81,9 @@
 crbug.com/769942 virtual/spv175/paint/invalidation/svg/resource-invalidate-on-target-update.svg [ Failure ]
 
 crbug.com/771643 virtual/spv175/compositing/overflow/nested-border-radius-clipping.html [ Failure ]
-crbug.com/768691 virtual/spv175/fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
+crbug.com/771643 virtual/spv175/fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
+crbug.com/771643 virtual/spv175/fast/borders/inline-mask-overlay-image-outset.html [ Failure ]
+crbug.com/771643 virtual/spv175/fast/borders/inline-mask-overlay-image.html [ Failure ]
 crbug.com/771643 virtual/spv175/fast/multicol/border-radius-clipped-layer.html [ Failure ]
 crbug.com/771643 virtual/spv175/fast/multicol/mixed-opacity-test.html [ Failure ]
 crbug.com/771643 virtual/spv175/fast/multicol/multicol-svg.html [ Failure ]
@@ -106,9 +108,6 @@
 # Scanlines off by 1, but code path should be the same
 crbug.com/644433 virtual/gpu/fast/canvas/OffscreenCanvas-2d-pattern-in-worker.html [ Failure ]
 
-# TODO(xlai): Update the exception in webkit platform tests and turn the test on.
-crbug.com/796202 external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.convert.to.blob.html [ Failure ]
-
 crbug.com/702006 paint/invalidation/compositing/scrolling-neg-z-index-descendants-should-cause-repaint.html [ Failure ]
 crbug.com/702006 virtual/spv175/paint/invalidation/compositing/scrolling-neg-z-index-descendants-should-cause-repaint.html [ Skip ]
 
@@ -2687,6 +2686,11 @@
 crbug.com/798864 external/wpt/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-sharedworker.html [ Failure ]
 crbug.com/798864 external/wpt/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-window.html [ Failure ]
 
+crbug.com/716320 virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.html [ Timeout ]
+crbug.com/716320 virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.html [ Timeout ]
+crbug.com/716320 virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.html [ Timeout ]
+crbug.com/716320 virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.worker.html [ Timeout ]
+
 # Flaky on trybots
 crbug.com/688486 external/wpt/service-workers/service-worker/fetch-request-resources.https.html [ Failure Pass ]
 crbug.com/688486 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/fetch-request-resources.https.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 2efcd8b0..21b39547 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -574,6 +574,12 @@
     "args": ["--force-presentation-receiver-for-testing"]
   },
   {
+    "prefix": "sharedarraybuffer",
+    "base": "external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers",
+    "args": ["--js-flags=--harmony-sharedarraybuffer",
+             "--enable-blink-features=SharedArrayBuffer"]
+  },
+  {
     "prefix": "longtask-v2",
     "base": "http/tests/performance-timing/longtask-v2",
     "args": ["--enable-blink-features=LongTaskV2"]
diff --git a/third_party/WebKit/LayoutTests/editing/selection/stay-in-textarea.html b/third_party/WebKit/LayoutTests/editing/selection/stay-in-textarea.html
index 359e6fa..1c89fb0 100644
--- a/third_party/WebKit/LayoutTests/editing/selection/stay-in-textarea.html
+++ b/third_party/WebKit/LayoutTests/editing/selection/stay-in-textarea.html
@@ -17,7 +17,7 @@
 
 textarea.focus();
 textarea.setSelectionRange(0, 2);
-var textareaSelection = internals.shadowRoot(textarea).getSelection();
+var textareaSelection = internals.youngestShadowRoot(textarea).getSelection();
 var initialTextareaFocusNode = textareaSelection.focusNode;
 
 var initialFocusNode = window.getSelection().focusNode;
diff --git a/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom-expected.txt b/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom-expected.txt
index 8f47bce..9364a536 100644
--- a/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom-expected.txt
@@ -3,8 +3,8 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS addShadowTreeWithDivElement(div); range.selectNodeContents(div.shadowRoot); internals.rangeAsText(range) is "b"
-PASS appendBrElement(div.shadowRoot.childNodes[0]); range.selectNodeContents(div.shadowRoot); internals.rangeAsText(range) is "b\n"
+PASS addShadowTreeWithDivElement(div); range.selectNodeContents(internals.oldestShadowRoot(div)); internals.rangeAsText(range) is "b"
+PASS appendBrElement(internals.oldestShadowRoot(div).childNodes[0]); range.selectNodeContents(internals.oldestShadowRoot(div)); internals.rangeAsText(range) is "b\n"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom.html b/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom.html
index 36dc5d6f..17e871553 100644
--- a/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom.html
+++ b/third_party/WebKit/LayoutTests/editing/text-iterator/basic-iteration-shadowdom.html
@@ -20,7 +20,7 @@
 function addShadowTreeWithDivElement(node)
 {
     node.createShadowRoot();
-    node.shadowRoot.innerHTML = '<div>b</div>';
+    internals.oldestShadowRoot(node).innerHTML = '<div>b</div>';
 }
 
 var testDocument = subframe.contentDocument;
@@ -31,9 +31,9 @@
 
 testDocument.body.innerHTML = '<div>a</div>';
 var div = testDocument.body.childNodes[0];
-shouldBe('addShadowTreeWithDivElement(div); range.selectNodeContents(div.shadowRoot); internals.rangeAsText(range)', '"b"');
+shouldBe('addShadowTreeWithDivElement(div); range.selectNodeContents(internals.oldestShadowRoot(div)); internals.rangeAsText(range)', '"b"');
 
-shouldBe('appendBrElement(div.shadowRoot.childNodes[0]); range.selectNodeContents(div.shadowRoot); internals.rangeAsText(range)', '"b\\n"');
+shouldBe('appendBrElement(internals.oldestShadowRoot(div).childNodes[0]); range.selectNodeContents(internals.oldestShadowRoot(div)); internals.rangeAsText(range)', '"b\\n"');
 
 document.body.removeChild(subframe);
 
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 5c4bb1df..9341f23 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -181068,6 +181068,12 @@
      {}
     ]
    ],
+   "html/browsers/browsing-the-web/read-media/pageload-image-in-popup.html": [
+    [
+     "/html/browsers/browsing-the-web/read-media/pageload-image-in-popup.html",
+     {}
+    ]
+   ],
    "html/browsers/browsing-the-web/read-media/pageload-image.html": [
     [
      "/html/browsers/browsing-the-web/read-media/pageload-image.html",
@@ -239422,7 +239428,7 @@
    "support"
   ],
   "content-security-policy/reporting/report-uri-from-child-frame.html": [
-   "11e8c95e9c02db2105b99f6a52b5c15c09e74bad",
+   "c91cc258165682aeb7af0f9e4b5b576ad0384c6b",
    "testharness"
   ],
   "content-security-policy/reporting/report-uri-from-inline-javascript.html": [
@@ -239466,11 +239472,11 @@
    "support"
   ],
   "content-security-policy/reporting/support/generate-csp-report.html": [
-   "9cc3c65a3c6fda8554b0d9703078885dd51da639",
+   "3084447e7fc1f504fe96df8ac49e5c03d4156ef4",
    "support"
   ],
   "content-security-policy/reporting/support/generate-csp-report.html.sub.headers": [
-   "d0d8e66ddc7605bef502067062e7a348080b4a03",
+   "abfdaa6f0fb659fd3c65074758d691b8e15eebf2",
    "support"
   ],
   "content-security-policy/reporting/support/set-cookie.py": [
@@ -308529,6 +308535,10 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
+  "html/browsers/browsing-the-web/read-media/pageload-image-in-popup.html": [
+   "ccf7d69d5d7fe04242eb63db86a04458cb979b87",
+   "testharness"
+  ],
   "html/browsers/browsing-the-web/read-media/pageload-image.html": [
    "b6710a9c29c09b52db31c9379e933649982dfe09",
    "testharness"
@@ -312478,7 +312488,7 @@
    "testharness"
   ],
   "html/dom/reflection-forms-expected.txt": [
-   "853e6f189cc45bcb1a0b42d7b7b3ed93ed4c56c0",
+   "cdfd341a65d2d5e122586ac298a1eda8fba58c42",
    "support"
   ],
   "html/dom/reflection-forms.html": [
@@ -328666,11 +328676,11 @@
    "testharness"
   ],
   "mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt": [
-   "48ae90591791c96db82a4f806ef6ffc23a91eee7",
+   "4b0785d04c447ae16bc5dbea2c95c48052d6ef43",
    "support"
   ],
   "mediacapture-streams/MediaDevices-IDL-enumerateDevices.html": [
-   "0bebfb5c5a6204257f30d03fb16e4a35b8943814",
+   "6f35e6cfb8409803c64ed7511f9f1dd5c1c538ac",
    "testharness"
   ],
   "mediacapture-streams/MediaDevices-enumerateDevices.https.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.window.js b/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.window.js
index 9c037ba..b53353ab 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.window.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.window.js
@@ -24,16 +24,25 @@
 }, "Verify calling 'navigator.sendBeacon()' with a URL that is not a http(s) scheme throws an exception.");
 
 // We'll validate that we can send one beacon that uses our entire Quota and then fail to send one that is just one char.
-test(function () {
-    var destinationURL = "/fetch/api/resources/trickle.py?count=1&ms=1000";
-
-    var firstSuccess = navigator.sendBeacon(destinationURL, maxPayload);
-    assert_true(firstSuccess, "calling 'navigator.sendBeacon()' with our max payload size should succeed.");
+promise_test(async () => {
+    function wait(ms) {
+        return new Promise(res => step_timeout(res, ms));
+    }
+    const url = '/fetch/api/resources/trickle.py?count=1&ms=0';
+    assert_true(navigator.sendBeacon(url, maxPayload),
+                "calling 'navigator.sendBeacon()' with our max payload size should succeed.");
 
     // Now we'll send just one character.
-    var secondSuccess = navigator.sendBeacon(destinationURL, "1");
-    assert_false(secondSuccess, "calling 'navigator.sendBeacon()' with just one char should fail while our Quota is used up.");
+    assert_false(navigator.sendBeacon(url, '1'),
+                 "calling 'navigator.sendBeacon()' with just one char should fail while our Quota is used up.");
 
-}, "Verify calling 'navigator.sendBeacon()' with a small payload fails while Quota is completely utilized.");
+    for (let i = 0; i < 20; ++i) {
+        await wait(100);
+        if (navigator.sendBeacon(url, maxPayload)) {
+           return;
+        }
+    }
+    assert_unreached('The quota should recover after fetching.');
+}, "Verify the behavior after the quota is exhausted.");
 
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener-expected.txt
deleted file mode 100644
index fbf6fe2..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-FAIL tokenization should skip window features separators before `name` assert_equals: "noopener" should activate feature "noopener" expected null but got object "[object Window]"
-PASS feature `name` should be converted to ASCII lowercase
-FAIL after `name`, tokenization should skip window features separators that are not "=" or "," assert_equals: "foo noopener=1" should activate feature "noopener" expected null but got object "[object Window]"
-PASS Tokenizing should ignore window feature separators except "," after initial "=" and before value
-PASS Tokenizing should read characters until first window feature separator as `value`
-PASS "noopener" should be based on name (key), not value
-FAIL invalid feature names should not tokenize as "noopener" assert_not_equals: "\0noopener" should NOT activate feature "noopener" got disallowed value null
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt
index 1d8a391..7e4fd09 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
-Found 85 tests; 64 PASS, 21 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 85 tests; 72 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test MediaDevices.enumerateDevices call and result. Types only.
 PASS Navigator interface: attribute mediaDevices
 PASS Navigator interface: operation getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback)
-FAIL MediaStream interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStream interface: existence and properties of interface object
 PASS MediaStream interface object length
 PASS MediaStream interface object name
-FAIL MediaStream interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStream interface: existence and properties of interface prototype object
 PASS MediaStream interface: existence and properties of interface prototype object's "constructor" property
 PASS MediaStream interface: attribute id
 PASS MediaStream interface: operation getAudioTracks()
@@ -19,10 +19,10 @@
 PASS MediaStream interface: attribute active
 PASS MediaStream interface: attribute onaddtrack
 PASS MediaStream interface: attribute onremovetrack
-FAIL MediaStreamTrack interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStreamTrack interface: existence and properties of interface object
 PASS MediaStreamTrack interface object length
 PASS MediaStreamTrack interface object name
-FAIL MediaStreamTrack interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStreamTrack interface: existence and properties of interface prototype object
 PASS MediaStreamTrack interface: existence and properties of interface prototype object's "constructor" property
 PASS MediaStreamTrack interface: attribute kind
 PASS MediaStreamTrack interface: attribute id
@@ -40,10 +40,10 @@
 PASS MediaStreamTrack interface: operation getSettings()
 PASS MediaStreamTrack interface: operation applyConstraints(MediaTrackConstraints)
 FAIL MediaStreamTrack interface: attribute onoverconstrained assert_true: The prototype object must have a property "onoverconstrained" expected true got false
-FAIL MediaStreamTrackEvent interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStreamTrackEvent interface: existence and properties of interface object
 PASS MediaStreamTrackEvent interface object length
 PASS MediaStreamTrackEvent interface object name
-FAIL MediaStreamTrackEvent interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object
 PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object's "constructor" property
 PASS MediaStreamTrackEvent interface: attribute track
 FAIL OverconstrainedErrorEvent interface: existence and properties of interface object assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
@@ -52,10 +52,10 @@
 FAIL OverconstrainedErrorEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
 FAIL OverconstrainedErrorEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
 FAIL OverconstrainedErrorEvent interface: attribute error assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL MediaDevices interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaDevices interface: existence and properties of interface object
 PASS MediaDevices interface object length
 PASS MediaDevices interface object name
-FAIL MediaDevices interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
+PASS MediaDevices interface: existence and properties of interface prototype object
 PASS MediaDevices interface: existence and properties of interface prototype object's "constructor" property
 PASS MediaDevices interface: attribute ondevicechange
 PASS MediaDevices interface: operation enumerateDevices()
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
index 4dc1c60..2d9c96ab 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
@@ -23,6 +23,8 @@
   function doIdlTest(idlText) {
     const MDI_idl = new IdlArray();
 
+    MDI_idl.add_untested_idls("interface Event {};");
+    MDI_idl.add_untested_idls("interface EventTarget {};");
     MDI_idl.add_untested_idls("interface Navigator {};");
     MDI_idl.add_idls(idlText);
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-response-taint.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-response-taint.https-expected.txt
deleted file mode 100644
index 4aeacfa5..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-response-taint.https-expected.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-This is a testharness.js-based test.
-PASS initialize global state
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"same-origin" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"same-origin" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"same-origin" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"cors" credentials:"include" should succeed.
-PASS url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"same-origin" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"no-cors" credentials:"include" should succeed.
-PASS url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"cors" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"cors" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?" mode:"cors" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?ACAOrigin=*" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?ACAOrigin=*" mode:"cors" credentials:"same-origin" should succeed.
-PASS url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?ACAOrigin=*" mode:"cors" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/service-workers/service-worker/resources/fetch-access-control.py?ACAOrigin=https://web-platform.test:8444&ACACredentials=true" mode:"cors" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"include" should succeed.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"same-origin" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"same-origin" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"same-origin" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"cors" credentials:"include" should succeed.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"same-origin" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fweb-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=same-origin&" mode:"cors" credentials:"include" should succeed.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"include" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"omit" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"same-origin" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"include" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"omit" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"same-origin" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"include" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"same-origin" credentials:"include" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"no-cors" credentials:"include" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=same-origin&credentials=omit&" mode:"cors" credentials:"include" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"same-origin" credentials:"include" should fail.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"no-cors" credentials:"include" should succeed.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"cors" credentials:"omit" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"cors" credentials:"same-origin" should fail.
-PASS url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"cors" credentials:"include" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"same-origin" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"no-cors" credentials:"include" should succeed.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"cors" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"cors" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3F&mode=no-cors&credentials=omit&" mode:"cors" credentials:"include" should fail.
-FAIL url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"same-origin" credentials:"omit" should fail. assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"same-origin" credentials:"same-origin" should fail. assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"same-origin" credentials:"include" should fail. assert_unreached: Should have rejected: undefined Reached unreachable code
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"cors" credentials:"include" should succeed.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"same-origin" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3D*&mode=cors&credentials=omit&" mode:"cors" credentials:"include" should succeed.
-FAIL url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"same-origin" credentials:"omit" should fail. assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"same-origin" credentials:"same-origin" should fail. assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"same-origin" credentials:"include" should fail. assert_unreached: Should have rejected: undefined Reached unreachable code
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"cors" credentials:"include" should succeed.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"same-origin" credentials:"omit" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"same-origin" credentials:"same-origin" should fail.
-PASS url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"same-origin" credentials:"include" should fail.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"no-cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"no-cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"no-cors" credentials:"include" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"cors" credentials:"omit" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"cors" credentials:"same-origin" should succeed.
-PASS fetching url:"https://www1.web-platform.test:8444/?url=https%3A%2F%2Fwww1.web-platform.test%3A8444%2Fservice-workers%2Fservice-worker%2Fresources%2Ffetch-access-control.py%3FACAOrigin%3Dhttps%3A%2F%2Fweb-platform.test%3A8444%26ACACredentials%3Dtrue&mode=cors&credentials=include&" mode:"cors" credentials:"include" should succeed.
-PASS restore global state
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas-api/OffscreenCanvas-convertToBlob-failures.html b/third_party/WebKit/LayoutTests/fast/canvas-api/OffscreenCanvas-convertToBlob-failures.html
index 2e34188..2795ffa2 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas-api/OffscreenCanvas-convertToBlob-failures.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas-api/OffscreenCanvas-convertToBlob-failures.html
@@ -9,43 +9,57 @@
 
 function makeWorker(script)
 {
-   var blob = new Blob([script]);
-   return new Worker(URL.createObjectURL(blob));
+  var blob = new Blob([script]);
+  return new Worker(URL.createObjectURL(blob));
 }
 
 async_test(function(t) {
-    var worker = makeWorker(document.getElementById("myWorker").textContent);
-    var offscreenCanvas = new OffscreenCanvas(10, 10);
-    worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
-    offscreenCanvas.convertToBlob().then(t.step_func_done(function() {
-        assert_false("convertToBlob didn't throw, but should be");
-    }), t.step_func_done(function(e) {
-        assert_true(e instanceof DOMException);
-        assert_equals(e.name, "InvalidStateError");
-    }));
+  var worker = makeWorker(document.getElementById("myWorker").textContent);
+  var offscreenCanvas = new OffscreenCanvas(10, 10);
+  worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
+  offscreenCanvas.convertToBlob().then(t.step_func_done(function() {
+    assert_false("convertToBlob didn't throw, but should be");
+  }), t.step_func_done(function(e) {
+    assert_true(e instanceof DOMException);
+    assert_equals(e.name, "InvalidStateError");
+  }));
 }, "Test that call convertToBlob on a detached OffscreenCanvas throws exception");
 
 async_test(function(t) {
-    var offscreenCanvas = new OffscreenCanvas(0, 0);
-    offscreenCanvas.convertToBlob().then(t.step_func_done(function(blob) {
-        assert_equals(null, blob, "convertToBlob should return null as result blob.");
-    }), t.step_func_done(function(e) {
-        assert_false("convertToBlob should not throw exception.");
-    }));
+  var offscreenCanvas = new OffscreenCanvas(0, 0);
+  offscreenCanvas.convertToBlob().then(t.step_func_done(function() {
+    assert_false("convertToBlob didn't throw, but should be");
+  }), t.step_func_done(function(e) {
+    assert_true(e instanceof DOMException);
+    assert_equals(e.name, "IndexSizeError");
+  }));
 }, "Test that call convertToBlob on an OffscreenCanvas with size 0 throws exception");
 
 async_test(function(t) {
-    // Based on third_party/libwebp/src/webp/encode.h:WEBP_MAX_DIMENSION
-    var webp_max_dimension = 16383;
-    // This test simulates the encoding failure.
-    var offscreenCanvas = new OffscreenCanvas(10, webp_max_dimension + 1);
-    var ctx = offscreenCanvas.getContext("2d");
-    offscreenCanvas.convertToBlob({type: "image/webp"}).then(t.step_func_done(function(blob) {
-        assert_equals(null, blob, "convertToBlob should return null as result blob.");
-    }), t.step_func_done(function(e) {
-        assert_false("convertToBlob should not throw exception.");
-    }));
+  // Based on third_party/libwebp/src/webp/encode.h:WEBP_MAX_DIMENSION
+  var webp_max_dimension = 16383;
+  // This test simulates the encoding failure.
+  var offscreenCanvas = new OffscreenCanvas(10, webp_max_dimension + 1);
+  var ctx = offscreenCanvas.getContext("2d");
+  ctx.fillRect(0, 0, 1, 1);
+  offscreenCanvas.convertToBlob({type: "image/webp"}).then(t.step_func_done(function() {
+    assert_false("convertToBlob didn't throw, but should be");
+  }), t.step_func_done(function(e) {
+    assert_true(e instanceof DOMException);
+    assert_equals(e.name, "EncodingError");
+  }));
 }, "Test that call convertToBlob throws EncodingError exception when encoding fails");
 
+async_test(function(t) {
+  var offscreenCanvas = new OffscreenCanvas(10, 10);
+  offscreenCanvas.convertToBlob().then(t.step_func_done(function() {
+    assert_false("convertToBlob didn't throw, but should be");
+  }), t.step_func_done(function(e) {
+    assert_true(e instanceof DOMException);
+    assert_equals(e.name, "InvalidStateError");
+  }));
+}, "Test that call convertToBlob on an OffscreenCanvas without contexts throws exception");
+
+
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-zero-size-readback.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-zero-size-readback.html
index e0b2cb5..d416e239 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-zero-size-readback.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-zero-size-readback.html
@@ -59,8 +59,6 @@
     assert_equals(imgdata.height, 1);
   }
 
-  return offscreen.convertToBlob().then(function(resultBlob) {
-    assert_equals(null, resultBlob);
-  });
+  return promise_rejects(t, new DOMException('', 'IndexSizeError'), offscreen.convertToBlob());
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/window-closed-during-layout-dump-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/window-closed-during-layout-dump-expected.txt
new file mode 100644
index 0000000..ed8e358
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/window-closed-during-layout-dump-expected.txt
@@ -0,0 +1 @@
+FAIL: main window was destroyed
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/window-closed-during-layout-dump.html b/third_party/WebKit/LayoutTests/fast/dom/Window/window-closed-during-layout-dump.html
new file mode 100644
index 0000000..424e88d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/window-closed-during-layout-dump.html
@@ -0,0 +1,10 @@
+<script>
+// Regression test for a layout test harness crash when the main test
+// window is closed while waiting for layout dump from subframes.
+// See also https://crbug.com/798598.
+if (testRunner) {
+  testRunner.dumpAsText();
+  testRunner.dumpChildFramesAsText();
+}
+window.close();
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/drag-and-drop-in-user-agent-shadow.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/drag-and-drop-in-user-agent-shadow.html
index 8fd215c..ef1233f 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/drag-and-drop-in-user-agent-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/drag-and-drop-in-user-agent-shadow.html
@@ -12,7 +12,7 @@
                                                document.createTextNode('Shadow Root Child')),
                                      createDOM('slot', {'name': 'user-agent-default-slot'}))));
 
-var shadowRootChild = window.internals.shadowRoot(host).getElementById('shadow-root-child');
+var shadowRootChild = window.internals.youngestShadowRoot(host).getElementById('shadow-root-child');
 var dragstartCount = 0;
 
 host.addEventListener('dragstart', function(e) {
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/offset-parent-does-not-leak-ua-shadow.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/offset-parent-does-not-leak-ua-shadow.html
index 77c5a35..6599e50 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/offset-parent-does-not-leak-ua-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/offset-parent-does-not-leak-ua-shadow.html
@@ -46,7 +46,7 @@
 container.appendChild(host);
 host.setAttribute('open', 'open');
 host.appendChild(child);
-var shadow = window.internals.shadowRoot(host);  // this is a UA shadow root
+var shadow = window.internals.youngestShadowRoot(host);  // this is a UA shadow root
 configureUAShadowRoot(shadow);
 shouldBe('child.offsetParent', 'container');
 
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js
index 1ba6705..c734253e 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js
@@ -102,7 +102,7 @@
 
 function isShadowHost(node)
 {
-    return window.internals.shadowRoot(node);
+    return window.internals.oldestShadowRoot(node);
 }
 
 function isShadowRoot(node)
@@ -115,6 +115,8 @@
     return element && element.nodeName == 'IFRAME';
 }
 
+// You can specify youngerShadowRoot by consecutive slashes.
+// See LayoutTests/fast/dom/shadow/get-element-by-id-in-shadow-root.html for actual usages.
 function getNodeInComposedTree(path)
 {
     var ids = path.split('/');
@@ -124,8 +126,10 @@
             node = node.contentDocument.getElementById(ids[i]);
             continue;
         }
-        if (internals.shadowRoot(node))
-          node = internals.shadowRoot(node);
+        if (isShadowRoot(node))
+            node = internals.youngerShadowRoot(node);
+        else if (internals.oldestShadowRoot(node))
+            node = internals.oldestShadowRoot(node);
         else
             return null;
         if (ids[i] != '')
@@ -172,10 +176,11 @@
         return element;
     }
     if (isShadowHost(element)) {
-        var shadowRoot = window.internals.shadowRoot(element);
-        if (shadowRoot) {
+        var shadowRoot = window.internals.oldestShadowRoot(element);
+        while (shadowRoot) {
             if (shadowRoot.activeElement)
                 return innermostActiveElement(shadowRoot.activeElement);
+            shadowRoot = window.internals.youngerShadowRoot(shadowRoot);
         }
     }
     return element;
@@ -337,8 +342,7 @@
         if (root.nodeType != 1)
             return null;
 
-        var shadowRoot = internals.shadowRoot(root);
-        if (shadowRoot) {
+        for (var shadowRoot = internals.youngestShadowRoot(root); shadowRoot; shadowRoot = shadowRoot.olderShadowRoot) {
             var node = iter(shadowRoot, id);
             if (node != null)
                 return node;
diff --git a/third_party/WebKit/LayoutTests/fast/forms/calendar-picker/calendar-picker-should-not-change-datetimelocal-time.html b/third_party/WebKit/LayoutTests/fast/forms/calendar-picker/calendar-picker-should-not-change-datetimelocal-time.html
index b6368f41..03ff0ef9 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/calendar-picker/calendar-picker-should-not-change-datetimelocal-time.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/calendar-picker/calendar-picker-should-not-change-datetimelocal-time.html
@@ -12,7 +12,7 @@
 
 var input = document.createElement('input');
 input.type = 'datetime-local';
-getElementByPseudoId(internals.shadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', 'yyyy-MM-dd HH:mm');
+getElementByPseudoId(internals.youngestShadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', 'yyyy-MM-dd HH:mm');
 document.body.appendChild(input);
 
 input.value = '1999-07-31T12:59';
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-clearbutton-preventdefault-mousecapture-status.html b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-clearbutton-preventdefault-mousecapture-status.html
index ceecd7e4..5c6b07b3 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-clearbutton-preventdefault-mousecapture-status.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-clearbutton-preventdefault-mousecapture-status.html
@@ -28,7 +28,7 @@
     evt.preventDefault();
 });
 
-var clearButton = getElementByPseudoId(internals.shadowRoot(input),'-webkit-clear-button');
+var clearButton = getElementByPseudoId(internals.oldestShadowRoot(input),'-webkit-clear-button');
 clickElement(clearButton);
 shouldBeEqualToString('input.value', '');
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-fallback-format.html b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-fallback-format.html
index 0bc22d65..7f0dbbf 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-fallback-format.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-fallback-format.html
@@ -14,7 +14,7 @@
 
 function setDateTimeFormat(pattern) {
     var value = input.value;
-    getElementByPseudoId(internals.shadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
+    getElementByPseudoId(internals.youngestShadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
     input.value = ''; // Updates the element for new format
     input.value = value;
 }
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus-expected.txt
index 9d468bf4..8e58ad0 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus-expected.txt
@@ -3,8 +3,8 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS internals.shadowPseudoId(internals.shadowRoot(dateInput).activeElement) is "-webkit-datetime-edit-month-field"
-PASS internals.shadowPseudoId(internals.shadowRoot(dateInput).activeElement) is "-webkit-datetime-edit-month-field"
+PASS internals.shadowPseudoId(internals.youngestShadowRoot(dateInput).activeElement) is "-webkit-datetime-edit-month-field"
+PASS internals.shadowPseudoId(internals.youngestShadowRoot(dateInput).activeElement) is "-webkit-datetime-edit-month-field"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus.html b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus.html
index 34e9f61f..aa1cfa3 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-focus.html
@@ -19,10 +19,10 @@
 dateInput.focus();
 // Because the year field is fixed, the first focusable element is the
 // month field.
-shouldBeEqualToString('internals.shadowPseudoId(internals.shadowRoot(dateInput).activeElement)', '-webkit-datetime-edit-month-field');
+shouldBeEqualToString('internals.shadowPseudoId(internals.youngestShadowRoot(dateInput).activeElement)', '-webkit-datetime-edit-month-field');
 dateInput.blur();
 dateInput.focus();
-shouldBeEqualToString('internals.shadowPseudoId(internals.shadowRoot(dateInput).activeElement)', '-webkit-datetime-edit-month-field');
+shouldBeEqualToString('internals.shadowPseudoId(internals.youngestShadowRoot(dateInput).activeElement)', '-webkit-datetime-edit-month-field');
 
 dateInput.remove();
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-readonly-subfield.html b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-readonly-subfield.html
index 8bef81600..be4118a6 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-readonly-subfield.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-readonly-subfield.html
@@ -16,7 +16,7 @@
 
 // FIXME: Rename this function and the test file.
 function isReadOnlyField(input, pseudo) {
-    var node = internals.shadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
+    var node = internals.youngestShadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
     if (!node)
         testFailed('Requested node is missing.');
     return node && node.hasAttribute('disabled');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/resources/preserve-value-after-history-back-frame.html b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/resources/preserve-value-after-history-back-frame.html
index 67e8cf42..4c8199c 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/resources/preserve-value-after-history-back-frame.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/date-multiple-fields/resources/preserve-value-after-history-back-frame.html
@@ -4,7 +4,7 @@
 <input type="date" id="test2" min="1999-01-01" max="2000-12-31">
 <script>
 function fieldsText(input) {
-    return window.internals.shadowRoot(input).textContent;
+    return window.internals.oldestShadowRoot(input).textContent;
 }
 
 function back(newState) {
diff --git a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-fallback-format.html b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-fallback-format.html
index c4f7f19..383434d 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-fallback-format.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-fallback-format.html
@@ -14,7 +14,7 @@
 
 function setDateTimeFormat(pattern) {
     var value = input.value;
-    getElementByPseudoId(internals.shadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
+    getElementByPseudoId(internals.youngestShadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
     input.value = ''; // Updates the element for new format
     input.value = value;
 }
diff --git a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-mouse-events.html b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-mouse-events.html
index 21a820c..e647d0a 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-mouse-events.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-mouse-events.html
@@ -76,7 +76,7 @@
 
     // With ICU 52 on Linux/Android, a comma is used to delimete date and time and
     // the hour and time field positions are shifted.
-    var commaOffset = window.internals.shadowRoot(input).textContent.indexOf(', ') == -1 ? 0 : 16;
+    var commaOffset = window.internals.oldestShadowRoot(input).textContent.indexOf(', ') == -1 ? 0 : 16;
 
     debug('');
     debug('==> Focus on the hour field.');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-readonly-subfield.html b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-readonly-subfield.html
index ac732a6..ca86145 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-readonly-subfield.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-readonly-subfield.html
@@ -18,7 +18,7 @@
 
 // FIXME: Rename this function and the test file.
 function isReadOnlyField(input, pseudo) {
-    var node = internals.shadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
+    var node = internals.youngestShadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
     if (!node)
         testFailed('Requested node is missing.');
     return node && node.hasAttribute('disabled');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/resources/preserve-value-after-history-back-frame.html b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/resources/preserve-value-after-history-back-frame.html
index 96a48378..2770cff 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/resources/preserve-value-after-history-back-frame.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/datetimelocal-multiple-fields/resources/preserve-value-after-history-back-frame.html
@@ -4,7 +4,7 @@
 <input type="datetime-local" id="test2" min="1999-01-01T00:00" max="2000-12-31T23:59">
 <script>
 function fieldsText(input) {
-    return window.internals.shadowRoot(input).textContent;
+    return window.internals.oldestShadowRoot(input).textContent;
 }
 
 // On Linux/Android with a newer ICU, date and time are separated by ','.
diff --git a/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-fallback-format.html b/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-fallback-format.html
index e5c0003..6ad72ac 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-fallback-format.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-fallback-format.html
@@ -14,7 +14,7 @@
 
 function setDateTimeFormat(pattern) {
     var value = input.value;
-    getElementByPseudoId(internals.shadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
+    getElementByPseudoId(internals.youngestShadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
     input.value = ''; // Updates the element for new format
     input.value = value;
 }
diff --git a/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-readonly-subfield.html b/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-readonly-subfield.html
index ab87c72..b0bf28b 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-readonly-subfield.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/month-multiple-fields-readonly-subfield.html
@@ -16,7 +16,7 @@
 
 // FIXME: Rename this function and the test file.
 function isReadOnlyField(input, pseudo) {
-    var node = internals.shadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
+    var node = internals.youngestShadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
     if (!node)
         testFailed('Requested node is missing.');
     return node && node.hasAttribute('disabled');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/resources/preserve-value-after-history-back-frame.html b/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/resources/preserve-value-after-history-back-frame.html
index 177be07b..4540ab1 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/resources/preserve-value-after-history-back-frame.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/month-multiple-fields/resources/preserve-value-after-history-back-frame.html
@@ -4,7 +4,7 @@
 <input type="month" id="test2" min="1998-01" max="1999-12">
 <script>
 function fieldsText(input) {
-    return window.internals.shadowRoot(input).textContent;
+    return window.internals.oldestShadowRoot(input).textContent;
 }
 
 function back(newState) {
diff --git a/third_party/WebKit/LayoutTests/fast/forms/resources/common-clearbutton-change-and-input-events.js b/third_party/WebKit/LayoutTests/fast/forms/resources/common-clearbutton-change-and-input-events.js
index c3793e27..54723483 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/resources/common-clearbutton-change-and-input-events.js
+++ b/third_party/WebKit/LayoutTests/fast/forms/resources/common-clearbutton-change-and-input-events.js
@@ -26,7 +26,7 @@
 
     debug('Click the clear button');
     // Move the cursor on to the clear button.
-    var clearButton = getElementByPseudoId(internals.shadowRoot(testInput), "-webkit-clear-button");
+    var clearButton = getElementByPseudoId(internals.oldestShadowRoot(testInput), "-webkit-clear-button");
     eventSender.mouseMoveTo(clearButton.offsetLeft + clearButton.offsetWidth / 2, clearButton.offsetTop + clearButton.offsetHeight / 2);
     eventSender.mouseDown();
     eventSender.mouseUp();
diff --git a/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-change-and-input-events.js b/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-change-and-input-events.js
index 116d140..404031a6 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-change-and-input-events.js
+++ b/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-change-and-input-events.js
@@ -31,7 +31,7 @@
 
     debug('Click the upper button');
     // Move the cursor on the upper button.
-    var spinButton = getElementByPseudoId(internals.shadowRoot(testInput), "-webkit-inner-spin-button");
+    var spinButton = getElementByPseudoId(internals.oldestShadowRoot(testInput), "-webkit-inner-spin-button");
     var rect = spinButton.getBoundingClientRect();
     eventSender.mouseMoveTo(rect.left, rect.top + rect.height / 4);
     eventSender.mouseDown();
diff --git a/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-click-in-iframe.js b/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-click-in-iframe.js
index bb0b5778..03e8be11 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-click-in-iframe.js
+++ b/third_party/WebKit/LayoutTests/fast/forms/resources/common-spinbutton-click-in-iframe.js
@@ -7,7 +7,7 @@
 {
     if (!window.internals)
         return null;
-    return getElementByPseudoId(internals.shadowRoot(input), "-webkit-inner-spin-button");
+    return getElementByPseudoId(internals.oldestShadowRoot(input), "-webkit-inner-spin-button");
 }
 
 function mouseClick()
diff --git a/third_party/WebKit/LayoutTests/fast/forms/resources/common.js b/third_party/WebKit/LayoutTests/fast/forms/resources/common.js
index 03286df..848bbb1 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/resources/common.js
+++ b/third_party/WebKit/LayoutTests/fast/forms/resources/common.js
@@ -120,7 +120,7 @@
 }
 
 function getUserAgentShadowTextContent(element) {
-    return internals.shadowRoot(element).textContent;
+    return internals.youngestShadowRoot(element).textContent;
 };
 
 function cumulativeOffset(element) {
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/resources/preserve-value-after-history-back-frame.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/resources/preserve-value-after-history-back-frame.html
index ba1a3d7..e21a86fa 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/resources/preserve-value-after-history-back-frame.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/resources/preserve-value-after-history-back-frame.html
@@ -4,7 +4,7 @@
 <input type=time id=test2 step=1>
 <script>
 function fieldsText(input) {
-    return window.internals.shadowRoot(input).textContent;
+    return window.internals.oldestShadowRoot(input).textContent;
 }
 
 function back(newState) {
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-fallback-format.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-fallback-format.html
index 2b90ac0e6..a834c00 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-fallback-format.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-fallback-format.html
@@ -14,7 +14,7 @@
 
 function setDateTimeFormat(pattern) {
     var value = input.value;
-    getElementByPseudoId(internals.shadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
+    getElementByPseudoId(internals.youngestShadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
     input.value = ''; // Updates the element for new format
     input.value = value;
 }
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus-style.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus-style.html
index d4cbc6bc..0df2fab 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus-style.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus-style.html
@@ -28,7 +28,7 @@
 var highlight = sampleStyle.backgroundColor;
 
 testInput.focus();
-var shadowRoot = internals.shadowRoot(testInput);
+var shadowRoot = internals.oldestShadowRoot(testInput);
 var fields = getElementByPseudoId(shadowRoot, "-webkit-datetime-edit-fields-wrapper").childNodes;
 for (var index = 0; index < fields.length; ++index) {
     var field = fields[index];
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus.html
index b8240f7..b6c13407 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-focus.html
@@ -4,7 +4,7 @@
 <input id="timeInput" type="time" value="01:01" style="font-size:20px">
 <script>
 function shadowPseudoIdOfFocused() {
-    return internals.shadowPseudoId(internals.shadowRoot(timeInput).activeElement);
+    return internals.shadowPseudoId(internals.youngestShadowRoot(timeInput).activeElement);
 }
 
 description('Check if focus() for focused input does not change focused sub-field.');
@@ -18,7 +18,7 @@
 shouldBeEqualToString('timeInput.focus(); shadowPseudoIdOfFocused(timeInput)', '-webkit-datetime-edit-minute-field');
 
 debug('Click on a delimiter between sub-fields, then check if focused element is not changed:');
-var focusedField = internals.shadowRoot(timeInput).activeElement;
+var focusedField = internals.youngestShadowRoot(timeInput).activeElement;
 eventSender.mouseMoveTo(focusedField.offsetLeft + focusedField.offsetWidth + 10, focusedField.offsetTop + 10);
 eventSender.mouseDown();
 eventSender.mouseUp();
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-keyboard-events.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-keyboard-events.html
index cddfac1..23f1a17 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-keyboard-events.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-keyboard-events.html
@@ -28,7 +28,7 @@
 
 function shadowPseudoIdOfFocusedSubField(host)
 {
-    return internals.shadowPseudoId(internals.shadowRoot(host).activeElement);
+    return internals.shadowPseudoId(internals.youngestShadowRoot(host).activeElement);
 }
 
 function keyDown(key, modifiers)
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-narrow-width-scroll.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-narrow-width-scroll.html
index 3a697ed..1e13ad24 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-narrow-width-scroll.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-narrow-width-scroll.html
@@ -11,7 +11,7 @@
     debug('This test rquires DRT/WRT.');
 var time1 = $('time1');
 time1.focus();
-var container = getElementByPseudoId(internals.shadowRoot(time1), '-webkit-datetime-edit');
+var container = getElementByPseudoId(internals.oldestShadowRoot(time1), '-webkit-datetime-edit');
 var initialScrollLeft = container.scrollLeft;
 eventSender.keyDown('\t');
 shouldBeTrue('initialScrollLeft < container.scrollLeft');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-readonly-subfield.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-readonly-subfield.html
index a1a62dad..b0674a0 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-readonly-subfield.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-readonly-subfield.html
@@ -15,7 +15,7 @@
 
 // FIXME: Rename this function and the test file.
 function isReadOnlyField(input, pseudo) {
-    var node = internals.shadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
+    var node = internals.youngestShadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
     if (!node)
         testFailed('Requested node is missing.');
     return node && node.hasAttribute('disabled');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-stepup-stepdown-from-renderer-hour.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-stepup-stepdown-from-renderer-hour.html
index 58778d2..e37bae8 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-stepup-stepdown-from-renderer-hour.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-stepup-stepdown-from-renderer-hour.html
@@ -14,7 +14,7 @@
 input.focus();
 
 function setDateTimeFormat(pattern) {
-  getElementByPseudoId(internals.shadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
+  getElementByPseudoId(internals.youngestShadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
   input.value = '';  // Updates the element for new format
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-tabindex.html b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-tabindex.html
index e4bbec31..6cc8a87 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-tabindex.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/time-multiple-fields/time-multiple-fields-tabindex.html
@@ -20,7 +20,7 @@
 var shift = ['shiftKey'];
 
 $('tabindex10').focus();
-var shadowRoot = internals.shadowRoot($('time-with-tabindex20'));
+var shadowRoot = internals.youngestShadowRoot($('time-with-tabindex20'));
 
 debug('Forword:');
 shouldBeEqualToString('eventSender.keyDown(tab); document.activeElement.id', 'tabindex20-1');
diff --git a/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/resources/preserve-value-after-history-back-frame.html b/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/resources/preserve-value-after-history-back-frame.html
index 45b9c62..92bc53e 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/resources/preserve-value-after-history-back-frame.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/resources/preserve-value-after-history-back-frame.html
@@ -4,7 +4,7 @@
 <input type="week" id="test2" min="1998-W01" max="1999-W12">
 <script>
 function fieldsText(input) {
-    return window.internals.shadowRoot(input).textContent;
+    return window.internals.oldestShadowRoot(input).textContent;
 }
 
 function back(newState) {
diff --git a/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-fallback-format.html b/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-fallback-format.html
index f3b6865..87495d3 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-fallback-format.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-fallback-format.html
@@ -14,7 +14,7 @@
 
 function setDateTimeFormat(pattern) {
     var value = input.value;
-    getElementByPseudoId(internals.shadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
+    getElementByPseudoId(internals.youngestShadowRoot(input), '-webkit-datetime-edit').setAttribute('pattern', pattern);
     input.value = ''; // Updates the element for new format
     input.value = value;
 }
diff --git a/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-readonly-subfield.html b/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-readonly-subfield.html
index 9549e7f..5d8c09d2d 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-readonly-subfield.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/week-multiple-fields/week-multiple-fields-readonly-subfield.html
@@ -16,7 +16,7 @@
 
 // FIXME: Rename this function and the test file.
 function isReadOnlyField(input, pseudo) {
-    var node = internals.shadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
+    var node = internals.youngestShadowRoot(input).querySelector('*[pseudo="' + pseudo + '"]');
     if (!node)
         testFailed('Requested node is missing.');
     return node && node.hasAttribute('disabled');
diff --git a/third_party/WebKit/LayoutTests/fast/harness/results.html b/third_party/WebKit/LayoutTests/fast/harness/results.html
index 8881449..1f5a785 100644
--- a/third_party/WebKit/LayoutTests/fast/harness/results.html
+++ b/third_party/WebKit/LayoutTests/fast/harness/results.html
@@ -1263,8 +1263,7 @@
   },
 
   printSummary: function (fullResults) {
-    if (fullResults.builder_name)
-      document.querySelector("#builder_name").innerText = fullResults.builder_name;
+    document.querySelector("#builder_name").innerText = fullResults.builder_name || document.lastModified;
     document.querySelector("#summary_passed").innerText = fullResults.num_passes;
     document.querySelector("#summary_regressions").innerText = fullResults.num_regressions;
     let failures = fullResults["num_failures_by_type"];
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.respond-to-same-origin-request-with-cross-origin-response.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.respond-to-same-origin-request-with-cross-origin-response.html
deleted file mode 100644
index 9f47eea..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.respond-to-same-origin-request-with-cross-origin-response.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<!-- This test requires internals because it tests Chromium's
-  internal UseCounter. See https://crbug.com/784018. -->
-<title>Service Worker: Respond to same-origin request with cross origin response</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/get-host-info.js"></script>
-<script src="resources/test-helpers.js"></script>
-<script>
-
-promise_test((t) => {
-    const url = 'resources/fetch-rewrite-worker.js';
-    const scope = 'resources/blank.html?' +
-                  'respond-to-same-origin-request-with-cross-origin-response';
-    const host_info = get_host_info();
-    const target_url = host_info['HTTPS_REMOTE_ORIGIN'] +
-                       base_path() +
-                       '/resources/fetch-access-control.php?ACAOrigin=*';
-    // from web_feature.mojom
-    const kRespondToSameOriginRequestWithCrossOriginResponse = 2231;
-    let worker;
-    let frame;
-    return service_worker_unregister_and_register(t, url, scope)
-      .then((registration) => {
-          add_completion_callback(() => registration.unregister());
-          worker = registration.installing;
-          return wait_for_state(t, worker, 'activated');
-        })
-      .then(() => with_iframe(scope))
-      .then((f) => {
-          frame = f;
-          assert_false(
-              frame.contentWindow.internals.isUseCounted(
-                  frame.contentDocument,
-                  kRespondToSameOriginRequestWithCrossOriginResponse),
-              'The usecounter must not be counted yet.');
-          add_completion_callback(() => frame.remove());
-          return frame.contentWindow.fetch(
-            './?url=' + encodeURIComponent(target_url) +
-            '&mode=cors', {mode: 'same-origin'});
-        })
-      .then(() => {
-          assert_true(
-              frame.contentWindow.internals.isUseCounted(
-                  frame.contentDocument,
-                  kRespondToSameOriginRequestWithCrossOriginResponse),
-              'The usecounter must be counted.');
-        });
-  }, 'Usecounter for RespondToSameOriginRequestWithCrossOriginResponse');
-
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.respond-to-same-origin-request-with-redirected-cross-origin-response.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.respond-to-same-origin-request-with-redirected-cross-origin-response.html
deleted file mode 100644
index bef7654..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium.respond-to-same-origin-request-with-redirected-cross-origin-response.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<!-- This test requires internals because it tests Chromium's
-  internal UseCounter. See https://crbug.com/784018. -->
-<title>Service Worker: Respond to same-origin request with redirected cross origin response</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/get-host-info.js"></script>
-<script src="resources/test-helpers.js"></script>
-<script>
-
-promise_test((t) => {
-  const url = 'resources/fetch-rewrite-worker.js';
-  const scope =
-        'resources/blank.html?' +
-        'respond-to-same-origin-request-with-redirected-cross-origin-response';
-  const host_info = get_host_info();
-  const target_url = host_info['HTTPS_REMOTE_ORIGIN'] +
-                     base_path() +
-                     '/resources/fetch-access-control.php?ACAOrigin=*';
-  const redirect_url = host_info['HTTP_ORIGIN'] +
-                       '/serviceworker/resources/redirect.php?Redirect=' +
-                       encodeURIComponent(target_url);
-  // from web_feature.mojom
-  const kRespondToSameOriginRequestWithCrossOriginResponse = 2231;
-  let worker;
-  let frame;
-  return service_worker_unregister_and_register(t, url, scope)
-    .then((registration) => {
-        add_completion_callback(() => registration.unregister());
-        worker = registration.installing;
-        return wait_for_state(t, worker, 'activated');
-      })
-    .then(() => with_iframe(scope))
-    .then((f) => {
-        frame = f;
-        assert_false(
-            frame.contentWindow.internals.isUseCounted(
-                frame.contentDocument,
-                kRespondToSameOriginRequestWithCrossOriginResponse),
-            'The usecounter must not be counted yet.');
-        add_completion_callback(() => frame.remove());
-        return frame.contentWindow.fetch(
-          './?url=' + encodeURIComponent(redirect_url) +
-          '&mode=cors', {mode: 'same-origin'});
-      })
-    .then(() => {
-        assert_true(
-            frame.contentWindow.internals.isUseCounted(
-                frame.contentDocument,
-                kRespondToSameOriginRequestWithCrossOriginResponse),
-            'The usecounter must be counted.');
-        });
-}, 'Usecounter for RespondToSameOriginRequestWithCrossOriginResponse for ' +
-   'redirected response');
-
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/svg/as-object/intrinsic-size-change-embedded-object.html b/third_party/WebKit/LayoutTests/http/tests/svg/as-object/intrinsic-size-change-embedded-object.html
new file mode 100644
index 0000000..dafac349
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/svg/as-object/intrinsic-size-change-embedded-object.html
@@ -0,0 +1,15 @@
+<!doctype HTML>
+<script src="../../../../resources/testharness.js"></script>
+<script src="../../../../resources/testharnessreport.js"></script>
+<div style="width: 400px; height: 300px;">
+  <object id=target style="border: 1px solid black"
+      data="http://localhost:8000/svg/as-object/resources/objectcontents.svg"></object>
+</div>
+<script>
+var t = async_test("objectsize");
+onload = t.step_func_done(function() {
+    let rect = target.getBoundingClientRect();
+    assert_equals(rect.width, 400);
+    assert_equals(rect.height, 798);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/svg/as-object/resources/objectcontents.svg b/third_party/WebKit/LayoutTests/http/tests/svg/as-object/resources/objectcontents.svg
new file mode 100644
index 0000000..cf29f0d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/svg/as-object/resources/objectcontents.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 200"/>
diff --git a/third_party/WebKit/LayoutTests/media/media-controls.js b/third_party/WebKit/LayoutTests/media/media-controls.js
index e65cf81..380f8283 100644
--- a/third_party/WebKit/LayoutTests/media/media-controls.js
+++ b/third_party/WebKit/LayoutTests/media/media-controls.js
@@ -342,7 +342,7 @@
 function checkPictureInPictureInterstitialDoesNotExist(videoElement) {
   var controlID = '-internal-picture-in-picture-interstitial';
 
-  var interstitial = getElementByPseudoId(internals.shadowRoot(videoElement), controlID);
+  var interstitial = getElementByPseudoId(internals.oldestShadowRoot(videoElement), controlID);
   if (interstitial)
       throw 'Should not have a picture in picture interstitial';
 }
@@ -430,4 +430,4 @@
         node = traverseNextNode(node, root);
     }
     return null;
-}
+}
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/resources/focus-utils.js b/third_party/WebKit/LayoutTests/shadow-dom/resources/focus-utils.js
index 5c3f471..5f2c5e63 100644
--- a/third_party/WebKit/LayoutTests/shadow-dom/resources/focus-utils.js
+++ b/third_party/WebKit/LayoutTests/shadow-dom/resources/focus-utils.js
@@ -8,10 +8,11 @@
     return element;
   }
   if (isShadowHost(element)) {
-    let shadowRoot = window.internals.shadowRoot(element);
-    if (shadowRoot) {
+    let shadowRoot = window.internals.oldestShadowRoot(element);
+    while (shadowRoot) {
       if (shadowRoot.activeElement)
         return innermostActiveElement(shadowRoot.activeElement);
+      shadowRoot = window.internals.youngerShadowRoot(shadowRoot);
     }
   }
   return element;
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/v0/closed-mode-deep-combinator-and-shadow-pseudo-expected.txt b/third_party/WebKit/LayoutTests/shadow-dom/v0/closed-mode-deep-combinator-and-shadow-pseudo-expected.txt
index 95117d9f..1186371 100644
--- a/third_party/WebKit/LayoutTests/shadow-dom/v0/closed-mode-deep-combinator-and-shadow-pseudo-expected.txt
+++ b/third_party/WebKit/LayoutTests/shadow-dom/v0/closed-mode-deep-combinator-and-shadow-pseudo-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE WARNING: line 306: /deep/ combinator is no longer supported in CSS dynamic profile.It is now effectively no-op, acting as if it were a descendant combinator. /deep/ combinator will be removed, and will be invalid at M65. You should remove it. See https://www.chromestatus.com/features/4964279606312960 for more details.
+CONSOLE WARNING: line 311: /deep/ combinator is no longer supported in CSS dynamic profile.It is now effectively no-op, acting as if it were a descendant combinator. /deep/ combinator will be removed, and will be invalid at M65. You should remove it. See https://www.chromestatus.com/features/4964279606312960 for more details.
 (1/6) /deep/ style rule on top-level document.
 PASS backgroundColorOf('host_open_open') is "rgba(0, 0, 0, 0)"
 PASS backgroundColorOf('host_open_open/div1') is "rgba(0, 0, 0, 0)"
diff --git a/third_party/WebKit/LayoutTests/virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/README.txt b/third_party/WebKit/LayoutTests/virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/README.txt
new file mode 100644
index 0000000..ddc7d0a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/sharedarraybuffer/external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/README.txt
@@ -0,0 +1,3 @@
+# This suite runs the tests in with --js-flags=--harmony-sharedarraybuffer
+# This enables the SharedArrayBuffer language feature in V8.
+# See https://github.com/tc39/ecmascript_sharedmem for more information.
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/fast/borders/inline-mask-overlay-image-outset-expected.png b/third_party/WebKit/LayoutTests/virtual/spv175/fast/borders/inline-mask-overlay-image-outset-expected.png
deleted file mode 100644
index b0c4012..0000000
--- a/third_party/WebKit/LayoutTests/virtual/spv175/fast/borders/inline-mask-overlay-image-outset-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp
index c8fbe34d..de49503 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp
@@ -370,6 +370,24 @@
       TransferArrayBufferContents(isolate, array_buffers, exception_state);
 }
 
+void SerializedScriptValue::CloneSharedArrayBuffers(
+    SharedArrayBufferArray& array_buffers) {
+  if (!array_buffers.size())
+    return;
+
+  HeapHashSet<Member<DOMArrayBufferBase>> visited;
+  shared_array_buffers_contents_.Grow(array_buffers.size());
+  size_t i = 0;
+  for (auto it = array_buffers.begin(); it != array_buffers.end(); ++it) {
+    DOMSharedArrayBuffer* shared_array_buffer = *it;
+    if (visited.Contains(shared_array_buffer))
+      continue;
+    visited.insert(shared_array_buffer);
+    shared_array_buffer->ShareContentsWith(shared_array_buffers_contents_[i]);
+    i++;
+  }
+}
+
 v8::Local<v8::Value> SerializedScriptValue::Deserialize(
     v8::Isolate* isolate,
     const DeserializeOptions& options) {
@@ -391,6 +409,7 @@
 
 bool SerializedScriptValue::HasPackedContents() const {
   return !array_buffer_contents_array_.IsEmpty() ||
+         !shared_array_buffers_contents_.IsEmpty() ||
          !image_bitmap_contents_array_.IsEmpty();
 }
 
@@ -535,15 +554,10 @@
 
     size_t index = std::distance(array_buffers.begin(), it);
     if (array_buffer_base->IsShared()) {
-      DOMSharedArrayBuffer* shared_array_buffer =
-          static_cast<DOMSharedArrayBuffer*>(array_buffer_base);
-      if (!shared_array_buffer->ShareContentsWith(contents.at(index))) {
-        exception_state.ThrowDOMException(kDataCloneError,
-                                          "SharedArrayBuffer at index " +
-                                              String::Number(index) +
-                                              " could not be transferred.");
-        return ArrayBufferContentsArray();
-      }
+      exception_state.ThrowDOMException(
+          kDataCloneError, "SharedArrayBuffer at index " +
+                               String::Number(index) + " is not transferable.");
+      return ArrayBufferContentsArray();
     } else {
       DOMArrayBuffer* array_buffer =
           static_cast<DOMArrayBuffer*>(array_buffer_base);
@@ -572,6 +586,8 @@
   if (!transferables_need_external_allocation_registration_) {
     for (auto& buffer : array_buffer_contents_array_)
       buffer.UnregisterExternalAllocationWithCurrentContext();
+    for (auto& buffer : shared_array_buffers_contents_)
+      buffer.UnregisterExternalAllocationWithCurrentContext();
     transferables_need_external_allocation_registration_ = true;
   }
 }
@@ -590,6 +606,8 @@
   if (transferables_need_external_allocation_registration_) {
     for (auto& buffer : array_buffer_contents_array_)
       buffer.RegisterExternalAllocationWithCurrentContext();
+    for (auto& buffer : shared_array_buffers_contents_)
+      buffer.RegisterExternalAllocationWithCurrentContext();
   }
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h
index 6761d245..29279ad 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h
@@ -56,14 +56,17 @@
 class StaticBitmapImage;
 class UnpackedSerializedScriptValue;
 class WebBlobInfo;
+class DOMSharedArrayBuffer;
 
 typedef HashMap<String, scoped_refptr<BlobDataHandle>> BlobDataHandleMap;
 typedef Vector<WebBlobInfo> WebBlobInfoArray;
+typedef HeapVector<Member<DOMSharedArrayBuffer>> SharedArrayBufferArray;
 
 class CORE_EXPORT SerializedScriptValue
     : public ThreadSafeRefCounted<SerializedScriptValue> {
  public:
   using ArrayBufferContentsArray = Vector<WTF::ArrayBufferContents, 1>;
+  using SharedArrayBufferContentsArray = Vector<WTF::ArrayBufferContents, 1>;
   using ImageBitmapContentsArray = Vector<scoped_refptr<StaticBitmapImage>, 1>;
   using TransferredWasmModulesArray =
       WTF::Vector<v8::WasmCompiledModule::TransferrableModule>;
@@ -224,6 +227,9 @@
   size_t DataLengthInBytes() const { return data_buffer_size_; }
 
   TransferredWasmModulesArray& WasmModules() { return wasm_modules_; }
+  SharedArrayBufferContentsArray& SharedArrayBuffersContents() {
+    return shared_array_buffers_contents_;
+  }
   BlobDataHandleMap& BlobDataHandles() { return blob_data_handles_; }
 
  private:
@@ -255,7 +261,7 @@
   void TransferOffscreenCanvas(v8::Isolate*,
                                const OffscreenCanvasArray&,
                                ExceptionState&);
-
+  void CloneSharedArrayBuffers(SharedArrayBufferArray&);
   DataBufferPtr data_buffer_;
   size_t data_buffer_size_ = 0;
 
@@ -267,6 +273,7 @@
   // These do not have one-use transferred contents, like the above.
   TransferredWasmModulesArray wasm_modules_;
   BlobDataHandleMap blob_data_handles_;
+  SharedArrayBufferContentsArray shared_array_buffers_contents_;
 
   bool has_registered_external_allocation_;
   bool transferables_need_external_allocation_registration_;
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
index eaa5826..6ec4ee67 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
@@ -612,4 +612,30 @@
   return v8::MaybeLocal<v8::WasmCompiledModule>();
 }
 
+v8::MaybeLocal<v8::SharedArrayBuffer>
+V8ScriptValueDeserializer::GetSharedArrayBufferFromId(v8::Isolate* isolate,
+                                                      uint32_t id) {
+  auto& shared_array_buffers_contents =
+      serialized_script_value_->SharedArrayBuffersContents();
+  if (id < shared_array_buffers_contents.size()) {
+    WTF::ArrayBufferContents& contents = shared_array_buffers_contents.at(id);
+    DOMSharedArrayBuffer* shared_array_buffer =
+        DOMSharedArrayBuffer::Create(contents);
+    v8::Local<v8::Object> creation_context =
+        script_state_->GetContext()->Global();
+    v8::Local<v8::Value> wrapper =
+        ToV8(shared_array_buffer, creation_context, isolate);
+    DCHECK(wrapper->IsSharedArrayBuffer());
+    return v8::Local<v8::SharedArrayBuffer>::Cast(wrapper);
+  }
+  ExceptionState exception_state(isolate, ExceptionState::kUnknownContext,
+                                 nullptr, nullptr);
+  exception_state.ThrowDOMException(kDataCloneError,
+                                    "Unable to deserialize SharedArrayBuffer.");
+  // If the id does not map to a valid index, it is expected that the
+  // SerializedScriptValue emptied its shared ArrayBufferContents when crossing
+  // a process boundary.
+  CHECK(shared_array_buffers_contents.IsEmpty());
+  return v8::MaybeLocal<v8::SharedArrayBuffer>();
+}
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.h b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.h
index 3e01a1f9..73cc88c5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.h
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.h
@@ -99,6 +99,9 @@
   v8::MaybeLocal<v8::Object> ReadHostObject(v8::Isolate*) override;
   v8::MaybeLocal<v8::WasmCompiledModule> GetWasmModuleFromId(v8::Isolate*,
                                                              uint32_t) override;
+  v8::MaybeLocal<v8::SharedArrayBuffer> GetSharedArrayBufferFromId(
+      v8::Isolate*,
+      uint32_t) override;
 
   scoped_refptr<ScriptState> script_state_;
   Member<UnpackedSerializedScriptValue> unpacked_value_;
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp
index ba4ae128..afb4c2c 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.cpp
@@ -102,6 +102,8 @@
   if (exception_state.HadException())
     return nullptr;
 
+  serialized_script_value_->CloneSharedArrayBuffers(shared_array_buffers_);
+
   // Finalize the results.
   std::pair<uint8_t*, size_t> buffer = serializer_.Release();
   serialized_script_value_->SetData(
@@ -136,12 +138,9 @@
 
   v8::Isolate* isolate = script_state_->GetIsolate();
 
-  // The order of ArrayBuffers and SharedArrayBuffers matters; we use the index
-  // into this array for deserialization.
   ArrayBufferArray array_buffers;
   if (transferables_)
     array_buffers.AppendVector(transferables_->array_buffers);
-  array_buffers.AppendVector(shared_array_buffers_);
 
   if (!array_buffers.IsEmpty()) {
     serialized_script_value_->TransferArrayBuffers(isolate, array_buffers,
@@ -528,23 +527,12 @@
 
   // The index returned from this function will be serialized into the data
   // stream. When deserializing, this will be used to index into the
-  // arrayBufferContents array of the SerializedScriptValue.
-  //
-  // The v8::ValueSerializer will use the same index space for transferred
-  // ArrayBuffers, but those will all occur first, because their indexes are
-  // generated in order via v8::ValueSerializer::TransferArrayBuffer (see
-  // prepareTransfer above).
-  //
-  // So we offset all SharedArrayBuffer indexes by the number of transferred
-  // ArrayBuffers.
+  // sharedArrayBufferContents array of the SerializedScriptValue.
   size_t index = shared_array_buffers_.Find(shared_array_buffer);
   if (index == kNotFound) {
     shared_array_buffers_.push_back(shared_array_buffer);
     index = shared_array_buffers_.size() - 1;
   }
-  if (transferables_) {
-    index += transferables_->array_buffers.size();
-  }
   return v8::Just<uint32_t>(index);
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h
index 16c0935..17c9996 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueSerializer.h
@@ -105,7 +105,7 @@
   const Transferables* transferables_ = nullptr;
   const ExceptionState* exception_state_ = nullptr;
   WebBlobInfoArray* blob_info_array_ = nullptr;
-  ArrayBufferArray shared_array_buffers_;
+  SharedArrayBufferArray shared_array_buffers_;
   Options::WasmSerializationPolicy wasm_policy_;
   bool for_storage_ = false;
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/bindings/scripts/idl_definitions.py b/third_party/WebKit/Source/bindings/scripts/idl_definitions.py
index f2f0e543..b333dee9 100644
--- a/third_party/WebKit/Source/bindings/scripts/idl_definitions.py
+++ b/third_party/WebKit/Source/bindings/scripts/idl_definitions.py
@@ -71,7 +71,7 @@
 from idl_types import IdlType
 from idl_types import IdlUnionType
 
-SPECIAL_KEYWORD_LIST = ['LEGACYCALLER', 'GETTER', 'SETTER', 'DELETER']
+SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER']
 
 
 ################################################################################
diff --git a/third_party/WebKit/Source/bindings/scripts/overload_set_algorithm.py b/third_party/WebKit/Source/bindings/scripts/overload_set_algorithm.py
index 6425a84..6e819d5 100644
--- a/third_party/WebKit/Source/bindings/scripts/overload_set_algorithm.py
+++ b/third_party/WebKit/Source/bindings/scripts/overload_set_algorithm.py
@@ -32,7 +32,7 @@
     Formally:
     An effective overload set represents the allowable invocations for a
     particular operation, constructor (specified with [Constructor] or
-    [NamedConstructor]), legacy caller or callback function.
+    [NamedConstructor]), or callback function.
 
     An additional argument N (argument count) is needed when overloading
     variadics, but we don't use that currently.
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_interface.py b/third_party/WebKit/Source/bindings/scripts/v8_interface.py
index 887374c..385c6e4 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_interface.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_interface.py
@@ -453,7 +453,6 @@
     })
 
     context.update({
-        'legacy_caller': legacy_caller(interface.legacy_caller, interface),
         'indexed_property_getter': property_getter(interface.indexed_property_getter, ['index']),
         'indexed_property_setter': property_setter(interface.indexed_property_setter, interface),
         'indexed_property_deleter': property_deleter(interface.indexed_property_deleter),
@@ -1383,12 +1382,6 @@
 # http://heycam.github.io/webidl/#idl-special-operations
 ################################################################################
 
-def legacy_caller(caller, interface):
-    if not caller:
-        return None
-
-    return v8_methods.method_context(interface, caller)
-
 def property_getter(getter, cpp_arguments):
     if not getter:
         return None
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_utilities.py b/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
index 0a05b80..ab27d73 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
@@ -536,27 +536,6 @@
 
 
 ################################################################################
-# Legacy callers
-# https://heycam.github.io/webidl/#idl-legacy-callers
-################################################################################
-
-def legacy_caller(interface):
-    try:
-        # Find legacy caller, if present; has form:
-        # legacycaller TYPE [OPTIONAL_IDENTIFIER](OPTIONAL_ARGUMENTS)
-        caller = next(
-            method
-            for method in interface.operations
-            if 'legacycaller' in method.specials)
-        if not caller.name:
-            raise Exception('legacycaller with no identifier is not supported: '
-                            '%s' % interface.name)
-        return caller
-    except StopIteration:
-        return None
-
-
-################################################################################
 # Indexed properties
 # http://heycam.github.io/webidl/#idl-indexed-properties
 ################################################################################
@@ -652,7 +631,6 @@
         return None
 
 
-IdlInterface.legacy_caller = property(legacy_caller)
 IdlInterface.indexed_property_getter = property(indexed_property_getter)
 IdlInterface.indexed_property_setter = property(indexed_property_setter)
 IdlInterface.indexed_property_deleter = property(indexed_property_deleter)
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/idl_definition_builder.py b/third_party/WebKit/Source/bindings/scripts/web_idl/idl_definition_builder.py
index 45d40a8..fbfb93a 100644
--- a/third_party/WebKit/Source/bindings/scripts/web_idl/idl_definition_builder.py
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/idl_definition_builder.py
@@ -296,7 +296,7 @@
         identifier = node.GetName()
         is_static = bool(node.GetProperty('STATIC'))
         properties = node.GetProperties()
-        for special_keyword in ['DELETER', 'GETTER', 'LEGACYCALLER', 'SETTER']:
+        for special_keyword in ['DELETER', 'GETTER', 'SETTER']:
             if special_keyword in properties:
                 special_keywords.append(special_keyword.lower())
 
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/operation.py b/third_party/WebKit/Source/bindings/scripts/web_idl/operation.py
index ab56382..df46bc2 100644
--- a/third_party/WebKit/Source/bindings/scripts/web_idl/operation.py
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/operation.py
@@ -9,7 +9,7 @@
 # https://heycam.github.io/webidl/#idl-operations
 class Operation(object):
     # https://www.w3.org/TR/WebIDL-1/#idl-special-operations
-    _SPECIAL_KEYWORDS = frozenset(['deleter', 'getter', 'legacycaller', 'setter', 'stringifier', 'serializer'])
+    _SPECIAL_KEYWORDS = frozenset(['deleter', 'getter', 'setter', 'stringifier', 'serializer'])
 
     def __init__(self, **kwargs):
         self._identifier = kwargs.pop('identifier')
diff --git a/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl
index f8717ce..c46136a 100644
--- a/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/interface_base.cpp.tmpl
@@ -644,9 +644,7 @@
                             v8::ReadOnly | v8::DontEnum | v8::DontDelete));
   {% endif %}
 
-  {% if legacy_caller and not is_partial %}
-  instanceTemplate->SetCallAsFunctionHandler({{cpp_class_or_partial}}V8Internal::{{legacy_caller.name}}MethodCallback);
-  {% elif has_custom_legacy_call_as_function and not is_partial %}
+  {% if has_custom_legacy_call_as_function and not is_partial %}
   instanceTemplate->SetCallAsFunctionHandler({{v8_class}}::legacyCallCustom);
   {% endif %}
 
diff --git a/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface2.idl b/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface2.idl
index 921a2b4..39f0c26 100644
--- a/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface2.idl
+++ b/third_party/WebKit/Source/bindings/tests/idls/core/TestInterface2.idl
@@ -43,9 +43,6 @@
     // This interface has only runtime enabled constants.
     [RuntimeEnabled=FeatureName] const unsigned short CONST_VALUE_1 = 1;
 
-    // Legacy caller with an identifier
-    legacycaller TestInterfaceEmpty legacyCaller(unsigned long index);
-
     // Indexed property operations with an identifier
     [RaisesException] getter TestInterfaceEmpty item(unsigned long index);
     [RaisesException] setter TestInterfaceEmpty setItem(unsigned long index, TestInterfaceEmpty value);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.cpp
index d9ff12c..f05483bf6 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.cpp
@@ -76,24 +76,6 @@
   V8SetReturnValueUnsigned(info, impl->size());
 }
 
-static void legacyCallerMethod(const v8::FunctionCallbackInfo<v8::Value>& info) {
-  ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "TestInterface2", "legacyCaller");
-
-  TestInterface2* impl = V8TestInterface2::ToImpl(info.Holder());
-
-  if (UNLIKELY(info.Length() < 1)) {
-    exceptionState.ThrowTypeError(ExceptionMessages::NotEnoughArguments(1, info.Length()));
-    return;
-  }
-
-  uint32_t index;
-  index = NativeValueTraits<IDLUnsignedLong>::NativeValue(info.GetIsolate(), info[0], exceptionState, kNormalConversion);
-  if (exceptionState.HadException())
-    return;
-
-  V8SetReturnValue(info, impl->legacyCaller(index));
-}
-
 static void itemMethod(const v8::FunctionCallbackInfo<v8::Value>& info) {
   ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "TestInterface2", "item");
 
@@ -510,12 +492,6 @@
   TestInterface2V8Internal::sizeAttributeGetter(info);
 }
 
-void V8TestInterface2::legacyCallerMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
-  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestInterface2_legacyCaller");
-
-  TestInterface2V8Internal::legacyCallerMethod(info);
-}
-
 void V8TestInterface2::itemMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
   RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestInterface2_item");
 
@@ -681,7 +657,6 @@
 };
 
 static const V8DOMConfiguration::MethodConfiguration V8TestInterface2Methods[] = {
-    {"legacyCaller", V8TestInterface2::legacyCallerMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kAllWorlds},
     {"item", V8TestInterface2::itemMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kAllWorlds},
     {"setItem", V8TestInterface2::setItemMethodCallback, 2, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kAllWorlds},
     {"deleteItem", V8TestInterface2::deleteItemMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kAllWorlds},
@@ -766,8 +741,6 @@
   };
   V8DOMConfiguration::InstallMethod(isolate, world, prototypeTemplate, signature, symbolKeyedIteratorConfiguration);
 
-  instanceTemplate->SetCallAsFunctionHandler(TestInterface2V8Internal::legacyCallerMethodCallback);
-
   // Custom signature
 }
 
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.h b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.h
index e472e3ee..6a420832 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface2.h
@@ -57,7 +57,6 @@
 
   CORE_EXPORT static void sizeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);
 
-  CORE_EXPORT static void legacyCallerMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
   CORE_EXPORT static void itemMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
   CORE_EXPORT static void setItemMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
   CORE_EXPORT static void deleteItemMethodCallback(const v8::FunctionCallbackInfo<v8::Value>&);
diff --git a/third_party/WebKit/Source/core/DEPS b/third_party/WebKit/Source/core/DEPS
index 7e05d30..26a4725 100644
--- a/third_party/WebKit/Source/core/DEPS
+++ b/third_party/WebKit/Source/core/DEPS
@@ -41,5 +41,9 @@
     ".*Test\.cpp" : [
         "+core/frame/WebLocalFrameImpl.h",
         "+core/frame/WebRemoteFrameImpl.h",
+    ],
+    # Allow LocalFrame.cpp to use WebLocalFrameImpl.h
+    "LocalFrame.cpp" : [
+        "+core/frame/WebLocalFrameImpl.h",
     ]
 }
diff --git a/third_party/WebKit/Source/core/css/SelectorQuery.cpp b/third_party/WebKit/Source/core/css/SelectorQuery.cpp
index 67cd6bf..f712079b 100644
--- a/third_party/WebKit/Source/core/css/SelectorQuery.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorQuery.cpp
@@ -336,6 +336,10 @@
     ShadowRoot* shadow_root = current->ContainingShadowRoot();
     if (shadow_root == root_node)
       return nullptr;
+    if (ShadowRoot* younger_shadow_root = shadow_root->YoungerShadowRoot()) {
+      DCHECK(younger_shadow_root->IsOpenOrV0());
+      return younger_shadow_root;
+    }
 
     current = &shadow_root->host();
   }
diff --git a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
index af99cc9..6165d79 100644
--- a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
@@ -342,10 +342,11 @@
     Element& element,
     RecursionData& recursion_data) {
   bool some_children_need_style_recalc = false;
-  if (ShadowRoot* root = element.GetShadowRoot()) {
+  for (ShadowRoot* root = element.YoungestShadowRoot(); root;
+       root = root->OlderShadowRoot()) {
     if (!recursion_data.TreeBoundaryCrossing() &&
         !root->ChildNeedsStyleInvalidation() && !root->NeedsStyleInvalidation())
-      return false;
+      continue;
     RecursionCheckpoint checkpoint(&recursion_data);
     SiblingData sibling_data;
     if (UNLIKELY(root->NeedsStyleInvalidation()))
@@ -366,7 +367,7 @@
                                           RecursionData& recursion_data) {
   SiblingData sibling_data;
   bool some_children_need_style_recalc = false;
-  if (UNLIKELY(!!element.GetShadowRoot())) {
+  if (UNLIKELY(!!element.YoungestShadowRoot())) {
     some_children_need_style_recalc =
         InvalidateShadowRootChildren(element, recursion_data);
   }
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 3f2da247..2a21883f 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -912,7 +912,8 @@
     if (Node::kInsertionShouldCallDidNotifySubtreeInsertions ==
         node.InsertedInto(this))
       post_insertion_notification_targets.push_back(&node);
-    if (ShadowRoot* shadow_root = node.GetShadowRoot())
+    for (ShadowRoot* shadow_root = node.YoungestShadowRoot(); shadow_root;
+         shadow_root = shadow_root->OlderShadowRoot())
       NotifyNodeInsertedInternal(*shadow_root,
                                  post_insertion_notification_targets);
   }
@@ -929,7 +930,8 @@
     if (!node.IsContainerNode() && !node.IsInTreeScope())
       continue;
     node.RemovedFrom(this);
-    if (ShadowRoot* shadow_root = node.GetShadowRoot())
+    for (ShadowRoot* shadow_root = node.YoungestShadowRoot(); shadow_root;
+         shadow_root = shadow_root->OlderShadowRoot())
       NotifyNodeRemoved(*shadow_root);
   }
 }
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index c9a921b..9a7a4993 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -2110,7 +2110,8 @@
     DCHECK(!node.ChildNeedsDistributionRecalc());
     DCHECK(!node.NeedsStyleInvalidation());
     DCHECK(!node.ChildNeedsStyleInvalidation());
-    if (ShadowRoot* shadow_root = node.GetShadowRoot())
+    for (ShadowRoot* shadow_root = node.YoungestShadowRoot(); shadow_root;
+         shadow_root = shadow_root->OlderShadowRoot())
       AssertLayoutTreeUpdated(*shadow_root);
   }
 }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index cf6ea960..467f2fd7 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2065,7 +2065,8 @@
     UpdatePseudoElement(kPseudoIdBefore, change);
 
     if (change > kUpdatePseudoElements || ChildNeedsStyleRecalc()) {
-      if (ShadowRoot* root = GetShadowRoot()) {
+      for (ShadowRoot* root = YoungestShadowRoot(); root;
+           root = root->OlderShadowRoot()) {
         if (root->ShouldCallRecalcStyle(change))
           root->RecalcStyle(change);
       }
@@ -2222,8 +2223,10 @@
 }
 
 void Element::RecalcShadowRootStylesForReattach() {
-  if (ShadowRoot* root = GetShadowRoot())
+  for (ShadowRoot* root = YoungestShadowRoot(); root;
+       root = root->OlderShadowRoot()) {
     root->RecalcStylesForReattach();
+  }
 }
 
 void Element::RebuildLayoutTree(WhitespaceAttacher& whitespace_attacher) {
@@ -2274,8 +2277,10 @@
 void Element::RebuildShadowRootLayoutTree(
     WhitespaceAttacher& whitespace_attacher) {
   DCHECK(Shadow());
-  if (ShadowRoot* root = GetShadowRoot())
+  for (ShadowRoot* root = YoungestShadowRoot(); root;
+       root = root->OlderShadowRoot()) {
     root->RebuildLayoutTree(whitespace_attacher);
+  }
   RebuildNonDistributedChildren();
 }
 
@@ -2521,6 +2526,13 @@
   return shadow_root;
 }
 
+ShadowRoot* Element::GetShadowRoot() const {
+  ElementShadow* element_shadow = Shadow();
+  if (!element_shadow)
+    return nullptr;
+  return &element_shadow->GetShadowRoot();
+}
+
 ShadowRoot* Element::OpenShadowRoot() const {
   ShadowRoot* root = GetShadowRoot();
   if (!root)
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index 2c52e015..951ae9f 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -502,12 +502,13 @@
   ShadowRoot& AttachShadowRootInternal(ShadowRootType,
                                        bool delegates_focus = false);
 
-  ShadowRoot* GetShadowRoot() const;
   ShadowRoot* OpenShadowRoot() const;
   ShadowRoot* ClosedShadowRoot() const;
   ShadowRoot* AuthorShadowRoot() const;
   ShadowRoot* UserAgentShadowRoot() const;
 
+  ShadowRoot* YoungestShadowRoot() const;
+
   ShadowRoot* ShadowRootIfV1() const;
 
   ShadowRoot& EnsureUserAgentShadowRoot();
@@ -954,6 +955,8 @@
   inline PseudoElement* CreatePseudoElementIfNeeded(PseudoId);
   void CreateAndAttachPseudoElementIfNeeded(PseudoId, AttachContext&);
 
+  ShadowRoot* GetShadowRoot() const;
+
   // FIXME: Everyone should allow author shadows.
   virtual bool AreAuthorShadowsAllowed() const { return true; }
   virtual void DidAddUserAgentShadowRoot(ShadowRoot&) {}
diff --git a/third_party/WebKit/Source/core/dom/ElementShadow.h b/third_party/WebKit/Source/core/dom/ElementShadow.h
index c13a5b0..f5d4840 100644
--- a/third_party/WebKit/Source/core/dom/ElementShadow.h
+++ b/third_party/WebKit/Source/core/dom/ElementShadow.h
@@ -87,25 +87,18 @@
   DISALLOW_COPY_AND_ASSIGN(ElementShadow);
 };
 
-inline ShadowRoot* Node::GetShadowRoot() const {
+inline ShadowRoot* Node::YoungestShadowRoot() const {
   if (!IsElementNode())
     return nullptr;
-  return ToElement(this)->GetShadowRoot();
+  return ToElement(this)->YoungestShadowRoot();
 }
 
-inline ShadowRoot* Element::GetShadowRoot() const {
+inline ShadowRoot* Element::YoungestShadowRoot() const {
   if (ElementShadow* shadow = Shadow())
     return &shadow->GetShadowRoot();
   return nullptr;
 }
 
-inline ShadowRoot* Element::ShadowRootIfV1() const {
-  ShadowRoot* root = GetShadowRoot();
-  if (root && root->IsV1())
-    return root;
-  return nullptr;
-}
-
 inline ElementShadow* ElementShadow::ContainingShadow() const {
   if (ShadowRoot* parent_root = Host().ContainingShadowRoot())
     return parent_root->Owner();
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 05c0cb3b..4eab4408 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -785,7 +785,8 @@
       child->RecalcDistribution();
   }
 
-  if (ShadowRoot* root = GetShadowRoot()) {
+  for (ShadowRoot* root = YoungestShadowRoot(); root;
+       root = root->OlderShadowRoot()) {
     if (root->ChildNeedsDistributionRecalc())
       root->RecalcDistribution();
   }
@@ -1619,6 +1620,13 @@
         if (!child1->IsShadowRoot())
           return Node::kDocumentPositionPreceding | connection;
 
+        for (const ShadowRoot* child = ToShadowRoot(child2)->OlderShadowRoot();
+             child; child = child->OlderShadowRoot()) {
+          if (child == child1) {
+            return Node::kDocumentPositionFollowing | connection;
+          }
+        }
+
         return Node::kDocumentPositionPreceding | connection;
       }
 
@@ -1744,7 +1752,12 @@
   for (unsigned index = chain.size(); index > 0; --index) {
     const Node* node = chain[index - 1];
     if (node->IsShadowRoot()) {
-      stream << "/#shadow-root";
+      int count = 0;
+      for (const ShadowRoot* shadow_root =
+               ToShadowRoot(node)->OlderShadowRoot();
+           shadow_root; shadow_root = shadow_root->OlderShadowRoot())
+        ++count;
+      stream << "/#shadow-root[" << count << "]";
       continue;
     }
 
@@ -1823,7 +1836,12 @@
                          marked_node2, marked_label2, builder);
     }
 
-    if (ShadowRoot* shadow_root = GetShadowRootFor(&node)) {
+    if (node.IsShadowRoot()) {
+      if (ShadowRoot* younger_shadow_root =
+              ToShadowRoot(node).YoungerShadowRoot())
+        AppendMarkedTree(indent.ToString(), younger_shadow_root, marked_node1,
+                         marked_label1, marked_node2, marked_label2, builder);
+    } else if (ShadowRoot* shadow_root = GetShadowRootFor(&node)) {
       AppendMarkedTree(indent.ToString(), shadow_root, marked_node1,
                        marked_label1, marked_node2, marked_label2, builder);
     }
@@ -1904,12 +1922,18 @@
   if (node == marked_node)
     stream << "*";
   stream << indent.Utf8().data() << *node << "\n";
-  if (node->IsFrameOwnerElement()) {
-    PrintSubTreeAcrossFrame(ToHTMLFrameOwnerElement(node)->contentDocument(),
-                            marked_node, indent + "\t", stream);
+  if (node->IsShadowRoot()) {
+    if (ShadowRoot* younger_shadow_root =
+            ToShadowRoot(node)->YoungerShadowRoot())
+      PrintSubTreeAcrossFrame(younger_shadow_root, marked_node, indent + "\t",
+                              stream);
+  } else {
+    if (node->IsFrameOwnerElement())
+      PrintSubTreeAcrossFrame(ToHTMLFrameOwnerElement(node)->contentDocument(),
+                              marked_node, indent + "\t", stream);
+    if (ShadowRoot* shadow_root = GetShadowRootFor(node))
+      PrintSubTreeAcrossFrame(shadow_root, marked_node, indent + "\t", stream);
   }
-  if (ShadowRoot* shadow_root = GetShadowRootFor(node))
-    PrintSubTreeAcrossFrame(shadow_root, marked_node, indent + "\t", stream);
   for (const Node* child = node->firstChild(); child;
        child = child->nextSibling())
     PrintSubTreeAcrossFrame(child, marked_node, indent + "\t", stream);
@@ -2028,7 +2052,8 @@
   ScriptForbiddenScope forbid_script_during_raw_iteration;
   for (Node& node : NodeTraversal::StartsAt(*this)) {
     node.RemoveAllEventListeners();
-    if (ShadowRoot* root = node.GetShadowRoot())
+    for (ShadowRoot* root = node.YoungestShadowRoot(); root;
+         root = root->OlderShadowRoot())
       root->RemoveAllEventListenersRecursively();
   }
 }
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index 53602dd0..78d7d23 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -364,7 +364,7 @@
   // isInShadowTree() returns true.
   // This can happen when handling queued events (e.g. during execCommand())
   ShadowRoot* ContainingShadowRoot() const;
-  ShadowRoot* GetShadowRoot() const;
+  ShadowRoot* YoungestShadowRoot() const;
   bool IsInUserAgentShadowRoot() const;
 
   // Returns nullptr, a child of ShadowRoot, or a legacy shadow root.
diff --git a/third_party/WebKit/Source/core/dom/ShadowRoot.h b/third_party/WebKit/Source/core/dom/ShadowRoot.h
index ec376ab3..ba9e1f4 100644
--- a/third_party/WebKit/Source/core/dom/ShadowRoot.h
+++ b/third_party/WebKit/Source/core/dom/ShadowRoot.h
@@ -42,6 +42,7 @@
 class Document;
 class ElementShadow;
 class ExceptionState;
+class HTMLShadowElement;
 class ShadowRootRareDataV0;
 class SlotAssignment;
 class StringOrTrustedHTML;
@@ -106,12 +107,17 @@
   void SetNeedsAssignmentRecalc();
 
   // For V0
+  ShadowRoot* YoungerShadowRoot() const { return nullptr; }
+  ShadowRoot* OlderShadowRoot() const { return nullptr; }
   bool ContainsShadowElements() const;
   bool ContainsContentElements() const;
   bool ContainsInsertionPoints() const {
     return ContainsShadowElements() || ContainsContentElements();
   }
   unsigned DescendantShadowElementCount() const;
+  HTMLShadowElement* ShadowInsertionPointOfYoungerShadowRoot() const {
+    return nullptr;
+  }
   void DidAddInsertionPoint(V0InsertionPoint*);
   void DidRemoveInsertionPoint(V0InsertionPoint*);
   const HeapVector<Member<V0InsertionPoint>>& DescendantInsertionPoints();
@@ -196,6 +202,13 @@
   return AdjustedFocusedElement();
 }
 
+inline ShadowRoot* Element::ShadowRootIfV1() const {
+  ShadowRoot* root = GetShadowRoot();
+  if (root && root->IsV1())
+    return root;
+  return nullptr;
+}
+
 inline bool Node::IsInUserAgentShadowRoot() const {
   return ContainingShadowRoot() && ContainingShadowRoot()->IsUserAgent();
 }
diff --git a/third_party/WebKit/Source/core/dom/TreeScope.cpp b/third_party/WebKit/Source/core/dom/TreeScope.cpp
index ca4e33fd..6ad6b022 100644
--- a/third_party/WebKit/Source/core/dom/TreeScope.cpp
+++ b/third_party/WebKit/Source/core/dom/TreeScope.cpp
@@ -80,10 +80,19 @@
   selection_ = nullptr;
 }
 
+TreeScope* TreeScope::OlderShadowRootOrParentTreeScope() const {
+  if (RootNode().IsShadowRoot()) {
+    if (ShadowRoot* older_shadow_root =
+            ToShadowRoot(RootNode()).OlderShadowRoot())
+      return older_shadow_root;
+  }
+  return ParentTreeScope();
+}
+
 bool TreeScope::IsInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(
     const TreeScope& scope) const {
   for (const TreeScope* current = &scope; current;
-       current = current->ParentTreeScope()) {
+       current = current->OlderShadowRootOrParentTreeScope()) {
     if (current == this)
       return true;
   }
@@ -440,6 +449,14 @@
       if (shadow_host1 != shadow_host2)
         return shadow_host1->compareDocumentPosition(
             shadow_host2, Node::kTreatShadowTreesAsDisconnected);
+
+      for (const ShadowRoot* child =
+               ToShadowRoot(child2->RootNode()).OlderShadowRoot();
+           child; child = child->OlderShadowRoot()) {
+        if (child == child1)
+          return Node::kDocumentPositionFollowing;
+      }
+
       return Node::kDocumentPositionPreceding;
     }
   }
@@ -498,7 +515,8 @@
     if (DeprecatedEqualIgnoringCase(element.FastGetAttribute(accesskeyAttr),
                                     key))
       result = &element;
-    if (ShadowRoot* shadow_root = element.GetShadowRoot()) {
+    for (ShadowRoot* shadow_root = element.YoungestShadowRoot(); shadow_root;
+         shadow_root = shadow_root->OlderShadowRoot()) {
       if (Element* shadow_result = shadow_root->GetElementByAccessKey(key))
         result = shadow_result;
     }
@@ -509,7 +527,8 @@
 void TreeScope::SetNeedsStyleRecalcForViewportUnits() {
   for (Element* element = ElementTraversal::FirstWithin(RootNode()); element;
        element = ElementTraversal::NextIncludingPseudo(*element)) {
-    if (ShadowRoot* root = element->GetShadowRoot())
+    for (ShadowRoot* root = element->YoungestShadowRoot(); root;
+         root = root->OlderShadowRoot())
       root->SetNeedsStyleRecalcForViewportUnits();
     const ComputedStyle* style = element->GetComputedStyle();
     if (style && style->HasViewportUnits())
diff --git a/third_party/WebKit/Source/core/dom/TreeScope.h b/third_party/WebKit/Source/core/dom/TreeScope.h
index d3b1687c..56ff525 100644
--- a/third_party/WebKit/Source/core/dom/TreeScope.h
+++ b/third_party/WebKit/Source/core/dom/TreeScope.h
@@ -54,6 +54,7 @@
  public:
   TreeScope* ParentTreeScope() const { return parent_tree_scope_; }
 
+  TreeScope* OlderShadowRootOrParentTreeScope() const;
   bool IsInclusiveOlderSiblingShadowRootOrAncestorTreeScopeOf(
       const TreeScope&) const;
 
diff --git a/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp b/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
index 8363437a..1365eda 100644
--- a/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
+++ b/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
@@ -79,7 +79,8 @@
         MoveTreeToNewScope(*attr);
     }
 
-    if (ShadowRoot* shadow = element.GetShadowRoot()) {
+    for (ShadowRoot* shadow = element.YoungestShadowRoot(); shadow;
+         shadow = shadow->OlderShadowRoot()) {
       shadow->SetParentTreeScope(NewScope());
       if (will_move_to_new_document) {
         if (shadow->GetType() == ShadowRootType::V0) {
@@ -112,7 +113,8 @@
         MoveTreeToNewDocument(*attr, old_document, new_document);
     }
 
-    if (ShadowRoot* shadow = element.GetShadowRoot())
+    for (ShadowRoot* shadow = element.YoungestShadowRoot(); shadow;
+         shadow = shadow->OlderShadowRoot())
       MoveTreeToNewDocument(*shadow, old_document, new_document);
   }
 }
diff --git a/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp b/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp
index a9e0425..5cff2b8e 100644
--- a/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp
+++ b/third_party/WebKit/Source/core/dom/VisitedLinkState.cpp
@@ -75,7 +75,8 @@
       ToElement(node).PseudoStateChanged(CSSSelector::kPseudoAnyLink);
     }
     if (IsShadowHost(&node)) {
-      if (ShadowRoot* root = node.GetShadowRoot())
+      for (ShadowRoot* root = node.YoungestShadowRoot(); root;
+           root = root->OlderShadowRoot())
         InvalidateStyleForAllLinksRecursively(*root,
                                               invalidate_visited_link_hashes);
     }
@@ -99,7 +100,8 @@
       ToElement(node).PseudoStateChanged(CSSSelector::kPseudoAnyLink);
     }
     if (IsShadowHost(&node))
-      if (ShadowRoot* root = node.GetShadowRoot())
+      for (ShadowRoot* root = node.YoungestShadowRoot(); root;
+           root = root->OlderShadowRoot())
         InvalidateStyleForLinkRecursively(*root, link_hash);
   }
 }
diff --git a/third_party/WebKit/Source/core/dom/events/EventPath.cpp b/third_party/WebKit/Source/core/dom/events/EventPath.cpp
index 5bf64294..39aab44 100644
--- a/third_party/WebKit/Source/core/dom/events/EventPath.cpp
+++ b/third_party/WebKit/Source/core/dom/events/EventPath.cpp
@@ -145,8 +145,12 @@
   //   - The root tree must be included.
   TreeScopeEventContext* root_tree = nullptr;
   for (const auto& tree_scope_event_context : tree_scope_event_contexts_) {
-    TreeScope* parent =
-        tree_scope_event_context.Get()->GetTreeScope().ParentTreeScope();
+    // Use olderShadowRootOrParentTreeScope here for parent-child relationships.
+    // See the definition of trees of trees in the Shadow DOM spec:
+    // http://w3c.github.io/webcomponents/spec/shadow/
+    TreeScope* parent = tree_scope_event_context.Get()
+                            ->GetTreeScope()
+                            .OlderShadowRootOrParentTreeScope();
     if (!parent) {
       DCHECK(!root_tree);
       root_tree = tree_scope_event_context.Get();
@@ -185,7 +189,8 @@
     tree_scope_event_contexts_.push_back(tree_scope_event_context);
 
     TreeScopeEventContext* parent_tree_scope_event_context =
-        EnsureTreeScopeEventContext(nullptr, tree_scope->ParentTreeScope());
+        EnsureTreeScopeEventContext(
+            nullptr, tree_scope->OlderShadowRootOrParentTreeScope());
     if (parent_tree_scope_event_context &&
         parent_tree_scope_event_context->Target()) {
       tree_scope_event_context->SetTarget(
@@ -237,7 +242,7 @@
   HeapVector<Member<TreeScope>, 32> parent_tree_scopes;
   EventTarget* related_node = nullptr;
   for (TreeScope* current = &scope; current;
-       current = current->ParentTreeScope()) {
+       current = current->OlderShadowRootOrParentTreeScope()) {
     parent_tree_scopes.push_back(current);
     RelatedTargetMap::const_iterator iter = related_target_map.find(current);
     if (iter != related_target_map.end() && iter->value) {
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index 5232bad9..e82446cd 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -414,12 +414,23 @@
           const ShadowRoot* shadow_root = ToShadowRoot(node_);
           if (shadow_root->GetType() == ShadowRootType::V0 ||
               shadow_root->GetType() == ShadowRootType::kOpen) {
-            // We are the shadow root; exit from here and go back to
-            // where we were.
-            node_ = &shadow_root->host();
-            iteration_progress_ = kHandledOpenShadowRoots;
-            --shadow_depth_;
-            fully_clipped_stack_.Pop();
+            ShadowRoot* next_shadow_root = shadow_root->OlderShadowRoot();
+            if (next_shadow_root &&
+                next_shadow_root->GetType() == ShadowRootType::V0) {
+              fully_clipped_stack_.Pop();
+              node_ = next_shadow_root;
+              iteration_progress_ = kHandledNone;
+              // m_shadowDepth is unchanged since we exit from a shadow root and
+              // enter another.
+              fully_clipped_stack_.PushFullyClippedState(node_);
+            } else {
+              // We are the last shadow root; exit from here and go back to
+              // where we were.
+              node_ = &shadow_root->host();
+              iteration_progress_ = kHandledOpenShadowRoots;
+              --shadow_depth_;
+              fully_clipped_stack_.Pop();
+            }
           } else {
             // If we are in a closed or user-agent shadow root, then go back to
             // the host.
diff --git a/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp b/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp
index a12389a..c25f42c 100644
--- a/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp
+++ b/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp
@@ -11,7 +11,6 @@
 #include "core/dom/CharacterData.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
-#include "core/dom/ElementShadow.h"
 #include "core/dom/ProcessingInstruction.h"
 #include "core/dom/ShadowRootInit.h"
 #include "core/editing/EditingUtilities.h"
diff --git a/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp b/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp
index 9718834..b0f4a22 100644
--- a/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp
+++ b/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp
@@ -4,7 +4,6 @@
 
 #include "core/editing/testing/SelectionSample.h"
 
-#include "core/dom/ElementShadow.h"
 #include "core/dom/ProcessingInstruction.h"
 #include "core/editing/SelectionTemplate.h"
 #include "core/editing/testing/EditingTestBase.h"
diff --git a/third_party/WebKit/Source/core/events/GestureEvent.cpp b/third_party/WebKit/Source/core/events/GestureEvent.cpp
index db234918..ecd9dc25 100644
--- a/third_party/WebKit/Source/core/events/GestureEvent.cpp
+++ b/third_party/WebKit/Source/core/events/GestureEvent.cpp
@@ -83,7 +83,7 @@
           view,
           0,
           static_cast<WebInputEvent::Modifiers>(event.GetModifiers()),
-          TimeTicks::FromSeconds(event.TimeStampSeconds()),
+          TimeTicksFromSeconds(event.TimeStampSeconds()),
           nullptr),
       native_event_(event) {}
 
diff --git a/third_party/WebKit/Source/core/events/KeyboardEvent.cpp b/third_party/WebKit/Source/core/events/KeyboardEvent.cpp
index c0169bb..11c1c296 100644
--- a/third_party/WebKit/Source/core/events/KeyboardEvent.cpp
+++ b/third_party/WebKit/Source/core/events/KeyboardEvent.cpp
@@ -97,7 +97,7 @@
           dom_window,
           0,
           static_cast<WebInputEvent::Modifiers>(key.GetModifiers()),
-          TimeTicks::FromSeconds(key.TimeStampSeconds()),
+          TimeTicksFromSeconds(key.TimeStampSeconds()),
           dom_window
               ? dom_window->GetInputDeviceCapabilities()->FiresTouchEvents(
                     false)
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.cpp b/third_party/WebKit/Source/core/events/MouseEvent.cpp
index aee2f31..cb4518b 100644
--- a/third_party/WebKit/Source/core/events/MouseEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MouseEvent.cpp
@@ -168,7 +168,7 @@
           abstract_view,
           detail,
           static_cast<WebInputEvent::Modifiers>(event.GetModifiers()),
-          TimeTicks::FromSeconds(event.TimeStampSeconds()),
+          TimeTicksFromSeconds(event.TimeStampSeconds()),
           abstract_view
               ? abstract_view->GetInputDeviceCapabilities()->FiresTouchEvents(
                     event.FromTouch())
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
index 9f734b9..ff732c0 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -291,7 +291,7 @@
                                   &coalesced_event_init);
       PointerEvent* event = PointerEvent::Create(
           pointer_event_name, coalesced_event_init,
-          TimeTicks::FromSeconds(coalesced_mouse_event.TimeStampSeconds()));
+          TimeTicksFromSeconds(coalesced_mouse_event.TimeStampSeconds()));
       // Set the trusted flag for the coalesced events at the creation time
       // as oppose to the normal events which is done at the dispatch time. This
       // is because we don't want to go over all the coalesced events at every
@@ -305,7 +305,7 @@
 
   return PointerEvent::Create(
       pointer_event_name, pointer_event_init,
-      TimeTicks::FromSeconds(mouse_event.TimeStampSeconds()));
+      TimeTicksFromSeconds(mouse_event.TimeStampSeconds()));
 }
 
 PointerEvent* PointerEventFactory::Create(
@@ -351,7 +351,7 @@
       UpdateTouchPointerEventInit(coalesced_event, view, &coalesced_event_init);
       PointerEvent* event = PointerEvent::Create(
           type, coalesced_event_init,
-          TimeTicks::FromSeconds(coalesced_event.TimeStampSeconds()));
+          TimeTicksFromSeconds(coalesced_event.TimeStampSeconds()));
       // Set the trusted flag for the coalesced events at the creation time
       // as oppose to the normal events which is done at the dispatch time. This
       // is because we don't want to go over all the coalesced events at every
@@ -365,7 +365,7 @@
 
   return PointerEvent::Create(
       type, pointer_event_init,
-      TimeTicks::FromSeconds(web_pointer_event.TimeStampSeconds()));
+      TimeTicksFromSeconds(web_pointer_event.TimeStampSeconds()));
 }
 
 PointerEvent* PointerEventFactory::CreatePointerCancelEvent(
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp b/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp
index a4cc8ad..5e361e8 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactoryTest.cpp
@@ -60,7 +60,7 @@
         web_pointer_event, coalesced_events, nullptr);
     EXPECT_EQ(unique_id, pointer_event->pointerId());
     EXPECT_EQ(is_primary, pointer_event->isPrimary());
-    EXPECT_EQ(TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting),
+    EXPECT_EQ(TimeTicksFromSeconds(WebInputEvent::kTimeStampForTesting),
               pointer_event->PlatformTimeStamp());
     const char* expected_pointer_type =
         PointerTypeNameForWebPointPointerType(pointer_type);
@@ -72,7 +72,7 @@
       EXPECT_EQ(is_primary,
                 pointer_event->getCoalescedEvents()[i]->isPrimary());
       EXPECT_EQ(expected_pointer_type, pointer_event->pointerType());
-      EXPECT_EQ(TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting),
+      EXPECT_EQ(TimeTicksFromSeconds(WebInputEvent::kTimeStampForTesting),
                 pointer_event->PlatformTimeStamp());
     }
     return pointer_event;
@@ -123,13 +123,13 @@
     int unique_id,
     bool is_primary) {
   PointerEvent* pointer_event = pointer_event_factory_.CreatePointerCancelEvent(
-      unique_id, TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting));
+      unique_id, TimeTicksFromSeconds(WebInputEvent::kTimeStampForTesting));
   EXPECT_EQ("pointercancel", pointer_event->type());
   EXPECT_EQ(unique_id, pointer_event->pointerId());
   EXPECT_EQ(is_primary, pointer_event->isPrimary());
   EXPECT_EQ(PointerTypeNameForWebPointPointerType(pointer_type),
             pointer_event->pointerType());
-  EXPECT_EQ(TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting),
+  EXPECT_EQ(TimeTicksFromSeconds(WebInputEvent::kTimeStampForTesting),
             pointer_event->PlatformTimeStamp());
 
   return pointer_event;
@@ -178,7 +178,7 @@
       coalesced_events, nullptr);
   EXPECT_EQ(unique_id, pointer_event->pointerId());
   EXPECT_EQ(is_primary, pointer_event->isPrimary());
-  EXPECT_EQ(TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting),
+  EXPECT_EQ(TimeTicksFromSeconds(WebInputEvent::kTimeStampForTesting),
             pointer_event->PlatformTimeStamp());
   const char* expected_pointer_type =
       PointerTypeNameForWebPointPointerType(pointer_type);
@@ -188,7 +188,7 @@
     EXPECT_EQ(unique_id, pointer_event->getCoalescedEvents()[i]->pointerId());
     EXPECT_EQ(is_primary, pointer_event->getCoalescedEvents()[i]->isPrimary());
     EXPECT_EQ(expected_pointer_type, pointer_event->pointerType());
-    EXPECT_EQ(TimeTicks::FromSeconds(WebInputEvent::kTimeStampForTesting + i),
+    EXPECT_EQ(TimeTicksFromSeconds(WebInputEvent::kTimeStampForTesting + i),
               pointer_event->getCoalescedEvents()[i]->PlatformTimeStamp());
   }
   return pointer_event;
diff --git a/third_party/WebKit/Source/core/events/TouchEvent.cpp b/third_party/WebKit/Source/core/events/TouchEvent.cpp
index 43934d29..ffcb287 100644
--- a/third_party/WebKit/Source/core/events/TouchEvent.cpp
+++ b/third_party/WebKit/Source/core/events/TouchEvent.cpp
@@ -226,7 +226,7 @@
           view,
           0,
           static_cast<WebInputEvent::Modifiers>(event.Event().GetModifiers()),
-          TimeTicks::FromSeconds(event.Event().TimeStampSeconds()),
+          TimeTicksFromSeconds(event.Event().TimeStampSeconds()),
           view ? view->GetInputDeviceCapabilities()->FiresTouchEvents(true)
                : nullptr),
       touches_(touches),
diff --git a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
index c71b06c..e62ff1b 100644
--- a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
+++ b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
@@ -86,7 +86,7 @@
                                            const LocalFrameView* plugin_parent,
                                            const LayoutObject* layout_object,
                                            WebMouseEvent& web_event) {
-  web_event.SetTimeStampSeconds(event.PlatformTimeStamp().InSeconds());
+  web_event.SetTimeStampSeconds(TimeTicksInSeconds(event.PlatformTimeStamp()));
   web_event.SetModifiers(event.GetModifiers());
 
   // TODO(bokan): If plugin_parent == nullptr, pointInRootFrame will really be
@@ -209,7 +209,7 @@
   else
     return;  // Skip all other mouse events.
 
-  time_stamp_seconds_ = event.PlatformTimeStamp().InSeconds();
+  time_stamp_seconds_ = TimeTicksInSeconds(event.PlatformTimeStamp());
   modifiers_ = event.GetModifiers();
   UpdateWebMouseEventFromCoreMouseEvent(event, plugin_parent, layout_object,
                                         *this);
@@ -287,7 +287,7 @@
   else
     return;
 
-  time_stamp_seconds_ = event.PlatformTimeStamp().InSeconds();
+  time_stamp_seconds_ = TimeTicksInSeconds(event.PlatformTimeStamp());
   modifiers_ = event.GetModifiers();
   frame_scale_ = 1;
   frame_translate_ = WebFloatPoint();
@@ -331,7 +331,7 @@
     return;  // Skip all other keyboard events.
 
   modifiers_ = event.GetModifiers();
-  time_stamp_seconds_ = event.PlatformTimeStamp().InSeconds();
+  time_stamp_seconds_ = TimeTicksInSeconds(event.PlatformTimeStamp());
   windows_key_code = event.keyCode();
 }
 
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 5236bf46..a770273 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -11584,7 +11584,7 @@
       WebFloatPoint(div1_tag->OffsetLeft() + 5, div1_tag->OffsetTop() + 5),
       WebFloatPoint(div1_tag->OffsetLeft() + 5, div1_tag->OffsetTop() + 5),
       WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_move_over_link_event.SetFrameScale(1);
   document->GetFrame()->GetEventHandler().HandleMouseMoveEvent(
       mouse_move_over_link_event, Vector<WebMouseEvent>());
@@ -11603,7 +11603,7 @@
       WebFloatPoint(div2_tag->OffsetLeft() + 5, div2_tag->OffsetTop() + 5),
       WebFloatPoint(div2_tag->OffsetLeft() + 5, div2_tag->OffsetTop() + 5),
       WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_move_event.SetFrameScale(1);
   document->GetFrame()->GetEventHandler().HandleMouseMoveEvent(
       mouse_move_event, Vector<WebMouseEvent>());
diff --git a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp
index 13ff081..27e21b5 100644
--- a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp
@@ -28,6 +28,7 @@
 #include "platform/geometry/LayoutRect.h"
 #include "platform/heap/Handle.h"
 #include "public/platform/WebFloatRect.h"
+#include "public/platform/WebIntrinsicSizingInfo.h"
 #include "public/platform/WebRect.h"
 #include "public/platform/WebScrollIntoViewParams.h"
 #include "public/web/WebDocument.h"
@@ -361,6 +362,24 @@
   scroll_sequencer->RunQueuedAnimations();
 }
 
+void WebRemoteFrameImpl::IntrinsicSizingInfoChanged(
+    const WebIntrinsicSizingInfo& web_sizing_info) {
+  FrameOwner* owner = GetFrame()->Owner();
+  // Only communication from HTMLPluginElement-owned subframes is allowed
+  // at present. This includes <embed> and <object> tags.
+  if (!owner || !owner->IsPlugin())
+    return;
+
+  IntrinsicSizingInfo sizing_info;
+  sizing_info.size = web_sizing_info.size;
+  sizing_info.aspect_ratio = web_sizing_info.aspect_ratio;
+  sizing_info.has_width = web_sizing_info.has_width;
+  sizing_info.has_height = web_sizing_info.has_height;
+  frame_->View()->SetIntrinsicSizeInfo(sizing_info);
+
+  owner->IntrinsicSizingInfoChanged();
+}
+
 void WebRemoteFrameImpl::SetHasReceivedUserGestureBeforeNavigation(bool value) {
   GetFrame()->SetDocumentHasReceivedUserGestureBeforeNavigation(value);
 }
diff --git a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h
index 3d66348..3fb6382 100644
--- a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h
@@ -81,6 +81,7 @@
   void SetHasReceivedUserGesture() override;
   void ScrollRectToVisible(const WebRect&,
                            const WebScrollIntoViewParams&) override;
+  void IntrinsicSizingInfoChanged(const WebIntrinsicSizingInfo&) override;
   void SetHasReceivedUserGestureBeforeNavigation(bool value) override;
   v8::Local<v8::Object> GlobalProxy() const override;
 
diff --git a/third_party/WebKit/Source/core/frame/BUILD.gn b/third_party/WebKit/Source/core/frame/BUILD.gn
index 133cae7..8e29e3dd 100644
--- a/third_party/WebKit/Source/core/frame/BUILD.gn
+++ b/third_party/WebKit/Source/core/frame/BUILD.gn
@@ -59,6 +59,7 @@
     "Intervention.cpp",
     "Intervention.h",
     "InterventionReport.h",
+    "IntrinsicSizingInfo.h",
     "LayoutSubtreeRootList.cpp",
     "LayoutSubtreeRootList.h",
     "LocalDOMWindow.cpp",
diff --git a/third_party/WebKit/Source/core/frame/EmbeddedContentView.h b/third_party/WebKit/Source/core/frame/EmbeddedContentView.h
index 8cbd0d3..63370eca 100644
--- a/third_party/WebKit/Source/core/frame/EmbeddedContentView.h
+++ b/third_party/WebKit/Source/core/frame/EmbeddedContentView.h
@@ -21,6 +21,7 @@
  public:
   virtual ~EmbeddedContentView() = default;
 
+  virtual bool IsFrameView() const { return false; }
   virtual bool IsLocalFrameView() const { return false; }
   virtual bool IsPluginView() const { return false; }
 
diff --git a/third_party/WebKit/Source/core/frame/FrameOwner.h b/third_party/WebKit/Source/core/frame/FrameOwner.h
index 43d1d0df..f9d8a44 100644
--- a/third_party/WebKit/Source/core/frame/FrameOwner.h
+++ b/third_party/WebKit/Source/core/frame/FrameOwner.h
@@ -27,6 +27,7 @@
 
   virtual bool IsLocal() const = 0;
   virtual bool IsRemote() const = 0;
+  virtual bool IsPlugin() { return false; }
 
   virtual Frame* ContentFrame() const = 0;
   virtual void SetContentFrame(Frame&) = 0;
@@ -46,7 +47,7 @@
 
   // The intrinsic dimensions of the embedded object changed. This is relevant
   // for SVG documents that are embedded via <object> or <embed>.
-  virtual void IntrinsicDimensionsChanged() = 0;
+  virtual void IntrinsicSizingInfoChanged() = 0;
 
   // Returns the 'name' content attribute value of the browsing context
   // container.
@@ -84,7 +85,7 @@
   void DispatchLoad() override {}
   bool CanRenderFallbackContent() const override { return false; }
   void RenderFallbackContent() override {}
-  void IntrinsicDimensionsChanged() override {}
+  void IntrinsicSizingInfoChanged() override {}
   AtomicString BrowsingContextContainerName() const override {
     return AtomicString();
   }
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index 93f2966..08314729 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -7,6 +7,7 @@
 
 #include "core/dom/DocumentLifecycle.h"
 #include "core/frame/EmbeddedContentView.h"
+#include "core/frame/IntrinsicSizingInfo.h"
 
 namespace blink {
 
@@ -15,8 +16,19 @@
   virtual ~FrameView() = default;
   virtual void UpdateViewportIntersectionsForSubtree(
       DocumentLifecycle::LifecycleState) = 0;
+
+  virtual bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const = 0;
+  virtual bool HasIntrinsicSizingInfo() const = 0;
+
+  bool IsFrameView() const override { return true; }
 };
 
+DEFINE_TYPE_CASTS(FrameView,
+                  EmbeddedContentView,
+                  embedded_content_view,
+                  embedded_content_view->IsFrameView(),
+                  embedded_content_view.IsFrameView());
+
 }  // namespace blink
 
 #endif  // FrameView_h
diff --git a/third_party/WebKit/Source/core/frame/IntrinsicSizingInfo.h b/third_party/WebKit/Source/core/frame/IntrinsicSizingInfo.h
new file mode 100644
index 0000000..9981528
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/IntrinsicSizingInfo.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IntrinsicSizingInfo_h
+#define IntrinsicSizingInfo_h
+
+#include "platform/geometry/FloatSize.h"
+
+namespace blink {
+
+struct IntrinsicSizingInfo {
+  IntrinsicSizingInfo() : has_width(true), has_height(true) {}
+
+  FloatSize size;
+  FloatSize aspect_ratio;
+  bool has_width;
+  bool has_height;
+
+  void Transpose() {
+    size = size.TransposedSize();
+    aspect_ratio = aspect_ratio.TransposedSize();
+    std::swap(has_width, has_height);
+  }
+};
+
+}  // namespace blink
+
+#endif  // IntrinsicSizingInfo_h
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index 7e80c652..8c3a3fbc 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -56,6 +56,7 @@
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/PerformanceMonitor.h"
 #include "core/frame/Settings.h"
+#include "core/frame/WebLocalFrameImpl.h"
 #include "core/html/HTMLFrameElementBase.h"
 #include "core/html/HTMLPlugInElement.h"
 #include "core/html/PluginDocument.h"
@@ -454,6 +455,21 @@
   return GetDocument() ? GetDocument()->GetLayoutView() : nullptr;
 }
 
+void LocalFrame::IntrinsicSizingInfoChanged(
+    const IntrinsicSizingInfo& sizing_info) {
+  if (!Owner())
+    return;
+  // Notify the owner. For remote frame owners, notify via
+  // an IPC to the parent renderer; otherwise notify directly.
+  if (Owner()->IsRemote()) {
+    WebLocalFrameImpl::FromFrame(this)
+        ->FrameWidget()
+        ->IntrinsicSizingInfoChanged(sizing_info);
+  } else {
+    Owner()->IntrinsicSizingInfoChanged();
+  }
+}
+
 void LocalFrame::DidChangeVisibilityState() {
   if (GetDocument())
     GetDocument()->DidChangeVisibilityState();
@@ -1173,8 +1189,10 @@
       });
   GetDocument()->Parser()->Finish();
 
-  // Upon loading of the page, log PageVisits in UseCounter.
-  if (GetPage())
+  // Upon loading of SVGIamges, log PageVisits in UseCounter.
+  // Do not track PageVisits for inspector, web page popups, and validation
+  // message overlays (the other callers of this method).
+  if (GetPage() && GetDocument()->IsSVGDocument())
     GetPage()->GetUseCounter().DidCommitLoad(this);
 }
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h
index 1bbad13..1d5f68c 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -159,6 +159,8 @@
   SpellChecker& GetSpellChecker() const;
   FrameConsole& Console() const;
 
+  void IntrinsicSizingInfoChanged(const IntrinsicSizingInfo&);
+
   // This method is used to get the highest level LocalFrame in this
   // frame's in-process subtree.
   // FIXME: This is a temporary hack to support RemoteFrames, and callers
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.h b/third_party/WebKit/Source/core/frame/LocalFrameView.h
index e7ee33c..e1ae0a0 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.h
@@ -206,8 +206,8 @@
   int InitialViewportWidth() const;
   int InitialViewportHeight() const;
 
-  bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const;
-  bool HasIntrinsicSizingInfo() const;
+  bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
+  bool HasIntrinsicSizingInfo() const override;
 
   void UpdateAcceleratedCompositingSettings();
 
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameOwner.h b/third_party/WebKit/Source/core/frame/RemoteFrameOwner.h
index fd18eca4..e45c08f2 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameOwner.h
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameOwner.h
@@ -42,7 +42,7 @@
   // TODO(dcheng): Implement.
   bool CanRenderFallbackContent() const override { return false; }
   void RenderFallbackContent() override {}
-  void IntrinsicDimensionsChanged() override {}
+  void IntrinsicSizingInfoChanged() override {}
 
   AtomicString BrowsingContextContainerName() const override {
     return browsing_context_container_name_;
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp b/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
index 2518596..3e0b727 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
@@ -220,6 +220,25 @@
   return hidden_for_throttling_;
 }
 
+void RemoteFrameView::SetIntrinsicSizeInfo(
+    const IntrinsicSizingInfo& size_info) {
+  intrinsic_sizing_info_ = size_info;
+  has_intrinsic_sizing_info_ = true;
+}
+
+bool RemoteFrameView::GetIntrinsicSizingInfo(
+    IntrinsicSizingInfo& sizing_info) const {
+  if (!has_intrinsic_sizing_info_)
+    return false;
+
+  sizing_info = intrinsic_sizing_info_;
+  return true;
+}
+
+bool RemoteFrameView::HasIntrinsicSizingInfo() const {
+  return has_intrinsic_sizing_info_;
+}
+
 void RemoteFrameView::Trace(blink::Visitor* visitor) {
   visitor->Trace(remote_frame_);
   visitor->Trace(visibility_observer_);
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameView.h b/third_party/WebKit/Source/core/frame/RemoteFrameView.h
index 8510f34..a4a24ae81 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameView.h
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameView.h
@@ -53,6 +53,11 @@
   void UpdateViewportIntersectionsForSubtree(
       DocumentLifecycle::LifecycleState) override;
 
+  bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
+
+  void SetIntrinsicSizeInfo(const IntrinsicSizingInfo& size_info);
+  bool HasIntrinsicSizingInfo() const override;
+
   virtual void Trace(blink::Visitor*);
 
  private:
@@ -79,6 +84,8 @@
   Member<ElementVisibilityObserver> visibility_observer_;
   bool subtree_throttled_ = false;
   bool hidden_for_throttling_ = false;
+  IntrinsicSizingInfo intrinsic_sizing_info_;
+  bool has_intrinsic_sizing_info_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
index c11e1801..d18fa5ae 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
@@ -170,7 +170,7 @@
   WebMouseEvent fake_mouse_move(
       WebInputEvent::kMouseMove, point_in_root_frame, screen_point,
       WebPointerProperties::Button::kLeft, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   fake_mouse_move.SetFrameScale(1);
   ToCoreFrame(LocalRoot())
       ->GetEventHandler()
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
index 3073065..3965c2d 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
@@ -21,6 +21,7 @@
 class CompositorAnimationHost;
 class CompositorMutatorImpl;
 class GraphicsLayer;
+struct IntrinsicSizingInfo;
 class PageWidgetEventHandler;
 class WebActiveGestureAnimation;
 class WebImage;
@@ -41,6 +42,7 @@
 
   virtual bool ForSubframe() const = 0;
   virtual void ScheduleAnimation() = 0;
+  virtual void IntrinsicSizingInfoChanged(const IntrinsicSizingInfo&) {}
   virtual CompositorMutatorImpl* CompositorMutator() = 0;
 
   virtual WebWidgetClient* Client() const = 0;
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
index 07c27016..fd220d3 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.cpp
@@ -533,6 +533,16 @@
   client_->ScheduleAnimation();
 }
 
+void WebFrameWidgetImpl::IntrinsicSizingInfoChanged(
+    const IntrinsicSizingInfo& sizing_info) {
+  WebIntrinsicSizingInfo web_sizing_info;
+  web_sizing_info.size = sizing_info.size;
+  web_sizing_info.aspect_ratio = sizing_info.aspect_ratio;
+  web_sizing_info.has_width = sizing_info.has_width;
+  web_sizing_info.has_height = sizing_info.has_height;
+  client_->IntrinsicSizingInfoChanged(web_sizing_info);
+}
+
 CompositorMutatorImpl& WebFrameWidgetImpl::Mutator() {
   return *CompositorMutator();
 }
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h
index 0500449..fb861d6 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetImpl.h
@@ -127,6 +127,7 @@
   // WebFrameWidgetBase overrides:
   bool ForSubframe() const override { return true; }
   void ScheduleAnimation() override;
+  void IntrinsicSizingInfoChanged(const IntrinsicSizingInfo&) override;
 
   WebWidgetClient* Client() const override { return client_; }
   void SetRootGraphicsLayer(GraphicsLayer*) override;
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
index 9bc3515..dac9f1b3 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
@@ -98,7 +98,7 @@
   SandboxFlags GetSandboxFlags() const final { return sandbox_flags_; }
   bool CanRenderFallbackContent() const override { return false; }
   void RenderFallbackContent() override {}
-  void IntrinsicDimensionsChanged() override { NOTREACHED(); }
+  void IntrinsicSizingInfoChanged() override {}
   AtomicString BrowsingContextContainerName() const override {
     return getAttribute(HTMLNames::nameAttr);
   }
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
index d44e1ca6..bc0efb3 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -209,7 +209,7 @@
     context.previous_in_flow = layout_object;
 }
 
-void HTMLPlugInElement::IntrinsicDimensionsChanged() {
+void HTMLPlugInElement::IntrinsicSizingInfoChanged() {
   if (auto* layout_object = GetLayoutObject()) {
     layout_object->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
         LayoutInvalidationReason::kUnknown);
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
index 97213ca..e55a14d 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
@@ -51,6 +51,8 @@
   ~HTMLPlugInElement() override;
   virtual void Trace(blink::Visitor*);
 
+  bool IsPlugin() override { return true; }
+
   bool HasPendingActivity() const final;
 
   void SetFocused(bool, WebFocusType) override;
@@ -152,7 +154,7 @@
 
   // HTMLFrameOwnerElement overrides:
   void DisconnectContentFrame() override;
-  void IntrinsicDimensionsChanged() final;
+  void IntrinsicSizingInfoChanged() final;
 
   // Return any existing LayoutEmbeddedContent without triggering relayout, or 0
   // if it doesn't yet exist.
diff --git a/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp b/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp
index cb95802d..5c83b56 100644
--- a/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp
@@ -49,4 +49,21 @@
 
 HTMLShadowElement::~HTMLShadowElement() = default;
 
+Node::InsertionNotificationRequest HTMLShadowElement::InsertedInto(
+    ContainerNode* insertion_point) {
+  if (insertion_point->isConnected()) {
+    // Warn if trying to reproject between user agent and author shadows.
+    ShadowRoot* root = ContainingShadowRoot();
+    if (root && root->OlderShadowRoot() &&
+        root->GetType() != root->OlderShadowRoot()->GetType()) {
+      String message =
+          String::Format("<shadow> doesn't work for %s element host.",
+                         root->host().tagName().Utf8().data());
+      GetDocument().AddConsoleMessage(ConsoleMessage::Create(
+          kRenderingMessageSource, kWarningMessageLevel, message));
+    }
+  }
+  return V0InsertionPoint::InsertedInto(insertion_point);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLShadowElement.h b/third_party/WebKit/Source/core/html/HTMLShadowElement.h
index 38fd654..c95f047 100644
--- a/third_party/WebKit/Source/core/html/HTMLShadowElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLShadowElement.h
@@ -45,6 +45,8 @@
 
  private:
   explicit HTMLShadowElement(Document&);
+  InsertionNotificationRequest InsertedInto(
+      ContainerNode* insertion_point) override;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
index 3f1ad6f..840d94c99 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
@@ -6,6 +6,7 @@
 
 #include "base/location.h"
 #include "build/build_config.h"
+#include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/fileapi/Blob.h"
@@ -417,8 +418,8 @@
                    WTF::Bind(&V8BlobCallback::InvokeAndReportException,
                              callback_, nullptr, nullptr));
   } else {
-    Blob* result_blob = nullptr;
-    script_promise_resolver_->Resolve(result_blob);
+    script_promise_resolver_->Reject(DOMException::Create(
+        kEncodingError, "Encoding of the source image has failed."));
   }
   // Avoid unwanted retention, see dispose().
   Dispose();
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLOptionsCollection.idl b/third_party/WebKit/Source/core/html/forms/HTMLOptionsCollection.idl
index b25fa0c..2d02067 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLOptionsCollection.idl
+++ b/third_party/WebKit/Source/core/html/forms/HTMLOptionsCollection.idl
@@ -24,7 +24,6 @@
 interface HTMLOptionsCollection : HTMLCollection {
     // Inherits item() and namedItem()
     [CEReactions, RaisesException=Setter] attribute unsigned long length; // shadows inherited length
-    // FIXME: The spec has a legacycaller HTMLOptionElement? (DOMString name);
     [CEReactions, RaisesException] setter void (unsigned long index, HTMLOptionElement? option);
     [CEReactions, RaisesException] void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
     [CEReactions] void remove(long index);
diff --git a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
index 513023f4..1dd9d52 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
@@ -3919,9 +3919,7 @@
   visitor->Trace(autoplay_policy_);
   visitor->Trace(media_controls_);
   visitor->Trace(controls_list_);
-  visitor->template RegisterWeakMembers<HTMLMediaElement,
-                                        &HTMLMediaElement::ClearWeakMembers>(
-      this);
+  visitor->Trace(audio_source_node_);
   Supplementable<HTMLMediaElement>::Trace(visitor);
   HTMLElement::Trace(visitor);
   PausableObject::Trace(visitor);
@@ -4094,13 +4092,6 @@
   return histogram;
 }
 
-void HTMLMediaElement::ClearWeakMembers(Visitor* visitor) {
-  if (!ThreadHeap::IsHeapObjectAlive(audio_source_node_)) {
-    GetAudioSourceProvider().SetClient(nullptr);
-    audio_source_node_ = nullptr;
-  }
-}
-
 void HTMLMediaElement::AudioSourceProviderImpl::Wrap(
     WebAudioSourceProvider* provider) {
   MutexLocker locker(provide_input_lock);
diff --git a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.h
index 30d8c35..86c0e7f 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.h
+++ b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.h
@@ -108,7 +108,6 @@
 
   void TraceWrappers(const ScriptWrappableVisitor*) const override;
 
-  void ClearWeakMembers(Visitor*);
   WebMediaPlayer* GetWebMediaPlayer() const { return web_media_player_.get(); }
 
   // Returns true if the loaded media has a video track.
@@ -665,11 +664,7 @@
   HeapVector<Member<ScriptPromiseResolver>> play_promise_reject_list_;
   ExceptionCode play_promise_error_code_;
 
-  // This is a weak reference, since audio_source_node_ holds a reference to us.
-  // TODO(Oilpan): Consider making this a strongly traced pointer with oilpan
-  // where strong cycles are not a problem.
-  GC_PLUGIN_IGNORE("http://crbug.com/404577")
-  WeakMember<AudioSourceProviderClient> audio_source_node_;
+  Member<AudioSourceProviderClient> audio_source_node_;
 
   // AudioClientImpl wraps an AudioSourceProviderClient.
   // When the audio format is known, Chromium calls setFormat().
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index 23041de..fcee50f2 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1061,7 +1061,7 @@
           scroll_manager_->GetAutoscrollController()) {
     controller->UpdateDragAndDrop(
         new_target, FlooredIntPoint(event.PositionInRootFrame()),
-        TimeTicks::FromSeconds(event.TimeStampSeconds()));
+        TimeTicksFromSeconds(event.TimeStampSeconds()));
   }
 
   if (drag_target_ != new_target) {
@@ -1891,7 +1891,7 @@
       WebFloatPoint(location_in_root_frame.X(), location_in_root_frame.Y()),
       WebFloatPoint(global_position.X(), global_position.Y()),
       WebPointerProperties::Button::kNoButton, /* clickCount */ 0,
-      WebInputEvent::kNoModifiers, CurrentTimeTicks().InSeconds(), source_type);
+      WebInputEvent::kNoModifiers, CurrentTimeTicksInSeconds(), source_type);
 
   // TODO(dtapuska): Transition the mouseEvent to be created really in viewport
   // coordinates instead of root frame coordinates.
diff --git a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
index 630e831..e6b277c 100644
--- a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
@@ -45,7 +45,7 @@
   TapEventBuilder(IntPoint position, int tap_count)
       : WebGestureEvent(WebInputEvent::kGestureTap,
                         WebInputEvent::kNoModifiers,
-                        CurrentTimeTicks().InSeconds()) {
+                        CurrentTimeTicksInSeconds()) {
     x = global_x = position.X();
     y = global_y = position.Y();
     source_device = kWebGestureDeviceTouchscreen;
@@ -76,7 +76,7 @@
                          WebMouseEvent::Button button_param)
       : WebMouseEvent(WebInputEvent::kMouseDown,
                       WebInputEvent::kNoModifiers,
-                      CurrentTimeTicks().InSeconds()) {
+                      CurrentTimeTicksInSeconds()) {
     click_count = click_count_param;
     button = button_param;
     SetPositionInWidget(position_param.X(), position_param.Y());
@@ -535,11 +535,10 @@
       SelectionInDOMTree::Builder()
           .Collapse(Position(GetDocument().body(), 0))
           .Build());
-  WebMouseEvent mouse_down_event(WebMouseEvent::kMouseDown, WebFloatPoint(0, 0),
-                                 WebFloatPoint(100, 200),
-                                 WebPointerProperties::Button::kRight, 1,
-                                 WebInputEvent::Modifiers::kRightButtonDown,
-                                 CurrentTimeTicks().InSeconds());
+  WebMouseEvent mouse_down_event(
+      WebMouseEvent::kMouseDown, WebFloatPoint(0, 0), WebFloatPoint(100, 200),
+      WebPointerProperties::Button::kRight, 1,
+      WebInputEvent::Modifiers::kRightButtonDown, CurrentTimeTicksInSeconds());
   mouse_down_event.SetFrameScale(1);
   EXPECT_EQ(WebInputEventResult::kHandledApplication,
             GetDocument().GetFrame()->GetEventHandler().SendContextMenuEvent(
@@ -693,20 +692,18 @@
       "<style>.box { width: 100px; height: 100px; display: block; }</style>"
       "<a class='box' href=''>Drag me</a>");
 
-  WebMouseEvent mouse_down_event(WebInputEvent::kMouseDown,
-                                 WebFloatPoint(50, 50), WebFloatPoint(50, 50),
-                                 WebPointerProperties::Button::kLeft, 1,
-                                 WebInputEvent::Modifiers::kLeftButtonDown,
-                                 CurrentTimeTicks().InSeconds());
+  WebMouseEvent mouse_down_event(
+      WebInputEvent::kMouseDown, WebFloatPoint(50, 50), WebFloatPoint(50, 50),
+      WebPointerProperties::Button::kLeft, 1,
+      WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
   mouse_down_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
       mouse_down_event);
 
-  WebMouseEvent mouse_move_event(WebInputEvent::kMouseMove,
-                                 WebFloatPoint(51, 50), WebFloatPoint(51, 50),
-                                 WebPointerProperties::Button::kLeft, 1,
-                                 WebInputEvent::Modifiers::kLeftButtonDown,
-                                 CurrentTimeTicks().InSeconds());
+  WebMouseEvent mouse_move_event(
+      WebInputEvent::kMouseMove, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
+      WebPointerProperties::Button::kLeft, 1,
+      WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
   mouse_move_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
       mouse_move_event, Vector<WebMouseEvent>());
@@ -720,7 +717,7 @@
   WebMouseEvent mouse_up_event(
       WebInputEvent::kMouseUp, WebFloatPoint(100, 50), WebFloatPoint(200, 250),
       WebPointerProperties::Button::kLeft, 1, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_up_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().DragSourceEndedAt(
       mouse_up_event, kDragOperationNone);
@@ -809,7 +806,7 @@
   WebMouseEvent mouse_move_event(
       WebInputEvent::kMouseMove, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
       WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_move_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
       mouse_move_event, Vector<WebMouseEvent>());
@@ -819,7 +816,7 @@
   WebMouseEvent mouse_leave_event(
       WebInputEvent::kMouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0),
       WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_leave_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent(
       mouse_leave_event);
@@ -878,7 +875,7 @@
   WebMouseEvent mouse_press_event(
       WebInputEvent::kMouseDown, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
       WebPointerProperties::Button::kLeft, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_press_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
       mouse_press_event);
@@ -936,7 +933,7 @@
   WebMouseEvent mouse_back_event(
       WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
       WebPointerProperties::Button::kBack, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_back_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
       mouse_back_event);
@@ -946,7 +943,7 @@
   WebMouseEvent mouse_forward_event(
       WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
       WebPointerProperties::Button::kForward, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_forward_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
       mouse_forward_event);
@@ -968,7 +965,7 @@
   WebMouseEvent mouse_back_event(
       WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
       WebPointerProperties::Button::kBack, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_back_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
       mouse_back_event);
@@ -978,7 +975,7 @@
   WebMouseEvent mouse_forward_event(
       WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
       WebPointerProperties::Button::kForward, 0, WebInputEvent::kNoModifiers,
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   mouse_forward_event.SetFrameScale(1);
   GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
       mouse_forward_event);
diff --git a/third_party/WebKit/Source/core/input/EventHandlingUtil.cpp b/third_party/WebKit/Source/core/input/EventHandlingUtil.cpp
index 39a9358..b71fb50 100644
--- a/third_party/WebKit/Source/core/input/EventHandlingUtil.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandlingUtil.cpp
@@ -137,12 +137,14 @@
   if (!layout_object || !layout_object->IsLayoutEmbeddedContent())
     return nullptr;
 
-  LocalFrameView* frame_view =
+  FrameView* frame_view =
       ToLayoutEmbeddedContent(layout_object)->ChildFrameView();
   if (!frame_view)
     return nullptr;
+  if (!frame_view->IsLocalFrameView())
+    return nullptr;
 
-  return &frame_view->GetFrame();
+  return &ToLocalFrameView(frame_view)->GetFrame();
 }
 
 LocalFrame* SubframeForHitTestResult(
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
index 46d0a0feb..469d0915 100644
--- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -341,7 +341,7 @@
                     last_known_mouse_position_.Y()),
       WebFloatPoint(last_known_mouse_global_position_.X(),
                     last_known_mouse_global_position_.Y()),
-      button, 0, modifiers, CurrentTimeTicks().InSeconds());
+      button, 0, modifiers, CurrentTimeTicksInSeconds());
   // TODO(dtapuska): Update m_lastKnowMousePosition to be viewport coordinates.
   fake_mouse_move_event.SetFrameScale(1);
   Vector<WebMouseEvent> coalesced_events;
@@ -558,8 +558,7 @@
   SetLastKnownMousePosition(mouse_event);
   mouse_down_may_start_drag_ = false;
   mouse_down_may_start_autoscroll_ = false;
-  mouse_down_timestamp_ =
-      TimeTicks::FromSeconds(mouse_event.TimeStampSeconds());
+  mouse_down_timestamp_ = TimeTicksFromSeconds(mouse_event.TimeStampSeconds());
 
   if (LocalFrameView* view = frame_->View()) {
     mouse_down_pos_ = view->RootFrameToContents(
@@ -730,7 +729,7 @@
         WebPointerProperties::Button::kLeft, 1,
         modifiers | WebInputEvent::Modifiers::kLeftButtonDown |
             WebInputEvent::Modifiers::kIsCompatibilityEventForTouch,
-        CurrentTimeTicks().InSeconds());
+        CurrentTimeTicksInSeconds());
     mouse_down_ = mouse_down_event;
 
     WebMouseEvent mouse_drag_event(
@@ -738,7 +737,7 @@
         WebPointerProperties::Button::kLeft, 1,
         modifiers | WebInputEvent::Modifiers::kLeftButtonDown |
             WebInputEvent::Modifiers::kIsCompatibilityEventForTouch,
-        CurrentTimeTicks().InSeconds());
+        CurrentTimeTicksInSeconds());
     HitTestRequest request(HitTestRequest::kReadOnly);
     MouseEventWithHitTestResults mev =
         EventHandlingUtil::PerformMouseEventHitTest(frame_, request,
@@ -869,7 +868,7 @@
     Node* node = result.InnerNode();
     if (node) {
       DragController::SelectionDragPolicy selection_drag_policy =
-          TimeTicks::FromSeconds(event.Event().TimeStampSeconds()) -
+          TimeTicksFromSeconds(event.Event().TimeStampSeconds()) -
                       mouse_down_timestamp_ <
                   kTextDragDelay
               ? DragController::kDelayedSelectionDragResolution
@@ -1028,7 +1027,7 @@
       movement.X(), movement.Y(),
       static_cast<WebInputEvent::Modifiers>(event.GetModifiers()), 0,
       MouseEvent::WebInputEventModifiersToButtons(event.GetModifiers()),
-      related_target, TimeTicks::FromSeconds(event.TimeStampSeconds()),
+      related_target, TimeTicksFromSeconds(event.TimeStampSeconds()),
       data_transfer,
       event.FromTouch() ? MouseEvent::kFromTouch
                         : MouseEvent::kRealOrIndistinguishable);
diff --git a/third_party/WebKit/Source/core/input/OverscrollBehaviorTest.cpp b/third_party/WebKit/Source/core/input/OverscrollBehaviorTest.cpp
index 23f08289c..18fe5ced 100644
--- a/third_party/WebKit/Source/core/input/OverscrollBehaviorTest.cpp
+++ b/third_party/WebKit/Source/core/input/OverscrollBehaviorTest.cpp
@@ -69,7 +69,7 @@
 void OverscrollBehaviorTest::ScrollBegin(double hint_x, double hint_y) {
   WebGestureEvent event(WebInputEvent::kGestureScrollBegin,
                         WebInputEvent::kNoModifiers,
-                        CurrentTimeTicks().InSeconds());
+                        CurrentTimeTicksInSeconds());
   event.x = event.global_x = 20;
   event.y = event.global_y = 20;
   event.source_device = WebGestureDevice::kWebGestureDeviceTouchscreen;
@@ -83,7 +83,7 @@
 void OverscrollBehaviorTest::ScrollUpdate(double delta_x, double delta_y) {
   WebGestureEvent event(WebInputEvent::kGestureScrollUpdate,
                         WebInputEvent::kNoModifiers,
-                        CurrentTimeTicks().InSeconds());
+                        CurrentTimeTicksInSeconds());
   event.x = event.global_x = 20;
   event.y = event.global_y = 20;
   event.source_device = WebGestureDevice::kWebGestureDeviceTouchscreen;
@@ -96,7 +96,7 @@
 void OverscrollBehaviorTest::ScrollEnd() {
   WebGestureEvent event(WebInputEvent::kGestureScrollEnd,
                         WebInputEvent::kNoModifiers,
-                        CurrentTimeTicks().InSeconds());
+                        CurrentTimeTicksInSeconds());
   event.x = event.global_x = 20;
   event.y = event.global_y = 20;
   event.source_device = WebGestureDevice::kWebGestureDeviceTouchscreen;
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
index df53dad..e96d0f2 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -252,7 +252,7 @@
     canceled_pointer_events.push_back(
         pointer_event_factory_.CreatePointerCancelEvent(
             PointerEventFactory::kMouseId,
-            TimeTicks::FromSeconds(web_pointer_event.TimeStampSeconds())));
+            TimeTicksFromSeconds(web_pointer_event.TimeStampSeconds())));
   } else {
     // TODO(nzolghadr): Maybe canceling all the scroll capable pointers is not
     // the best strategy here. See the github issue for more details:
@@ -267,7 +267,7 @@
         canceled_pointer_events.push_back(
             pointer_event_factory_.CreatePointerCancelEvent(
                 pointer_id,
-                TimeTicks::FromSeconds(web_pointer_event.TimeStampSeconds())));
+                TimeTicksFromSeconds(web_pointer_event.TimeStampSeconds())));
       }
 
       scroll_capable_pointers_canceled_ = true;
diff --git a/third_party/WebKit/Source/core/input/ScrollManager.cpp b/third_party/WebKit/Source/core/input/ScrollManager.cpp
index 4cb5ac5..290e87f 100644
--- a/third_party/WebKit/Source/core/input/ScrollManager.cpp
+++ b/third_party/WebKit/Source/core/input/ScrollManager.cpp
@@ -540,14 +540,16 @@
       !layout_object->IsLayoutEmbeddedContent())
     return WebInputEventResult::kNotHandled;
 
-  LocalFrameView* frame_view =
+  FrameView* frame_view =
       ToLayoutEmbeddedContent(layout_object)->ChildFrameView();
 
-  if (!frame_view)
+  if (!frame_view || !frame_view->IsLocalFrameView())
     return WebInputEventResult::kNotHandled;
 
-  return frame_view->GetFrame().GetEventHandler().HandleGestureScrollEvent(
-      gesture_event);
+  return ToLocalFrameView(frame_view)
+      ->GetFrame()
+      .GetEventHandler()
+      .HandleGestureScrollEvent(gesture_event);
 }
 
 bool ScrollManager::IsViewportScrollingElement(const Element& element) const {
diff --git a/third_party/WebKit/Source/core/input/ScrollSnapTest.cpp b/third_party/WebKit/Source/core/input/ScrollSnapTest.cpp
index 5f4e3048..ff777e22 100644
--- a/third_party/WebKit/Source/core/input/ScrollSnapTest.cpp
+++ b/third_party/WebKit/Source/core/input/ScrollSnapTest.cpp
@@ -86,7 +86,7 @@
                                  double hint_y) {
   WebGestureEvent event(WebInputEvent::kGestureScrollBegin,
                         WebInputEvent::kNoModifiers,
-                        CurrentTimeTicks().InSeconds());
+                        CurrentTimeTicksInSeconds());
   event.x = event.global_x = x;
   event.y = event.global_y = y;
   event.source_device = WebGestureDevice::kWebGestureDeviceTouchscreen;
@@ -103,7 +103,7 @@
                                   double delta_y) {
   WebGestureEvent event(WebInputEvent::kGestureScrollUpdate,
                         WebInputEvent::kNoModifiers,
-                        CurrentTimeTicks().InSeconds());
+                        CurrentTimeTicksInSeconds());
   event.x = event.global_x = x;
   event.y = event.global_y = y;
   event.source_device = WebGestureDevice::kWebGestureDeviceTouchscreen;
@@ -116,7 +116,7 @@
 void ScrollSnapTest::ScrollEnd(double x, double y) {
   WebGestureEvent event(WebInputEvent::kGestureScrollEnd,
                         WebInputEvent::kNoModifiers,
-                        CurrentTimeTicks().InSeconds());
+                        CurrentTimeTicksInSeconds());
   event.x = event.global_x = x;
   event.y = event.global_y = y;
   event.source_device = WebGestureDevice::kWebGestureDeviceTouchscreen;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
index 03af63f5..5b77895 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -309,7 +309,8 @@
       Unbind(content_document, nodes_map);
   }
 
-  if (ShadowRoot* root = node->GetShadowRoot())
+  for (ShadowRoot* root = node->YoungestShadowRoot(); root;
+       root = root->OlderShadowRoot())
     Unbind(root, nodes_map);
 
   if (node->IsElementNode()) {
@@ -942,6 +943,8 @@
       return nullptr;
     if (node->IsShadowRoot()) {
       const ShadowRoot* shadow_root = ToShadowRoot(node);
+      if (shadow_root->OlderShadowRoot())
+        return shadow_root->OlderShadowRoot();
       Element& host = shadow_root->host();
       if (host.HasChildren())
         return host.firstChild();
@@ -1980,7 +1983,8 @@
   if (!shadow_host_id)
     return;
 
-  if (ShadowRoot* root = shadow_host->GetShadowRoot()) {
+  for (ShadowRoot* root = shadow_host->YoungestShadowRoot(); root;
+       root = root->OlderShadowRoot()) {
     const HeapVector<Member<V0InsertionPoint>>& insertion_points =
         root->DescendantInsertionPoints();
     for (const auto& it : insertion_points) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
index 72771df9..115d596 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
@@ -331,11 +331,12 @@
     BuildLayerIdToNodeIdMap(child, layer_id_to_node_id_map);
   if (!root->GetLayoutObject().IsLayoutIFrame())
     return;
-  LocalFrameView* child_frame_view =
+  FrameView* child_frame_view =
       ToLayoutEmbeddedContent(root->GetLayoutObject()).ChildFrameView();
-  if (!child_frame_view)
+  if (!child_frame_view || !child_frame_view->IsLocalFrameView())
     return;
-  LayoutView* child_layout_view = child_frame_view->GetLayoutView();
+  LayoutView* child_layout_view =
+      ToLocalFrameView(child_frame_view)->GetLayoutView();
   if (!child_layout_view)
     return;
   PaintLayerCompositor* child_compositor = child_layout_view->Compositor();
diff --git a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
index 01558ec0b..9f3a76b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
@@ -88,10 +88,12 @@
   DCHECK_LE(ref_count_, 0);
 }
 
-LocalFrameView* LayoutEmbeddedContent::ChildFrameView() const {
+FrameView* LayoutEmbeddedContent::ChildFrameView() const {
   EmbeddedContentView* embedded_content_view = GetEmbeddedContentView();
-  if (embedded_content_view && embedded_content_view->IsLocalFrameView())
-    return ToLocalFrameView(embedded_content_view);
+
+  if (embedded_content_view && embedded_content_view->IsFrameView())
+    return ToFrameView(embedded_content_view);
+
   return nullptr;
 }
 
@@ -165,15 +167,18 @@
     const HitTestLocation& location_in_container,
     const LayoutPoint& accumulated_offset,
     HitTestAction action) {
-  LocalFrameView* frame_view = ChildFrameView();
-  if (!frame_view || !result.GetHitTestRequest().AllowsChildFrameContent()) {
+  FrameView* frame_view = ChildFrameView();
+  if (!frame_view || !frame_view->IsLocalFrameView() ||
+      !result.GetHitTestRequest().AllowsChildFrameContent()) {
     return NodeAtPointOverEmbeddedContentView(result, location_in_container,
                                               accumulated_offset, action);
   }
 
+  LocalFrameView* local_frame_view = ToLocalFrameView(frame_view);
+
   // A hit test can never hit an off-screen element; only off-screen iframes are
   // throttled; therefore, hit tests can skip descending into throttled iframes.
-  if (frame_view->ShouldThrottleRendering()) {
+  if (local_frame_view->ShouldThrottleRendering()) {
     return NodeAtPointOverEmbeddedContentView(result, location_in_container,
                                               accumulated_offset, action);
   }
@@ -182,14 +187,15 @@
             DocumentLifecycle::kCompositingClean);
 
   if (action == kHitTestForeground) {
-    auto* child_layout_view = frame_view->GetLayoutView();
+    auto* child_layout_view = local_frame_view->GetLayoutView();
 
     if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
         child_layout_view) {
       LayoutPoint adjusted_location = accumulated_offset + Location();
-      LayoutPoint content_offset = LayoutPoint(BorderLeft() + PaddingLeft(),
-                                               BorderTop() + PaddingTop()) -
-                                   LayoutSize(frame_view->ScrollOffsetInt());
+      LayoutPoint content_offset =
+          LayoutPoint(BorderLeft() + PaddingLeft(),
+                      BorderTop() + PaddingTop()) -
+          LayoutSize(local_frame_view->ScrollOffsetInt());
       HitTestLocation new_hit_test_location(
           location_in_container, -adjusted_location - content_offset);
       HitTestRequest new_hit_test_request(result.GetHitTestRequest().GetType() |
@@ -251,8 +257,10 @@
     return;
 
   // If the iframe has custom scrollbars, recalculate their style.
-  if (LocalFrameView* frame_view = ChildFrameView())
-    frame_view->RecalculateCustomScrollbarStyle();
+  if (FrameView* frame_view = ChildFrameView()) {
+    if (frame_view->IsLocalFrameView())
+      ToLocalFrameView(frame_view)->RecalculateCustomScrollbarStyle();
+  }
 
   if (Style()->Visibility() != EVisibility::kVisible) {
     embedded_content_view->Hide();
@@ -354,8 +362,9 @@
 }
 
 bool LayoutEmbeddedContent::IsThrottledFrameView() const {
-  if (LocalFrameView* frame_view = ChildFrameView())
-    return frame_view->ShouldThrottleRendering();
+  FrameView* frame_view = ChildFrameView();
+  if (frame_view && frame_view->IsLocalFrameView())
+    return ToLocalFrameView(frame_view)->ShouldThrottleRendering();
   return false;
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.h b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.h
index e108cd9..3e875baa 100644
--- a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.h
+++ b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.h
@@ -52,7 +52,7 @@
   // with the current Node, if Node is HTMLFrameOwnerElement. This is different
   // to LayoutObject::GetFrameView which returns the LocalFrameView associated
   // with the root Document Frame.
-  LocalFrameView* ChildFrameView() const;
+  FrameView* ChildFrameView() const;
   WebPluginContainerImpl* Plugin() const;
   EmbeddedContentView* GetEmbeddedContentView() const;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp b/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp
index 9ae50fb9..5057c53 100644
--- a/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp
@@ -156,13 +156,13 @@
 bool LayoutEmbeddedObject::NeedsPreferredWidthsRecalculation() const {
   if (LayoutEmbeddedContent::NeedsPreferredWidthsRecalculation())
     return true;
-  LocalFrameView* frame_view = ChildFrameView();
+  FrameView* frame_view = ChildFrameView();
   return frame_view && frame_view->HasIntrinsicSizingInfo();
 }
 
 bool LayoutEmbeddedObject::GetNestedIntrinsicSizingInfo(
     IntrinsicSizingInfo& intrinsic_sizing_info) const {
-  if (LocalFrameView* frame_view = ChildFrameView())
+  if (FrameView* frame_view = ChildFrameView())
     return frame_view->GetIntrinsicSizingInfo(intrinsic_sizing_info);
   return false;
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
index c477305..eb16347b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
@@ -924,10 +924,4 @@
                     Size().Height());
 }
 
-void IntrinsicSizingInfo::Transpose() {
-  size = size.TransposedSize();
-  aspect_ratio = aspect_ratio.TransposedSize();
-  std::swap(has_width, has_height);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.h b/third_party/WebKit/Source/core/layout/LayoutReplaced.h
index ebef7f9..342b5d517 100644
--- a/third_party/WebKit/Source/core/layout/LayoutReplaced.h
+++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.h
@@ -27,17 +27,7 @@
 
 namespace blink {
 
-struct IntrinsicSizingInfo {
-  STACK_ALLOCATED();
-  IntrinsicSizingInfo() : has_width(true), has_height(true) {}
-
-  FloatSize size;
-  FloatSize aspect_ratio;
-  bool has_width;
-  bool has_height;
-
-  void Transpose();
-};
+struct IntrinsicSizingInfo;
 
 // LayoutReplaced is the base class for a replaced element as defined by CSS:
 //
diff --git a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
index 0c8fc7fd..f251e12 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
@@ -537,9 +537,9 @@
   }
 
   if (o.IsLayoutEmbeddedContent()) {
-    LocalFrameView* frame_view = ToLayoutEmbeddedContent(o).ChildFrameView();
-    if (frame_view) {
-      if (auto* layout_view = frame_view->GetLayoutView()) {
+    FrameView* frame_view = ToLayoutEmbeddedContent(o).ChildFrameView();
+    if (frame_view && frame_view->IsLocalFrameView()) {
+      if (auto* layout_view = ToLocalFrameView(frame_view)->GetLayoutView()) {
         layout_view->GetDocument().UpdateStyleAndLayout();
         if (auto* layer = layout_view->Layer()) {
           LayoutTreeAsText::WriteLayers(
diff --git a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
index 574de644..632498a 100644
--- a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
+++ b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
@@ -49,37 +49,34 @@
     WebMouseEvent event(
         WebInputEvent::kMouseMove, WebFloatPoint(x, y), WebFloatPoint(x, y),
         WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
-        CurrentTimeTicks().InSeconds());
+        CurrentTimeTicksInSeconds());
     event.SetFrameScale(1);
     EventHandler().HandleMouseMoveEvent(event, Vector<WebMouseEvent>());
   }
 
   void HandleMousePressEvent(int x, int y) {
-    WebMouseEvent event(WebInputEvent::kMouseDown, WebFloatPoint(x, y),
-                        WebFloatPoint(x, y),
-                        WebPointerProperties::Button::kLeft, 0,
-                        WebInputEvent::Modifiers::kLeftButtonDown,
-                        CurrentTimeTicks().InSeconds());
+    WebMouseEvent event(
+        WebInputEvent::kMouseDown, WebFloatPoint(x, y), WebFloatPoint(x, y),
+        WebPointerProperties::Button::kLeft, 0,
+        WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
     event.SetFrameScale(1);
     EventHandler().HandleMousePressEvent(event);
   }
 
   void HandleMouseReleaseEvent(int x, int y) {
-    WebMouseEvent event(WebInputEvent::kMouseUp, WebFloatPoint(x, y),
-                        WebFloatPoint(x, y),
-                        WebPointerProperties::Button::kLeft, 0,
-                        WebInputEvent::Modifiers::kLeftButtonDown,
-                        CurrentTimeTicks().InSeconds());
+    WebMouseEvent event(
+        WebInputEvent::kMouseUp, WebFloatPoint(x, y), WebFloatPoint(x, y),
+        WebPointerProperties::Button::kLeft, 0,
+        WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
     event.SetFrameScale(1);
     EventHandler().HandleMouseReleaseEvent(event);
   }
 
   void HandleMouseLeaveEvent() {
-    WebMouseEvent event(WebInputEvent::kMouseMove, WebFloatPoint(1, 1),
-                        WebFloatPoint(1, 1),
-                        WebPointerProperties::Button::kLeft, 0,
-                        WebInputEvent::Modifiers::kLeftButtonDown,
-                        CurrentTimeTicks().InSeconds());
+    WebMouseEvent event(
+        WebInputEvent::kMouseMove, WebFloatPoint(1, 1), WebFloatPoint(1, 1),
+        WebPointerProperties::Button::kLeft, 0,
+        WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
     event.SetFrameScale(1);
     EventHandler().HandleMouseLeaveEvent(event);
   }
@@ -417,7 +414,7 @@
   DCHECK(scrollable_area->VerticalScrollbar());
   WebGestureEvent scroll_begin(WebInputEvent::kGestureScrollBegin,
                                WebInputEvent::kNoModifiers,
-                               CurrentTimeTicks().InSeconds());
+                               CurrentTimeTicksInSeconds());
   scroll_begin.x = scroll_begin.global_x =
       scrollable->OffsetLeft() + scrollable->OffsetWidth() - 2;
   scroll_begin.y = scroll_begin.global_y = scrollable->OffsetTop();
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
index 3a09ad0..86abecd 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
@@ -101,6 +101,9 @@
   if (!frame || !frame->GetDocument()->IsSVGDocument())
     return false;
 
+  if (frame->Owner() && frame->Owner()->IsRemote())
+    return true;
+
   // If our frame has an owner layoutObject, we're embedded through eg.
   // object/embed/iframe, but we only negotiate if we're in an SVG document
   // inside a embedded object (object/embed).
@@ -272,14 +275,15 @@
   return false;
 }
 
-void LayoutSVGRoot::IntrinsicDimensionsChanged() const {
+void LayoutSVGRoot::IntrinsicSizingInfoChanged() const {
   // TODO(fs): Merge with IntrinsicSizeChanged()? (from LayoutReplaced)
   // Ignore changes to intrinsic dimensions if the <svg> is not in an SVG
   // document, or not embedded in a way that supports/allows size negotiation.
   if (!IsEmbeddedThroughFrameContainingSVGDocument())
     return;
-  if (FrameOwner* frame_owner = GetFrame()->Owner())
-    frame_owner->IntrinsicDimensionsChanged();
+  IntrinsicSizingInfo sizing_info;
+  ComputeIntrinsicSizingInfo(sizing_info);
+  GetFrame()->IntrinsicSizingInfoChanged(sizing_info);
 }
 
 void LayoutSVGRoot::StyleDidChange(StyleDifference diff,
@@ -295,7 +299,7 @@
   // able to determine our intrinsic dimensions, so in that case always
   // initiate a size negotiation.
   if (!old_style || StyleChangeAffectsIntrinsicSize(*old_style))
-    IntrinsicDimensionsChanged();
+    IntrinsicSizingInfoChanged();
 
   LayoutReplaced::StyleDidChange(diff, old_style);
   SVGResourcesCache::ClientStyleChanged(this, diff, StyleRef());
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
index 355855a..8f278d352 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
@@ -38,7 +38,7 @@
   bool IsEmbeddedThroughSVGImage() const;
   bool IsEmbeddedThroughFrameContainingSVGDocument() const;
 
-  void IntrinsicDimensionsChanged() const;
+  void IntrinsicSizingInfoChanged() const;
   void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
 
   // If you have a LayoutSVGRoot, use firstChild or lastChild instead.
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
index 53162c5..ea89aacd 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -375,34 +375,36 @@
     return exception_state.Reject(script_state);
   }
 
-  ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
-  ScriptPromise promise = resolver->Promise();
+  if (!this->IsPaintable() || size_.IsEmpty()) {
+    exception_state.ThrowDOMException(
+        kIndexSizeError, "The size of the OffscreenCanvas is zero.");
+    return exception_state.Reject(script_state);
+  }
 
-  if (!IsPaintable() || size_.IsEmpty()) {
-    Blob* blob = nullptr;
-    resolver->Resolve(blob);
-    return promise;
+  if (!this->context_) {
+    exception_state.ThrowDOMException(
+        kInvalidStateError, "OffscreenCanvas object has no rendering contexts");
+    return exception_state.Reject(script_state);
   }
 
   double start_time = WTF::CurrentTimeTicksInSeconds();
-
-  CanvasAsyncBlobCreator* async_creator = nullptr;
   scoped_refptr<StaticBitmapImage> snapshot =
-      context_ ? context_->GetImage(kPreferNoAcceleration)
-               : CreateTransparentImage(size_);
+      context_->GetImage(kPreferNoAcceleration);
   if (snapshot) {
+    ScriptPromiseResolver* resolver =
+        ScriptPromiseResolver::Create(script_state);
     String encoding_mime_type = ImageEncoderUtils::ToEncodingMimeType(
         options.type(), ImageEncoderUtils::kEncodeReasonConvertToBlobPromise);
-    async_creator = CanvasAsyncBlobCreator::Create(
+    CanvasAsyncBlobCreator* async_creator = CanvasAsyncBlobCreator::Create(
         snapshot, encoding_mime_type, start_time,
         ExecutionContext::From(script_state), resolver);
     async_creator->ScheduleAsyncBlobCreation(options.quality());
+    return resolver->Promise();
   } else {
-    Blob* blob = nullptr;
-    resolver->Resolve(blob);
+    exception_state.ThrowDOMException(
+        kNotReadableError, "Readback of the source image has failed.");
+    return exception_state.Reject(script_state);
   }
-
-  return promise;
 }
 
 FontSelector* OffscreenCanvas::GetFontSelector() {
diff --git a/third_party/WebKit/Source/core/page/AutoscrollControllerTest.cpp b/third_party/WebKit/Source/core/page/AutoscrollControllerTest.cpp
index 2c40731..0092c6f 100644
--- a/third_party/WebKit/Source/core/page/AutoscrollControllerTest.cpp
+++ b/third_party/WebKit/Source/core/page/AutoscrollControllerTest.cpp
@@ -60,7 +60,7 @@
   WebMouseEvent event(WebInputEvent::kMouseDown, WebFloatPoint(5, 5),
                       WebFloatPoint(5, 5), WebPointerProperties::Button::kLeft,
                       0, WebInputEvent::Modifiers::kLeftButtonDown,
-                      CurrentTimeTicks().InSeconds());
+                      CurrentTimeTicksInSeconds());
   event.SetFrameScale(1);
 
   GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(event);
diff --git a/third_party/WebKit/Source/core/page/CreateWindow.cpp b/third_party/WebKit/Source/core/page/CreateWindow.cpp
index 062c79fe..8213fe7 100644
--- a/third_party/WebKit/Source/core/page/CreateWindow.cpp
+++ b/third_party/WebKit/Source/core/page/CreateWindow.cpp
@@ -145,16 +145,14 @@
 // parsing window features.
 static bool IsWindowFeaturesSeparator(UChar c) {
   return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' ||
-         c == ',' || c == '\0';
+         c == ',' || c == '\f';
 }
 
 WebWindowFeatures GetWindowFeaturesFromString(const String& feature_string) {
   WebWindowFeatures window_features;
 
-  // The IE rule is: all features except for channelmode default
-  // to YES, but if the user specifies a feature string, all features default to
-  // NO. (There is no public standard that applies to this method.)
-  // <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
+  // This code follows the HTML spec, specifically
+  // https://html.spec.whatwg.org/#concept-window-open-features-tokenize
   if (feature_string.IsEmpty())
     return window_features;
 
@@ -163,55 +161,66 @@
   window_features.tool_bar_visible = false;
   window_features.scrollbars_visible = false;
 
-  // Tread lightly in this code -- it was specifically designed to mimic Win
-  // IE's parsing behavior.
   unsigned key_begin, key_end;
   unsigned value_begin, value_end;
 
   String buffer = feature_string.DeprecatedLower();
   unsigned length = buffer.length();
   for (unsigned i = 0; i < length;) {
-    // skip to first non-separator, but don't skip past the end of the string
+    // skip to first non-separator (start of key name), but don't skip
+    // past the end of the string
     while (i < length && IsWindowFeaturesSeparator(buffer[i]))
       i++;
     key_begin = i;
 
-    // skip to first separator
+    // skip to first separator (end of key name), but don't skip past
+    // the end of the string
     while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
       i++;
     key_end = i;
 
     SECURITY_DCHECK(i <= length);
 
-    // skip to first '=', but don't skip past a ',' or the end of the string
+    // skip separators past the key name, except '=', and don't skip past
+    // the end of the string
     while (i < length && buffer[i] != '=') {
-      if (buffer[i] == ',')
+      if (buffer[i] == ',' || !IsWindowFeaturesSeparator(buffer[i]))
         break;
+
       i++;
     }
 
-    SECURITY_DCHECK(i <= length);
+    if (i < length && IsWindowFeaturesSeparator(buffer[i])) {
+      // skip to first non-separator (start of value), but don't skip
+      // past a ',' or the end of the string.
+      while (i < length && IsWindowFeaturesSeparator(buffer[i])) {
+        if (buffer[i] == ',')
+          break;
 
-    // Skip to first non-separator, but don't skip past a ',' or the end of the
-    // string.
-    while (i < length && IsWindowFeaturesSeparator(buffer[i])) {
-      if (buffer[i] == ',')
-        break;
-      i++;
+        i++;
+      }
+
+      value_begin = i;
+
+      SECURITY_DCHECK(i <= length);
+
+      // skip to first separator (end of value)
+      while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
+        i++;
+
+      value_end = i;
+
+      SECURITY_DCHECK(i <= length);
+    } else {
+      // No value given.
+      value_begin = i;
+      value_end = i;
     }
-    value_begin = i;
 
-    SECURITY_DCHECK(i <= length);
-
-    // skip to first separator
-    while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
-      i++;
-    value_end = i;
-
-    SECURITY_DCHECK(i <= length);
-
-    String key_string(buffer.Substring(key_begin, key_end - key_begin));
-    String value_string(buffer.Substring(value_begin, value_end - value_begin));
+    String key_string(
+        buffer.Substring(key_begin, key_end - key_begin).LowerASCII());
+    String value_string(
+        buffer.Substring(value_begin, value_end - value_begin).LowerASCII());
 
     // Listing a key with no value is shorthand for key=yes
     int value;
@@ -220,6 +229,9 @@
     else
       value = value_string.ToInt();
 
+    if (key_string.IsEmpty())
+      continue;
+
     if (key_string == "left" || key_string == "screenx") {
       window_features.x_set = true;
       window_features.x = value;
diff --git a/third_party/WebKit/Source/core/page/DragController.cpp b/third_party/WebKit/Source/core/page/DragController.cpp
index a90f5cd..12803017 100644
--- a/third_party/WebKit/Source/core/page/DragController.cpp
+++ b/third_party/WebKit/Source/core/page/DragController.cpp
@@ -130,7 +130,7 @@
                     drag_data->GlobalPosition().Y()),
       WebPointerProperties::Button::kLeft, 0,
       static_cast<WebInputEvent::Modifiers>(drag_data->GetModifiers()),
-      CurrentTimeTicks().InSeconds());
+      CurrentTimeTicksInSeconds());
   // TODO(dtapuska): Really we should chnage DragData to store the viewport
   // coordinates and scale.
   result.SetFrameScale(1);
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
index f040536e..4e0d4cc 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
@@ -747,7 +747,8 @@
       ToLayoutEmbeddedContent(layout_object);
   ASSERT_TRUE(layout_embedded_content);
 
-  LocalFrameView* inner_frame_view = layout_embedded_content->ChildFrameView();
+  LocalFrameView* inner_frame_view =
+      ToLocalFrameView(layout_embedded_content->ChildFrameView());
   ASSERT_TRUE(inner_frame_view);
 
   auto* inner_layout_view = inner_frame_view->GetLayoutView();
@@ -800,7 +801,8 @@
       ToLayoutEmbeddedContent(layout_object);
   ASSERT_TRUE(layout_embedded_content);
 
-  LocalFrameView* inner_frame_view = layout_embedded_content->ChildFrameView();
+  LocalFrameView* inner_frame_view =
+      ToLocalFrameView(layout_embedded_content->ChildFrameView());
   ASSERT_TRUE(inner_frame_view);
 
   auto* inner_layout_view = inner_frame_view->GetLayoutView();
@@ -979,7 +981,8 @@
       ToLayoutEmbeddedContent(layout_object);
   ASSERT_TRUE(layout_embedded_content);
 
-  LocalFrameView* inner_frame_view = layout_embedded_content->ChildFrameView();
+  LocalFrameView* inner_frame_view =
+      ToLocalFrameView(layout_embedded_content->ChildFrameView());
   ASSERT_TRUE(inner_frame_view);
 
   auto* inner_layout_view = inner_frame_view->GetLayoutView();
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index 6cd4d23..beb50c36 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -61,7 +61,7 @@
                                  const FillLayer& fill_layer,
                                  const LayoutSize& positioning_area_size) {
   StyleImage* image = fill_layer.GetImage();
-  EFillSizeType type = fill_layer.Size().type;
+  EFillSizeType type = fill_layer.SizeType();
 
   LayoutSize image_intrinsic_size(image->ImageSize(
       obj.GetDocument(), obj.Style()->EffectiveZoom(), positioning_area_size));
@@ -69,8 +69,8 @@
     case EFillSizeType::kSizeLength: {
       LayoutSize tile_size(positioning_area_size);
 
-      Length layer_width = fill_layer.Size().size.Width();
-      Length layer_height = fill_layer.Size().size.Height();
+      const Length& layer_width = fill_layer.SizeLength().Width();
+      const Length& layer_height = fill_layer.SizeLength().Height();
 
       if (layer_width.IsFixed())
         tile_size.SetWidth(LayoutUnit(layer_width.Value()));
@@ -633,7 +633,7 @@
     LayoutUnit rounded_width = positioning_area_size.Width() / nr_tiles;
 
     // Maintain aspect ratio if background-size: auto is set
-    if (fill_layer.Size().size.Height().IsAuto() &&
+    if (fill_layer.SizeLength().Height().IsAuto() &&
         background_repeat_y != EFillRepeat::kRoundFill) {
       fill_tile_size.SetHeight(fill_tile_size.Height() * rounded_width /
                                fill_tile_size.Width());
@@ -661,7 +661,7 @@
                                           fill_tile_size.Height()));
     LayoutUnit rounded_height = positioning_area_size.Height() / nr_tiles;
     // Maintain aspect ratio if background-size: auto is set
-    if (fill_layer.Size().size.Width().IsAuto() &&
+    if (fill_layer.SizeLength().Width().IsAuto() &&
         background_repeat_x != EFillRepeat::kRoundFill) {
       fill_tile_size.SetWidth(fill_tile_size.Width() * rounded_height /
                               fill_tile_size.Height());
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
index fe86c72..514f100 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -225,9 +225,8 @@
 
 void BoxPainter::PaintMask(const PaintInfo& paint_info,
                            const LayoutPoint& paint_offset) {
-  DCHECK_EQ(PaintPhase::kMask, paint_info.phase);
-  DCHECK(layout_box_.HasMask());
-  if (layout_box_.Style()->Visibility() != EVisibility::kVisible)
+  if (layout_box_.Style()->Visibility() != EVisibility::kVisible ||
+      paint_info.phase != PaintPhase::kMask)
     return;
 
   if (DrawingRecorder::UseCachedDrawingIfPossible(
@@ -243,10 +242,16 @@
                                  const LayoutRect& paint_rect) {
   // Figure out if we need to push a transparency layer to render our mask.
   bool push_transparency_layer = false;
+  bool flatten_compositing_layers =
+      paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers;
+  bool mask_blending_applied_by_compositor =
+      !flatten_compositing_layers && layout_box_.HasLayer() &&
+      layout_box_.Layer()->MaskBlendingAppliedByCompositor();
+
   bool all_mask_images_loaded = true;
 
-  DCHECK(layout_box_.HasLayer());
-  if (!layout_box_.Layer()->MaskBlendingAppliedByCompositor(paint_info)) {
+  if (!mask_blending_applied_by_compositor &&
+      !RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     push_transparency_layer = true;
     StyleImage* mask_box_image = layout_box_.Style()->MaskBoxImage().GetImage();
     const FillLayer& mask_layers = layout_box_.Style()->MaskLayers();
diff --git a/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp
index 8f672ea..d351362 100644
--- a/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp
@@ -33,6 +33,13 @@
     return;
 
   if (paint_info.phase == PaintPhase::kMask) {
+    if (DrawingRecorder::UseCachedDrawingIfPossible(
+            paint_info.context, inline_flow_box_,
+            DisplayItem::PaintPhaseToDrawingType(paint_info.phase)))
+      return;
+    DrawingRecorder recorder(
+        paint_info.context, inline_flow_box_,
+        DisplayItem::PaintPhaseToDrawingType(paint_info.phase));
     PaintMask(paint_info, paint_offset);
     return;
   }
@@ -336,21 +343,11 @@
 
 void InlineFlowBoxPainter::PaintMask(const PaintInfo& paint_info,
                                      const LayoutPoint& paint_offset) {
-  DCHECK_EQ(PaintPhase::kMask, paint_info.phase);
-  const auto& box_model = *ToLayoutBoxModelObject(
-      LineLayoutAPIShim::LayoutObjectFrom(inline_flow_box_.BoxModelObject()));
-  DCHECK(box_model.HasMask());
-  if (box_model.StyleRef().Visibility() != EVisibility::kVisible)
+  if (inline_flow_box_.GetLineLayoutItem().Style()->Visibility() !=
+          EVisibility::kVisible ||
+      paint_info.phase != PaintPhase::kMask)
     return;
 
-  if (DrawingRecorder::UseCachedDrawingIfPossible(
-          paint_info.context, inline_flow_box_,
-          DisplayItem::PaintPhaseToDrawingType(paint_info.phase)))
-    return;
-  DrawingRecorder recorder(
-      paint_info.context, inline_flow_box_,
-      DisplayItem::PaintPhaseToDrawingType(paint_info.phase));
-
   LayoutRect frame_rect = FrameRectClampedToLineTopAndBottomIfNeeded();
 
   // Move x/y to our coordinates.
@@ -358,32 +355,45 @@
   inline_flow_box_.FlipForWritingMode(local_rect);
   LayoutPoint adjusted_paint_offset = paint_offset + local_rect.Location();
 
-  const auto& mask_nine_piece_image = box_model.StyleRef().MaskBoxImage();
-  const auto* mask_box_image = mask_nine_piece_image.GetImage();
+  const NinePieceImage& mask_nine_piece_image =
+      inline_flow_box_.GetLineLayoutItem().Style()->MaskBoxImage();
+  StyleImage* mask_box_image =
+      inline_flow_box_.GetLineLayoutItem().Style()->MaskBoxImage().GetImage();
 
   // Figure out if we need to push a transparency layer to render our mask.
   bool push_transparency_layer = false;
+  bool flatten_compositing_layers =
+      paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers;
+  bool mask_blending_applied_by_compositor =
+      !flatten_compositing_layers &&
+      inline_flow_box_.GetLineLayoutItem().HasLayer() &&
+      inline_flow_box_.BoxModelObject()
+          .Layer()
+          ->MaskBlendingAppliedByCompositor();
   SkBlendMode composite_op = SkBlendMode::kSrcOver;
-  DCHECK(box_model.HasLayer());
-  if (!box_model.Layer()->MaskBlendingAppliedByCompositor(paint_info)) {
-    if ((mask_box_image && box_model.StyleRef().MaskLayers().HasImage()) ||
-        box_model.StyleRef().MaskLayers().Next()) {
+  if (!mask_blending_applied_by_compositor) {
+    if ((mask_box_image && inline_flow_box_.GetLineLayoutItem()
+                               .Style()
+                               ->MaskLayers()
+                               .HasImage()) ||
+        inline_flow_box_.GetLineLayoutItem().Style()->MaskLayers().Next()) {
       push_transparency_layer = true;
       paint_info.context.BeginLayer(1.0f, SkBlendMode::kDstIn);
     } else {
       // TODO(fmalita): passing a dst-in xfer mode down to
-      // paintFillLayers/paintNinePieceImage seems dangerous: it is only
-      // correct if applied atomically (single draw call). While the heuristic
-      // above presumably ensures that is the case, this approach seems super
-      // fragile. We should investigate dropping this optimization in favour
-      // of the more robust layer branch above.
+      // paintFillLayers/paintNinePieceImage seems dangerous: it is only correct
+      // if applied atomically (single draw call). While the heuristic above
+      // presumably ensures that is the case, this approach seems super fragile.
+      // We should investigate dropping this optimization in favour of the more
+      // robust layer branch above.
       composite_op = SkBlendMode::kDstIn;
     }
   }
 
   LayoutRect paint_rect = LayoutRect(adjusted_paint_offset, frame_rect.Size());
   PaintFillLayers(paint_info, Color::kTransparent,
-                  box_model.StyleRef().MaskLayers(), paint_rect, composite_op);
+                  inline_flow_box_.GetLineLayoutItem().Style()->MaskLayers(),
+                  paint_rect, composite_op);
 
   bool has_box_image = mask_box_image && mask_box_image->CanRender();
   if (!has_box_image || !mask_box_image->IsLoaded()) {
@@ -392,13 +402,16 @@
     return;  // Don't paint anything while we wait for the image to load.
   }
 
+  LayoutBoxModelObject* box_model = ToLayoutBoxModelObject(
+      LineLayoutAPIShim::LayoutObjectFrom(inline_flow_box_.BoxModelObject()));
   // The simple case is where we are the only box for this object. In those
   // cases only a single call to draw is required.
   if (!inline_flow_box_.PrevLineBox() && !inline_flow_box_.NextLineBox()) {
-    NinePieceImagePainter::Paint(paint_info.context, box_model,
-                                 box_model.GetDocument(), GetNode(&box_model),
-                                 paint_rect, box_model.StyleRef(),
-                                 mask_nine_piece_image, composite_op);
+    NinePieceImagePainter::Paint(
+        paint_info.context, *box_model, box_model->GetDocument(),
+        GetNode(box_model), paint_rect,
+        inline_flow_box_.GetLineLayoutItem().StyleRef(), mask_nine_piece_image,
+        composite_op);
   } else {
     // We have a mask image that spans multiple lines.
     // FIXME: What the heck do we do with RTL here? The math we're using is
@@ -410,10 +423,11 @@
     GraphicsContextStateSaver state_saver(paint_info.context);
     // TODO(chrishtr): this should be pixel-snapped.
     paint_info.context.Clip(clip_rect);
-    NinePieceImagePainter::Paint(paint_info.context, box_model,
-                                 box_model.GetDocument(), GetNode(&box_model),
-                                 image_strip_paint_rect, box_model.StyleRef(),
-                                 mask_nine_piece_image, composite_op);
+    NinePieceImagePainter::Paint(
+        paint_info.context, *box_model, box_model->GetDocument(),
+        GetNode(box_model), image_strip_paint_rect,
+        inline_flow_box_.GetLineLayoutItem().StyleRef(), mask_nine_piece_image,
+        composite_op);
   }
 
   if (push_transparency_layer)
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index bbe9f65..47746b03 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -71,7 +71,6 @@
 #include "core/paint/ClipPathClipper.h"
 #include "core/paint/FilterEffectBuilder.h"
 #include "core/paint/ObjectPaintInvalidator.h"
-#include "core/paint/PaintInfo.h"
 #include "core/paint/compositing/CompositedLayerMapping.h"
 #include "core/paint/compositing/PaintLayerCompositor.h"
 #include "platform/LengthFunctions.h"
@@ -2678,15 +2677,10 @@
     grouped_mapping->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
 }
 
-bool PaintLayer::MaskBlendingAppliedByCompositor(
-    const PaintInfo& paint_info) const {
+bool PaintLayer::MaskBlendingAppliedByCompositor() const {
   DCHECK(layout_object_.HasMask());
-  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
     return true;
-
-  if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
-    return false;
-
   return rare_data_ && rare_data_->composited_layer_mapping &&
          rare_data_->composited_layer_mapping->HasMaskLayer();
 }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index 73b09a07..d32d727 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -552,7 +552,7 @@
   };
   void SetGroupedMapping(CompositedLayerMapping*, SetGroupMappingOptions);
 
-  bool MaskBlendingAppliedByCompositor(const PaintInfo&) const;
+  bool MaskBlendingAppliedByCompositor() const;
   bool HasCompositedClippingMask() const;
   bool NeedsCompositedScrolling() const {
     return scrollable_area_ && scrollable_area_->NeedsCompositedScrolling();
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
index c0842526..839f3837 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
@@ -480,10 +480,9 @@
          child = child->NextSibling())
       WriteLayoutObjectNode(*child);
     if (object.IsLayoutEmbeddedContent()) {
-      LocalFrameView* frame_view =
-          ToLayoutEmbeddedContent(object).ChildFrameView();
-      if (frame_view)
-        WriteFrameViewNode(*frame_view, &object);
+      FrameView* frame_view = ToLayoutEmbeddedContent(object).ChildFrameView();
+      if (frame_view && frame_view->IsLocalFrameView())
+        WriteFrameViewNode(*ToLocalFrameView(frame_view), &object);
     }
   }
 
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
index 44e3a39d..8e1c717d 100644
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
@@ -251,17 +251,18 @@
   if (object.IsLayoutEmbeddedContent()) {
     const LayoutEmbeddedContent& layout_embedded_content =
         ToLayoutEmbeddedContent(object);
-    LocalFrameView* frame_view = layout_embedded_content.ChildFrameView();
-    if (frame_view) {
+    FrameView* frame_view = layout_embedded_content.ChildFrameView();
+    if (frame_view && frame_view->IsLocalFrameView()) {
+      LocalFrameView* local_frame_view = ToLocalFrameView(frame_view);
       if (context.tree_builder_context) {
         context.tree_builder_context->fragments[0].current.paint_offset +=
             layout_embedded_content.ReplacedContentRect().Location() -
-            frame_view->FrameRect().Location();
+            local_frame_view->FrameRect().Location();
         context.tree_builder_context->fragments[0].current.paint_offset =
             RoundedIntPoint(context.tree_builder_context->fragments[0]
                                 .current.paint_offset);
       }
-      Walk(*frame_view, context);
+      Walk(*local_frame_view, context);
     }
     // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281).
   }
diff --git a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
index f75381c..5303f5b 100644
--- a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
@@ -275,7 +275,7 @@
                             StyleChangeReasonForTracing::Create(
                                 StyleChangeReason::kSVGContainerSizeChange));
         if (layout_object)
-          ToLayoutSVGRoot(layout_object)->IntrinsicDimensionsChanged();
+          ToLayoutSVGRoot(layout_object)->IntrinsicSizingInfoChanged();
       }
     } else {
       InvalidateSVGPresentationAttributeStyle();
@@ -291,7 +291,7 @@
     if (LayoutObject* object = GetLayoutObject()) {
       object->SetNeedsTransformUpdate();
       if (attr_name == SVGNames::viewBoxAttr && object->IsSVGRoot())
-        ToLayoutSVGRoot(object)->IntrinsicDimensionsChanged();
+        ToLayoutSVGRoot(object)->IntrinsicSizingInfoChanged();
     }
   }
 
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index bd527d1..32b7755 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -757,12 +757,37 @@
 }
 
 ShadowRoot* Internals::shadowRoot(Element* host) {
+  // TODO(kochi): Rewrite all references of youngestShadowRoot and
+  // oldestShadowRoot to shadowRoot.
+  return youngestShadowRoot(host);
+}
+
+ShadowRoot* Internals::youngestShadowRoot(Element* host) {
   DCHECK(host);
   if (ElementShadow* shadow = host->Shadow())
     return &shadow->GetShadowRoot();
   return nullptr;
 }
 
+ShadowRoot* Internals::oldestShadowRoot(Element* host) {
+  DCHECK(host);
+  if (ElementShadow* shadow = host->Shadow())
+    return &shadow->GetShadowRoot();
+  return nullptr;
+}
+
+ShadowRoot* Internals::youngerShadowRoot(Node* shadow,
+                                         ExceptionState& exception_state) {
+  DCHECK(shadow);
+  if (!shadow->IsShadowRoot()) {
+    exception_state.ThrowDOMException(
+        kInvalidAccessError, "The node provided is not a shadow root.");
+    return nullptr;
+  }
+
+  return ToShadowRoot(shadow)->YoungerShadowRoot();
+}
+
 String Internals::shadowRootType(const Node* root,
                                  ExceptionState& exception_state) const {
   DCHECK(root);
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index c88d157..4d2253a 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -115,6 +115,9 @@
   ShadowRoot* createUserAgentShadowRoot(Element* host);
 
   ShadowRoot* shadowRoot(Element* host);
+  ShadowRoot* youngestShadowRoot(Element* host);
+  ShadowRoot* oldestShadowRoot(Element* host);
+  ShadowRoot* youngerShadowRoot(Node* shadow, ExceptionState&);
   String shadowRootType(const Node*, ExceptionState&) const;
   bool hasShadowInsertionPoint(const Node*, ExceptionState&) const;
   bool hasContentElement(const Node*, ExceptionState&) const;
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index cab779a..3096c81 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -49,6 +49,9 @@
     ShadowRoot createUserAgentShadowRoot(Element host);
 
     ShadowRoot shadowRoot(Element host);
+    ShadowRoot youngestShadowRoot(Element host);
+    ShadowRoot oldestShadowRoot(Element host);
+    [RaisesException] ShadowRoot youngerShadowRoot(Node root);
 
     void setBrowserControlsState(float top_height, float bottom_height, boolean shrinksLayout);
     void setBrowserControlsShownRatio(float ratio);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElement.cpp
index d0422ee..57df466a 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElement.cpp
@@ -54,7 +54,7 @@
 // +- #cutoff-4
 // +- #fake-timeline
 void MediaControlLoadingPanelElement::PopulateShadowDOM() {
-  ShadowRoot* shadow_root = GetShadowRoot();
+  ShadowRoot* shadow_root = YoungestShadowRoot();
   DCHECK(!shadow_root->HasChildren());
 
   // This stylesheet element and will contain rules that are specific to the
@@ -125,7 +125,7 @@
 
 void MediaControlLoadingPanelElement::CleanupShadowDOM() {
   // Clear the shadow DOM children and all references to it.
-  ShadowRoot* shadow_root = GetShadowRoot();
+  ShadowRoot* shadow_root = YoungestShadowRoot();
   DCHECK(shadow_root->HasChildren());
   event_listener_->Detach();
   shadow_root->RemoveChildren();
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElementTest.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElementTest.cpp
index ffcec53..33226bc1 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElementTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlLoadingPanelElementTest.cpp
@@ -137,12 +137,12 @@
 
   void CheckIsHidden() {
     EXPECT_FALSE(loading_element_->IsWanted());
-    EXPECT_FALSE(loading_element_->GetShadowRoot()->HasChildren());
+    EXPECT_FALSE(loading_element_->YoungestShadowRoot()->HasChildren());
   }
 
   void CheckIsShown() {
     EXPECT_TRUE(loading_element_->IsWanted());
-    EXPECT_TRUE(loading_element_->GetShadowRoot()->HasChildren());
+    EXPECT_TRUE(loading_element_->YoungestShadowRoot()->HasChildren());
   }
 
   void ExpectAnimationIterationCount(Element* element, const String& value) {
diff --git a/third_party/WebKit/Source/modules/payments/PaymentHandlerUtils.cpp b/third_party/WebKit/Source/modules/payments/PaymentHandlerUtils.cpp
index 7912776..bbcef32 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentHandlerUtils.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentHandlerUtils.cpp
@@ -43,6 +43,7 @@
     case ServiceWorkerResponseError::kBodyLocked:
     case ServiceWorkerResponseError::kRedirectedResponseForNotFollowRequest:
     case ServiceWorkerResponseError::kDataPipeCreationFailed:
+    case ServiceWorkerResponseError::kResponseTypeCORSForRequestModeSameOrigin:
       NOTREACHED();
       error_message = error_message + "an unexpected error occurred.";
       break;
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchRespondWithObserver.cpp b/third_party/WebKit/Source/modules/serviceworkers/FetchRespondWithObserver.cpp
index 2fc6ce9a1..780d083 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/FetchRespondWithObserver.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/FetchRespondWithObserver.cpp
@@ -14,8 +14,6 @@
 #include "core/dom/ExecutionContext.h"
 #include "core/fetch/BodyStreamBuffer.h"
 #include "core/fetch/BytesConsumer.h"
-#include "core/frame/UseCounter.h"
-#include "core/frame/WebFeature.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/inspector/ConsoleTypes.h"
 #include "modules/serviceworkers/ServiceWorkerGlobalScopeClient.h"
@@ -77,6 +75,11 @@
                       "an \"opaqueredirect\" type response was used for a "
                       "request whose redirect mode is not \"manual\".";
       break;
+    case ServiceWorkerResponseError::kResponseTypeCORSForRequestModeSameOrigin:
+      error_message = error_message +
+                      "a \"cors\" type response was used for a request whose "
+                      "mode is \"same-origin\".";
+      break;
     case ServiceWorkerResponseError::kBodyLocked:
       error_message = error_message +
                       "a Response whose \"body\" is locked cannot be used to "
@@ -175,6 +178,7 @@
       ToIsolate(GetExecutionContext()), value.V8Value());
   // "If one of the following conditions is true, return a network error:
   //   - |response|'s type is |error|.
+  //   - |request|'s mode is |same-origin| and |response|'s type is |cors|.
   //   - |request|'s mode is not |no-cors| and response's type is |opaque|.
   //   - |request| is a client request and |response|'s type is neither
   //     |basic| nor |default|."
@@ -184,6 +188,12 @@
     OnResponseRejected(ServiceWorkerResponseError::kResponseTypeError);
     return;
   }
+  if (response_type == network::mojom::FetchResponseType::kCORS &&
+      request_mode_ == network::mojom::FetchRequestMode::kSameOrigin) {
+    OnResponseRejected(
+        ServiceWorkerResponseError::kResponseTypeCORSForRequestModeSameOrigin);
+    return;
+  }
   if (response_type == network::mojom::FetchResponseType::kOpaque) {
     if (request_mode_ != network::mojom::FetchRequestMode::kNoCORS) {
       OnResponseRejected(ServiceWorkerResponseError::kResponseTypeOpaque);
@@ -224,17 +234,6 @@
   WebServiceWorkerResponse web_response;
   response->PopulateWebServiceWorkerResponse(web_response);
 
-  // UseCounter for cross origin CORS responses to "same-origin" requests.
-  // See https://crbug.com/784018.
-  if (request_mode_ == network::mojom::FetchRequestMode::kSameOrigin &&
-      !web_response.UrlList().empty() &&
-      !SecurityOrigin::AreSameSchemeHostPort(
-          request_url_, *(web_response.UrlList().end() - 1))) {
-    UseCounter::Count(
-        GetExecutionContext(),
-        WebFeature::kRespondToSameOriginRequestWithCrossOriginResponse);
-  }
-
   BodyStreamBuffer* buffer = response->InternalBodyBuffer();
   if (buffer) {
     scoped_refptr<BlobDataHandle> blob_data_handle =
diff --git a/third_party/WebKit/Source/platform/Timer.cpp b/third_party/WebKit/Source/platform/Timer.cpp
index 6e709e5..0ba77c1 100644
--- a/third_party/WebKit/Source/platform/Timer.cpp
+++ b/third_party/WebKit/Source/platform/Timer.cpp
@@ -171,7 +171,7 @@
 
 // static
 TimeTicks TimerBase::TimerCurrentTimeTicksInSeconds() const {
-  return TimeTicks::FromSeconds(
+  return TimeTicksFromSeconds(
       TimerTaskRunner()->MonotonicallyIncreasingVirtualTimeSeconds());
 }
 
diff --git a/third_party/WebKit/Source/platform/wtf/BUILD.gn b/third_party/WebKit/Source/platform/wtf/BUILD.gn
index dde0d91c..fb9704e 100644
--- a/third_party/WebKit/Source/platform/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/platform/wtf/BUILD.gn
@@ -344,7 +344,6 @@
     "ScopedLoggerTest.cpp",
     "StringExtrasTest.cpp",
     "StringHasherTest.cpp",
-    "TimeTest.cpp",
     "TreeNodeTest.cpp",
     "TypeTraitsTest.cpp",
     "VectorTest.cpp",
diff --git a/third_party/WebKit/Source/platform/wtf/Time.cpp b/third_party/WebKit/Source/platform/wtf/Time.cpp
index d405bf4..c2fda3e 100644
--- a/third_party/WebKit/Source/platform/wtf/Time.cpp
+++ b/third_party/WebKit/Source/platform/wtf/Time.cpp
@@ -68,4 +68,12 @@
   return CurrentTimeTicks().since_origin().InMillisecondsF();
 }
 
+TimeTicks TimeTicksFromSeconds(double seconds) {
+  return TimeTicks() + TimeDelta::FromSecondsD(seconds);
+}
+
+double TimeTicksInSeconds(TimeTicks ticks) {
+  return (ticks - TimeTicks()).InSecondsF();
+}
+
 }  // namespace WTF
diff --git a/third_party/WebKit/Source/platform/wtf/Time.h b/third_party/WebKit/Source/platform/wtf/Time.h
index 62fee87..0c66f6c 100644
--- a/third_party/WebKit/Source/platform/wtf/Time.h
+++ b/third_party/WebKit/Source/platform/wtf/Time.h
@@ -22,6 +22,7 @@
 
 using TimeDelta = base::TimeDelta;
 using Time = base::Time;
+using TimeTicks = base::TimeTicks;
 
 // Returns the current UTC time in seconds, counted from January 1, 1970.
 // Precision varies depending on platform but is usually as good or better
@@ -44,66 +45,6 @@
 // Allows wtf/Time.h to use the same mock time function
 WTF_EXPORT TimeFunction GetTimeFunctionForTesting();
 
-class TimeTicks {
- public:
-  TimeTicks() = default;
-  TimeTicks(base::TimeTicks value) : value_(value) {}
-
-  static TimeTicks UnixEpoch() {
-    return TimeTicks(base::TimeTicks::UnixEpoch());
-  }
-
-  int64_t ToInternalValueForTesting() const { return value_.ToInternalValue(); }
-
-  // Only use this conversion when interfacing with legacy code that represents
-  // time in double. Converting to double can lead to losing information for
-  // large time values.
-  double InSeconds() const { return (value_ - base::TimeTicks()).InSecondsF(); }
-
-  static TimeTicks FromSeconds(double seconds) {
-    return TimeTicks() + TimeDelta::FromSecondsD(seconds);
-  }
-
-  TimeDelta since_origin() const { return value_.since_origin(); }
-
-  bool is_null() const { return value_.is_null(); }
-
-  operator base::TimeTicks() const { return value_; }
-
-  TimeTicks& operator=(TimeTicks other) {
-    value_ = other.value_;
-    return *this;
-  }
-
-  TimeDelta operator-(TimeTicks other) const { return value_ - other.value_; }
-
-  TimeTicks operator+(TimeDelta delta) const {
-    return TimeTicks(value_ + delta);
-  }
-  TimeTicks operator-(TimeDelta delta) const {
-    return TimeTicks(value_ - delta);
-  }
-
-  TimeTicks& operator+=(TimeDelta delta) {
-    value_ += delta;
-    return *this;
-  }
-  TimeTicks& operator-=(TimeDelta delta) {
-    value_ -= delta;
-    return *this;
-  }
-
-  bool operator==(TimeTicks other) const { return value_ == other.value_; }
-  bool operator!=(TimeTicks other) const { return value_ != other.value_; }
-  bool operator<(TimeTicks other) const { return value_ < other.value_; }
-  bool operator<=(TimeTicks other) const { return value_ <= other.value_; }
-  bool operator>(TimeTicks other) const { return value_ > other.value_; }
-  bool operator>=(TimeTicks other) const { return value_ >= other.value_; }
-
- private:
-  base::TimeTicks value_;
-};
-
 // Monotonically increasing clock time since an arbitrary and unspecified origin
 // time. Mockable using SetTimeFunctionsForTesting().
 WTF_EXPORT TimeTicks CurrentTimeTicks();
@@ -113,6 +54,9 @@
 WTF_EXPORT double CurrentTimeTicksInSeconds();
 WTF_EXPORT double CurrentTimeTicksInMilliseconds();
 
+WTF_EXPORT TimeTicks TimeTicksFromSeconds(double);
+WTF_EXPORT double TimeTicksInSeconds(TimeTicks);
+
 }  // namespace WTF
 
 using WTF::CurrentTime;
@@ -125,5 +69,7 @@
 using WTF::TimeDelta;
 using WTF::TimeFunction;
 using WTF::TimeTicks;
+using WTF::TimeTicksFromSeconds;
+using WTF::TimeTicksInSeconds;
 
 #endif  // Time_h
diff --git a/third_party/WebKit/Source/platform/wtf/TimeTest.cpp b/third_party/WebKit/Source/platform/wtf/TimeTest.cpp
deleted file mode 100644
index 15b762f..0000000
--- a/third_party/WebKit/Source/platform/wtf/TimeTest.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "platform/wtf/Time.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace WTF {
-namespace {
-
-TEST(TimeTicks, NumericOperations) {
-  TimeTicks zero;
-  ASSERT_EQ(0, zero.ToInternalValueForTesting());
-
-  TimeTicks t1 = zero + TimeDelta::FromMilliseconds(1001);
-  ASSERT_EQ(1001000, t1.ToInternalValueForTesting());
-
-  TimeTicks t2 = zero + TimeDelta::FromSeconds(1);
-  ASSERT_EQ(TimeDelta::FromMilliseconds(1), t1 - t2);
-}
-
-}  // namespace
-}  // namespace WTF
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer.py
index f744861..6eab2d7 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer.py
@@ -267,8 +267,6 @@
 
         # Read the base (non-virtual) results.
         results_by_directory = self.read_results_by_directory(self._virtual_base(baseline_name))
-        # Since implicit_all_pass defaults to True, we can also optimize away
-        # redundant all-PASS testharness.js results at the virtual root.
         results_by_port_name = self._results_by_port_name(results_by_directory)
 
         for port_name in self._ports.keys():
@@ -323,18 +321,16 @@
         """Returns the absolute path to the baseline in the given directory."""
         return self._filesystem.join(self._parent_of_tests, directory, baseline_name)
 
-    def _results_by_port_name(self, results_by_directory, implicit_all_pass=True):
+    def _results_by_port_name(self, results_by_directory):
         """Transforms a by-directory result dict to by-port-name.
 
         The method mimicks the baseline search behaviour, i.e. results[port] is
-        the first baseline found on the baseline search path of the port.
+        the first baseline found on the baseline search path of the port. If no
+        baseline is found on the search path, the test is assumed to be an all-
+        PASS testharness.js test.
 
         Args:
             results_by_directory: A dictionary returned by read_results_by_directory().
-            implicit_all_pass: If True, ports with no baselines found will have
-                all-PASS testharness.js results, which matches the real-world
-                behaviour of run-webkit-tests for testharness.js tests.
-                Otherwise, such ports will not be found in the dict.
 
         Returns:
             A dictionary mapping port names to their baselines.
@@ -345,7 +341,7 @@
                 if directory in results_by_directory:
                     results_by_port_name[port_name] = results_by_directory[directory]
                     break
-            if port_name not in results_by_port_name and implicit_all_pass:
+            if port_name not in results_by_port_name:
                 results_by_port_name[port_name] = ALL_PASS
         return results_by_port_name
 
@@ -399,9 +395,7 @@
 
     def _find_optimal_result_placement(self, baseline_name):
         results_by_directory = self.read_results_by_directory(baseline_name)
-        # Set implicit_all_pass=False so that we won't get non-existent all-PASS
-        # testharness.js results, which would break _find_in_search_path.
-        results_by_port_name = self._results_by_port_name(results_by_directory, implicit_all_pass=False)
+        results_by_port_name = self._results_by_port_name(results_by_directory)
 
         new_results_by_directory = self._remove_redundant_results(
             results_by_directory, results_by_port_name)
@@ -459,7 +453,10 @@
         for index, directory in enumerate(search_path):
             if directory in results_by_directory and (results_by_directory[directory] == current_result):
                 return index, directory
-        assert False, 'result %s not found in search path %s, %s' % (current_result, search_path, results_by_directory)
+        assert current_result == ALL_PASS, (
+            'result %s not found in search path %s, %s' % (current_result, search_path, results_by_directory))
+        # Implicit all-PASS at the root.
+        return len(search_path) - 1, search_path[-1]
 
     def _remove_all_pass_testharness_result_at_root(self, baseline_name):
         """Removes the all-PASS testharness.js result at the non-virtual root."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py
index cc7ba469..a7a8515 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py
@@ -27,7 +27,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 import unittest
-import sys
 
 from webkitpy.common.checkout.baseline_optimizer import BaselineOptimizer
 from webkitpy.common.host_mock import MockHost
@@ -305,6 +304,14 @@
             {'platform/linux': ALL_PASS_TESTHARNESS_RESULT},
             {'platform/linux': None})
 
+    def test_all_pass_testharness_at_linux_and_win(self):
+        # https://crbug.com/805008
+        self._assert_optimization(
+            {'platform/linux': ALL_PASS_TESTHARNESS_RESULT,
+             'platform/win': ALL_PASS_TESTHARNESS_RESULT},
+            {'platform/linux': None,
+             'platform/win': None})
+
     def test_all_pass_testharness_at_virtual_root(self):
         self._assert_optimization(
             {'virtual/gpu/fast/canvas': ALL_PASS_TESTHARNESS_RESULT},
diff --git a/third_party/WebKit/common/service_worker/service_worker_error_type.mojom b/third_party/WebKit/common/service_worker/service_worker_error_type.mojom
index aa16afcc..dfa24a1 100644
--- a/third_party/WebKit/common/service_worker/service_worker_error_type.mojom
+++ b/third_party/WebKit/common/service_worker/service_worker_error_type.mojom
@@ -47,7 +47,7 @@
   // kForeignFetchMismatchedOrigin = 13,  // obsolete
   kRedirectedResponseForNotFollowRequest = 14,
   kDataPipeCreationFailed = 15,
+  kResponseTypeCORSForRequestModeSameOrigin = 16,
   // Add a new type here, then update kLast and enums.xml.
-  kLast = kDataPipeCreationFailed
+  kLast = kResponseTypeCORSForRequestModeSameOrigin
 };
-
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 7222f77..48de4ada 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -227,6 +227,7 @@
     "platform/WebInputEvent.h",
     "platform/WebInputEventResult.h",
     "platform/WebInsecureRequestPolicy.h",
+    "platform/WebIntrinsicSizingInfo.h",
     "platform/WebIsolatedWorldIds.h",
     "platform/WebKeyboardEvent.h",
     "platform/WebLayer.h",
diff --git a/third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h b/third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h
new file mode 100644
index 0000000..123fcaec
--- /dev/null
+++ b/third_party/WebKit/public/platform/WebIntrinsicSizingInfo.h
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebIntrinsicSizingInfo_h
+#define WebIntrinsicSizingInfo_h
+
+#include "public/platform/WebFloatSize.h"
+
+namespace blink {
+
+struct WebIntrinsicSizingInfo {
+  WebIntrinsicSizingInfo() : has_width(true), has_height(true) {}
+
+  WebFloatSize size;
+  WebFloatSize aspect_ratio;
+  bool has_width;
+  bool has_height;
+};
+
+}  // namespace blink
+
+#endif  // WebIntrinsicSizingInfo_h
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index 8e5775f..a6fddc6 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1737,7 +1737,7 @@
   kDocumentPageShowRegistered = 2228,
   kDocumentPageShowFired = 2229,
   kReplaceCharsetInXHR = 2230,
-  kRespondToSameOriginRequestWithCrossOriginResponse = 2231,
+  kRespondToSameOriginRequestWithCrossOriginResponse = 2231,  // Obsolete.
   kLinkRelModulePreload = 2232,
   kPerformanceMeasurePassedInObject = 2233,
   kPerformanceMeasurePassedInNavigationTiming = 2234,
diff --git a/third_party/WebKit/public/web/WebRemoteFrame.h b/third_party/WebKit/public/web/WebRemoteFrame.h
index 0cdd934..215eefc7 100644
--- a/third_party/WebKit/public/web/WebRemoteFrame.h
+++ b/third_party/WebKit/public/web/WebRemoteFrame.h
@@ -21,6 +21,7 @@
 class WebRemoteFrameClient;
 class WebString;
 class WebView;
+struct WebIntrinsicSizingInfo;
 struct WebRect;
 struct WebResourceTimingInfo;
 struct WebScrollIntoViewParams;
@@ -120,6 +121,8 @@
   virtual void ScrollRectToVisible(const WebRect&,
                                    const WebScrollIntoViewParams&) = 0;
 
+  virtual void IntrinsicSizingInfoChanged(const WebIntrinsicSizingInfo&) = 0;
+
  protected:
   explicit WebRemoteFrame(WebTreeScopeType scope) : WebFrame(scope) {}
 
diff --git a/third_party/WebKit/public/web/WebWidgetClient.h b/third_party/WebKit/public/web/WebWidgetClient.h
index 2b58f79..8efdb2a5 100644
--- a/third_party/WebKit/public/web/WebWidgetClient.h
+++ b/third_party/WebKit/public/web/WebWidgetClient.h
@@ -34,6 +34,7 @@
 #include "WebNavigationPolicy.h"
 #include "public/platform/WebCommon.h"
 #include "public/platform/WebDragOperation.h"
+#include "public/platform/WebIntrinsicSizingInfo.h"
 #include "public/platform/WebLayerTreeView.h"
 #include "public/platform/WebPoint.h"
 #include "public/platform/WebRect.h"
@@ -74,6 +75,10 @@
   // Called when a call to WebWidget::animate is required
   virtual void ScheduleAnimation() {}
 
+  // A notification callback for when the intrinsic sizing of the
+  // widget changed. This is only called for SVG within a remote frame.
+  virtual void IntrinsicSizingInfoChanged(const WebIntrinsicSizingInfo&) {}
+
   // Called immediately following the first compositor-driven (frame-generating)
   // layout that happened after an interesting document lifecyle change (see
   // WebMeaningfulLayout for details.)
diff --git a/third_party/WebKit/public/web/WebWindowFeatures.h b/third_party/WebKit/public/web/WebWindowFeatures.h
index cf213a9..373798f 100644
--- a/third_party/WebKit/public/web/WebWindowFeatures.h
+++ b/third_party/WebKit/public/web/WebWindowFeatures.h
@@ -34,13 +34,13 @@
 namespace blink {
 
 struct WebWindowFeatures {
-  float x = 0;
+  int x = 0;
   bool x_set = false;
-  float y = 0;
+  int y = 0;
   bool y_set = false;
-  float width = 0;
+  int width = 0;
   bool width_set = false;
-  float height = 0;
+  int height = 0;
   bool height_set = false;
 
   bool menu_bar_visible = true;
diff --git a/third_party/WebKit/public/web/remote_objects.mojom b/third_party/WebKit/public/web/remote_objects.mojom
index 2c0169b..3ea1085 100644
--- a/third_party/WebKit/public/web/remote_objects.mojom
+++ b/third_party/WebKit/public/web/remote_objects.mojom
@@ -20,4 +20,12 @@
 };
 
 struct RemoteInvocationArgument {};
-struct RemoteInvocationResult {};
+
+enum RemoteInvocationError {
+  OK = 0,
+  METHOD_NOT_FOUND,
+};
+
+struct RemoteInvocationResult {
+  RemoteInvocationError error = OK;
+};
diff --git a/third_party/wayland-protocols/BUILD.gn b/third_party/wayland-protocols/BUILD.gn
index 257031a..cbe1b3f 100644
--- a/third_party/wayland-protocols/BUILD.gn
+++ b/third_party/wayland-protocols/BUILD.gn
@@ -301,3 +301,24 @@
 
   public_configs = [ ":keyboard_extension_protocol_config" ]
 }
+
+config("input_timestamps_protocol_config") {
+  include_dirs = [ "include/protocol" ]
+}
+
+source_set("input_timestamps_protocol") {
+  sources = [
+    "include/protocol/input-timestamps-unstable-v1-client-protocol.h",
+    "include/protocol/input-timestamps-unstable-v1-server-protocol.h",
+    "protocol/input-timestamps-v1-protocol.c",
+  ]
+
+  deps = [
+    "//third_party/wayland:wayland_util",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+
+  public_configs = [ ":input_timestamps_protocol_config" ]
+}
diff --git a/third_party/wayland-protocols/README.chromium b/third_party/wayland-protocols/README.chromium
index 3527d0e..c3a3d31 100644
--- a/third_party/wayland-protocols/README.chromium
+++ b/third_party/wayland-protocols/README.chromium
@@ -1,6 +1,6 @@
 Name: wayland-protocols
 URL: http://wayland.freedesktop.org/
-Version: 1.8
+Version: 4f789286e4ab7f6fecc2ccb895d79362a9b2382a
 License: MIT
 License File: src/COPYING
 Security Critical: yes
@@ -13,7 +13,7 @@
 wayland-protocols.
 
 To import a new snapshot of wayland-protocols:
-- Checkout the latest release tag: git checkout 1.8
+- Checkout the latest version: git checkout 4f789286e4ab7f6fecc2ccb895d79362a9b2382a
 - Change the DEPS entry to the newly checked out commit.
 - Update generated files:
     wayland-scanner code < src/unstable/xdg-shell/xdg-shell-unstable-v5.xml > protocol/xdg-shell-v5-protocol.c
@@ -61,6 +61,10 @@
     wayland-scanner code < unstable/keyboard/keyboard-extension-unstable-v1.xml > protocol/keyboard-extension-protocol.c
     wayland-scanner server-header < unstable/keyboard/keyboard-extension-unstable-v1.xml > include/protocol/keyboard-extension-unstable-v1-server-protocol.h
     wayland-scanner client-header < unstable/keyboard/keyboard-extension-unstable-v1.xml > include/protocol/keyboard-extension-unstable-v1-client-protocol.h
+    wayland-scanner code < src/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml > protocol/pointer-gestures-v1-protocol.c
     wayland-scanner client-header < src/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml > include/protocol/pointer-gestures-unstable-v1-client-protocol.h
     wayland-scanner server-header < src/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml > include/protocol/pointer-gestures-unstable-v1-server-protocol.h
+    wayland-scanner code < src/unstable/input-timestamps/input-timestamps-unstable-v1.xml > protocol/input-timestamps-v1-protocol.c
+    wayland-scanner server-header < src/unstable/input-timestamps/input-timestamps-unstable-v1.xml > include/protocol/input-timestamps-unstable-v1-server-protocol.h
+    wayland-scanner client-header < src/unstable/input-timestamps/input-timestamps-unstable-v1.xml > include/protocol/input-timestamps-unstable-v1-client-protocol.h
 - Update this README to reflect the new version number.
diff --git a/third_party/wayland-protocols/include/protocol/input-timestamps-unstable-v1-client-protocol.h b/third_party/wayland-protocols/include/protocol/input-timestamps-unstable-v1-client-protocol.h
new file mode 100644
index 0000000..bef0d50
--- /dev/null
+++ b/third_party/wayland-protocols/include/protocol/input-timestamps-unstable-v1-client-protocol.h
@@ -0,0 +1,326 @@
+/* Generated by wayland-scanner 1.13.0 */
+
+#ifndef INPUT_TIMESTAMPS_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define INPUT_TIMESTAMPS_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_input_timestamps_unstable_v1 The input_timestamps_unstable_v1 protocol
+ * High-resolution timestamps for input events
+ *
+ * @section page_desc_input_timestamps_unstable_v1 Description
+ *
+ * This protocol specifies a way for a client to request and receive
+ * high-resolution timestamps for input events.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ *
+ * @section page_ifaces_input_timestamps_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_input_timestamps_manager_v1 - context object for high-resolution input timestamps
+ * - @subpage page_iface_zwp_input_timestamps_v1 - context object for input timestamps
+ * @section page_copyright_input_timestamps_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2017 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_keyboard;
+struct wl_pointer;
+struct wl_touch;
+struct zwp_input_timestamps_manager_v1;
+struct zwp_input_timestamps_v1;
+
+/**
+ * @page page_iface_zwp_input_timestamps_manager_v1 zwp_input_timestamps_manager_v1
+ * @section page_iface_zwp_input_timestamps_manager_v1_desc Description
+ *
+ * A global interface used for requesting high-resolution timestamps
+ * for input events.
+ * @section page_iface_zwp_input_timestamps_manager_v1_api API
+ * See @ref iface_zwp_input_timestamps_manager_v1.
+ */
+/**
+ * @defgroup iface_zwp_input_timestamps_manager_v1 The zwp_input_timestamps_manager_v1 interface
+ *
+ * A global interface used for requesting high-resolution timestamps
+ * for input events.
+ */
+extern const struct wl_interface zwp_input_timestamps_manager_v1_interface;
+/**
+ * @page page_iface_zwp_input_timestamps_v1 zwp_input_timestamps_v1
+ * @section page_iface_zwp_input_timestamps_v1_desc Description
+ *
+ * Provides high-resolution timestamp events for a set of subscribed input
+ * events. The set of subscribed input events is determined by the
+ * zwp_input_timestamps_manager_v1 request used to create this object.
+ * @section page_iface_zwp_input_timestamps_v1_api API
+ * See @ref iface_zwp_input_timestamps_v1.
+ */
+/**
+ * @defgroup iface_zwp_input_timestamps_v1 The zwp_input_timestamps_v1 interface
+ *
+ * Provides high-resolution timestamp events for a set of subscribed input
+ * events. The set of subscribed input events is determined by the
+ * zwp_input_timestamps_manager_v1 request used to create this object.
+ */
+extern const struct wl_interface zwp_input_timestamps_v1_interface;
+
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_DESTROY 0
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_KEYBOARD_TIMESTAMPS 1
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_POINTER_TIMESTAMPS 2
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_TOUCH_TIMESTAMPS 3
+
+
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_KEYBOARD_TIMESTAMPS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_POINTER_TIMESTAMPS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_TOUCH_TIMESTAMPS_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_input_timestamps_manager_v1 */
+static inline void
+zwp_input_timestamps_manager_v1_set_user_data(struct zwp_input_timestamps_manager_v1 *zwp_input_timestamps_manager_v1, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zwp_input_timestamps_manager_v1, user_data);
+}
+
+/** @ingroup iface_zwp_input_timestamps_manager_v1 */
+static inline void *
+zwp_input_timestamps_manager_v1_get_user_data(struct zwp_input_timestamps_manager_v1 *zwp_input_timestamps_manager_v1)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zwp_input_timestamps_manager_v1);
+}
+
+static inline uint32_t
+zwp_input_timestamps_manager_v1_get_version(struct zwp_input_timestamps_manager_v1 *zwp_input_timestamps_manager_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_input_timestamps_manager_v1);
+}
+
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ *
+ * Informs the server that the client will no longer be using this
+ * protocol object. Existing objects created by this object are not
+ * affected.
+ */
+static inline void
+zwp_input_timestamps_manager_v1_destroy(struct zwp_input_timestamps_manager_v1 *zwp_input_timestamps_manager_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zwp_input_timestamps_manager_v1,
+			 ZWP_INPUT_TIMESTAMPS_MANAGER_V1_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) zwp_input_timestamps_manager_v1);
+}
+
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ *
+ * Creates a new input timestamps object that represents a subscription
+ * to high-resolution timestamp events for all wl_keyboard events that
+ * carry a timestamp.
+ *
+ * If the associated wl_keyboard object is invalidated, either through
+ * client action (e.g. release) or server-side changes, the input
+ * timestamps object becomes inert and the client should destroy it
+ * by calling zwp_input_timestamps_v1.destroy.
+ */
+static inline struct zwp_input_timestamps_v1 *
+zwp_input_timestamps_manager_v1_get_keyboard_timestamps(struct zwp_input_timestamps_manager_v1 *zwp_input_timestamps_manager_v1, struct wl_keyboard *keyboard)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_input_timestamps_manager_v1,
+			 ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_KEYBOARD_TIMESTAMPS, &zwp_input_timestamps_v1_interface, NULL, keyboard);
+
+	return (struct zwp_input_timestamps_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ *
+ * Creates a new input timestamps object that represents a subscription
+ * to high-resolution timestamp events for all wl_pointer events that
+ * carry a timestamp.
+ *
+ * If the associated wl_pointer object is invalidated, either through
+ * client action (e.g. release) or server-side changes, the input
+ * timestamps object becomes inert and the client should destroy it
+ * by calling zwp_input_timestamps_v1.destroy.
+ */
+static inline struct zwp_input_timestamps_v1 *
+zwp_input_timestamps_manager_v1_get_pointer_timestamps(struct zwp_input_timestamps_manager_v1 *zwp_input_timestamps_manager_v1, struct wl_pointer *pointer)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_input_timestamps_manager_v1,
+			 ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_POINTER_TIMESTAMPS, &zwp_input_timestamps_v1_interface, NULL, pointer);
+
+	return (struct zwp_input_timestamps_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ *
+ * Creates a new input timestamps object that represents a subscription
+ * to high-resolution timestamp events for all wl_touch events that
+ * carry a timestamp.
+ *
+ * If the associated wl_touch object becomes invalid, either through
+ * client action (e.g. release) or server-side changes, the input
+ * timestamps object becomes inert and the client should destroy it
+ * by calling zwp_input_timestamps_v1.destroy.
+ */
+static inline struct zwp_input_timestamps_v1 *
+zwp_input_timestamps_manager_v1_get_touch_timestamps(struct zwp_input_timestamps_manager_v1 *zwp_input_timestamps_manager_v1, struct wl_touch *touch)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_input_timestamps_manager_v1,
+			 ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_TOUCH_TIMESTAMPS, &zwp_input_timestamps_v1_interface, NULL, touch);
+
+	return (struct zwp_input_timestamps_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ * @struct zwp_input_timestamps_v1_listener
+ */
+struct zwp_input_timestamps_v1_listener {
+	/**
+	 * high-resolution timestamp event
+	 *
+	 * The timestamp event is associated with the first subsequent
+	 * input event carrying a timestamp which belongs to the set of
+	 * input events this object is subscribed to.
+	 *
+	 * The timestamp provided by this event is a high-resolution
+	 * version of the timestamp argument of the associated input event.
+	 * The provided timestamp is in the same clock domain and is at
+	 * least as accurate as the associated input event timestamp.
+	 *
+	 * The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec
+	 * triples, each component being an unsigned 32-bit value. Whole
+	 * seconds are in tv_sec which is a 64-bit value combined from
+	 * tv_sec_hi and tv_sec_lo, and the additional fractional part in
+	 * tv_nsec as nanoseconds. Hence, for valid timestamps tv_nsec must
+	 * be in [0, 999999999].
+	 * @param tv_sec_hi high 32 bits of the seconds part of the timestamp
+	 * @param tv_sec_lo low 32 bits of the seconds part of the timestamp
+	 * @param tv_nsec nanoseconds part of the timestamp
+	 */
+	void (*timestamp)(void *data,
+			  struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
+			  uint32_t tv_sec_hi,
+			  uint32_t tv_sec_lo,
+			  uint32_t tv_nsec);
+};
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ */
+static inline int
+zwp_input_timestamps_v1_add_listener(struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
+				     const struct zwp_input_timestamps_v1_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) zwp_input_timestamps_v1,
+				     (void (**)(void)) listener, data);
+}
+
+#define ZWP_INPUT_TIMESTAMPS_V1_DESTROY 0
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_V1_TIMESTAMP_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_input_timestamps_v1 */
+static inline void
+zwp_input_timestamps_v1_set_user_data(struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zwp_input_timestamps_v1, user_data);
+}
+
+/** @ingroup iface_zwp_input_timestamps_v1 */
+static inline void *
+zwp_input_timestamps_v1_get_user_data(struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zwp_input_timestamps_v1);
+}
+
+static inline uint32_t
+zwp_input_timestamps_v1_get_version(struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_input_timestamps_v1);
+}
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ *
+ * Informs the server that the client will no longer be using this
+ * protocol object. After the server processes the request, no more
+ * timestamp events will be emitted.
+ */
+static inline void
+zwp_input_timestamps_v1_destroy(struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zwp_input_timestamps_v1,
+			 ZWP_INPUT_TIMESTAMPS_V1_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) zwp_input_timestamps_v1);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/wayland-protocols/include/protocol/input-timestamps-unstable-v1-server-protocol.h b/third_party/wayland-protocols/include/protocol/input-timestamps-unstable-v1-server-protocol.h
new file mode 100644
index 0000000..65d9cee
--- /dev/null
+++ b/third_party/wayland-protocols/include/protocol/input-timestamps-unstable-v1-server-protocol.h
@@ -0,0 +1,235 @@
+/* Generated by wayland-scanner 1.13.0 */
+
+#ifndef INPUT_TIMESTAMPS_UNSTABLE_V1_SERVER_PROTOCOL_H
+#define INPUT_TIMESTAMPS_UNSTABLE_V1_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_input_timestamps_unstable_v1 The input_timestamps_unstable_v1 protocol
+ * High-resolution timestamps for input events
+ *
+ * @section page_desc_input_timestamps_unstable_v1 Description
+ *
+ * This protocol specifies a way for a client to request and receive
+ * high-resolution timestamps for input events.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ *
+ * @section page_ifaces_input_timestamps_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_input_timestamps_manager_v1 - context object for high-resolution input timestamps
+ * - @subpage page_iface_zwp_input_timestamps_v1 - context object for input timestamps
+ * @section page_copyright_input_timestamps_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2017 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_keyboard;
+struct wl_pointer;
+struct wl_touch;
+struct zwp_input_timestamps_manager_v1;
+struct zwp_input_timestamps_v1;
+
+/**
+ * @page page_iface_zwp_input_timestamps_manager_v1 zwp_input_timestamps_manager_v1
+ * @section page_iface_zwp_input_timestamps_manager_v1_desc Description
+ *
+ * A global interface used for requesting high-resolution timestamps
+ * for input events.
+ * @section page_iface_zwp_input_timestamps_manager_v1_api API
+ * See @ref iface_zwp_input_timestamps_manager_v1.
+ */
+/**
+ * @defgroup iface_zwp_input_timestamps_manager_v1 The zwp_input_timestamps_manager_v1 interface
+ *
+ * A global interface used for requesting high-resolution timestamps
+ * for input events.
+ */
+extern const struct wl_interface zwp_input_timestamps_manager_v1_interface;
+/**
+ * @page page_iface_zwp_input_timestamps_v1 zwp_input_timestamps_v1
+ * @section page_iface_zwp_input_timestamps_v1_desc Description
+ *
+ * Provides high-resolution timestamp events for a set of subscribed input
+ * events. The set of subscribed input events is determined by the
+ * zwp_input_timestamps_manager_v1 request used to create this object.
+ * @section page_iface_zwp_input_timestamps_v1_api API
+ * See @ref iface_zwp_input_timestamps_v1.
+ */
+/**
+ * @defgroup iface_zwp_input_timestamps_v1 The zwp_input_timestamps_v1 interface
+ *
+ * Provides high-resolution timestamp events for a set of subscribed input
+ * events. The set of subscribed input events is determined by the
+ * zwp_input_timestamps_manager_v1 request used to create this object.
+ */
+extern const struct wl_interface zwp_input_timestamps_v1_interface;
+
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ * @struct zwp_input_timestamps_manager_v1_interface
+ */
+struct zwp_input_timestamps_manager_v1_interface {
+	/**
+	 * destroy the input timestamps manager object
+	 *
+	 * Informs the server that the client will no longer be using
+	 * this protocol object. Existing objects created by this object
+	 * are not affected.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * subscribe to high-resolution keyboard timestamp events
+	 *
+	 * Creates a new input timestamps object that represents a
+	 * subscription to high-resolution timestamp events for all
+	 * wl_keyboard events that carry a timestamp.
+	 *
+	 * If the associated wl_keyboard object is invalidated, either
+	 * through client action (e.g. release) or server-side changes, the
+	 * input timestamps object becomes inert and the client should
+	 * destroy it by calling zwp_input_timestamps_v1.destroy.
+	 * @param keyboard the wl_keyboard object for which to get timestamp events
+	 */
+	void (*get_keyboard_timestamps)(struct wl_client *client,
+					struct wl_resource *resource,
+					uint32_t id,
+					struct wl_resource *keyboard);
+	/**
+	 * subscribe to high-resolution pointer timestamp events
+	 *
+	 * Creates a new input timestamps object that represents a
+	 * subscription to high-resolution timestamp events for all
+	 * wl_pointer events that carry a timestamp.
+	 *
+	 * If the associated wl_pointer object is invalidated, either
+	 * through client action (e.g. release) or server-side changes, the
+	 * input timestamps object becomes inert and the client should
+	 * destroy it by calling zwp_input_timestamps_v1.destroy.
+	 * @param pointer the wl_pointer object for which to get timestamp events
+	 */
+	void (*get_pointer_timestamps)(struct wl_client *client,
+				       struct wl_resource *resource,
+				       uint32_t id,
+				       struct wl_resource *pointer);
+	/**
+	 * subscribe to high-resolution touch timestamp events
+	 *
+	 * Creates a new input timestamps object that represents a
+	 * subscription to high-resolution timestamp events for all
+	 * wl_touch events that carry a timestamp.
+	 *
+	 * If the associated wl_touch object becomes invalid, either
+	 * through client action (e.g. release) or server-side changes, the
+	 * input timestamps object becomes inert and the client should
+	 * destroy it by calling zwp_input_timestamps_v1.destroy.
+	 * @param touch the wl_touch object for which to get timestamp events
+	 */
+	void (*get_touch_timestamps)(struct wl_client *client,
+				     struct wl_resource *resource,
+				     uint32_t id,
+				     struct wl_resource *touch);
+};
+
+
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_KEYBOARD_TIMESTAMPS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_POINTER_TIMESTAMPS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_input_timestamps_manager_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_MANAGER_V1_GET_TOUCH_TIMESTAMPS_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ * @struct zwp_input_timestamps_v1_interface
+ */
+struct zwp_input_timestamps_v1_interface {
+	/**
+	 * destroy the input timestamps object
+	 *
+	 * Informs the server that the client will no longer be using
+	 * this protocol object. After the server processes the request, no
+	 * more timestamp events will be emitted.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define ZWP_INPUT_TIMESTAMPS_V1_TIMESTAMP 0
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_V1_TIMESTAMP_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ */
+#define ZWP_INPUT_TIMESTAMPS_V1_DESTROY_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_input_timestamps_v1
+ * Sends an timestamp event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param tv_sec_hi high 32 bits of the seconds part of the timestamp
+ * @param tv_sec_lo low 32 bits of the seconds part of the timestamp
+ * @param tv_nsec nanoseconds part of the timestamp
+ */
+static inline void
+zwp_input_timestamps_v1_send_timestamp(struct wl_resource *resource_, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec)
+{
+	wl_resource_post_event(resource_, ZWP_INPUT_TIMESTAMPS_V1_TIMESTAMP, tv_sec_hi, tv_sec_lo, tv_nsec);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-client-protocol.h b/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-client-protocol.h
index 7b7daab..415dd83 100644
--- a/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-client-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-client-protocol.h
@@ -1,46 +1,202 @@
+/* Generated by wayland-scanner 1.13.0 */
+
 #ifndef POINTER_GESTURES_UNSTABLE_V1_CLIENT_PROTOCOL_H
 #define POINTER_GESTURES_UNSTABLE_V1_CLIENT_PROTOCOL_H
 
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
 #include <stdint.h>
 #include <stddef.h>
 #include "wayland-client.h"
 
-struct wl_client;
-struct wl_resource;
+#ifdef  __cplusplus
+extern "C" {
+#endif
 
-struct zwp_pointer_gestures_v1;
-struct zwp_pointer_gesture_swipe_v1;
+/**
+ * @page page_pointer_gestures_unstable_v1 The pointer_gestures_unstable_v1 protocol
+ * @section page_ifaces_pointer_gestures_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_pointer_gestures_v1 - touchpad gestures
+ * - @subpage page_iface_zwp_pointer_gesture_swipe_v1 - a swipe gesture object
+ * - @subpage page_iface_zwp_pointer_gesture_pinch_v1 - a pinch gesture object
+ */
+struct wl_pointer;
+struct wl_surface;
 struct zwp_pointer_gesture_pinch_v1;
+struct zwp_pointer_gesture_swipe_v1;
+struct zwp_pointer_gestures_v1;
 
+/**
+ * @page page_iface_zwp_pointer_gestures_v1 zwp_pointer_gestures_v1
+ * @section page_iface_zwp_pointer_gestures_v1_desc Description
+ *
+ * A global interface to provide semantic touchpad gestures for a given
+ * pointer.
+ *
+ * Two gestures are currently supported: swipe and zoom/rotate.
+ * All gestures follow a three-stage cycle: begin, update, end and
+ * are identified by a unique id.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ * @section page_iface_zwp_pointer_gestures_v1_api API
+ * See @ref iface_zwp_pointer_gestures_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_gestures_v1 The zwp_pointer_gestures_v1 interface
+ *
+ * A global interface to provide semantic touchpad gestures for a given
+ * pointer.
+ *
+ * Two gestures are currently supported: swipe and zoom/rotate.
+ * All gestures follow a three-stage cycle: begin, update, end and
+ * are identified by a unique id.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ */
 extern const struct wl_interface zwp_pointer_gestures_v1_interface;
+/**
+ * @page page_iface_zwp_pointer_gesture_swipe_v1 zwp_pointer_gesture_swipe_v1
+ * @section page_iface_zwp_pointer_gesture_swipe_v1_desc Description
+ *
+ * A swipe gesture object notifies a client about a multi-finger swipe
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving in the
+ * same direction but once initiated the direction may change.
+ * The precise conditions of when such a gesture is detected are
+ * implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ * @section page_iface_zwp_pointer_gesture_swipe_v1_api API
+ * See @ref iface_zwp_pointer_gesture_swipe_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_gesture_swipe_v1 The zwp_pointer_gesture_swipe_v1 interface
+ *
+ * A swipe gesture object notifies a client about a multi-finger swipe
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving in the
+ * same direction but once initiated the direction may change.
+ * The precise conditions of when such a gesture is detected are
+ * implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ */
 extern const struct wl_interface zwp_pointer_gesture_swipe_v1_interface;
+/**
+ * @page page_iface_zwp_pointer_gesture_pinch_v1 zwp_pointer_gesture_pinch_v1
+ * @section page_iface_zwp_pointer_gesture_pinch_v1_desc Description
+ *
+ * A pinch gesture object notifies a client about a multi-finger pinch
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving towards
+ * each other or away from each other, or by two or more fingers rotating
+ * around a logical center of gravity. The precise conditions of when
+ * such a gesture is detected are implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ * @section page_iface_zwp_pointer_gesture_pinch_v1_api API
+ * See @ref iface_zwp_pointer_gesture_pinch_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_gesture_pinch_v1 The zwp_pointer_gesture_pinch_v1 interface
+ *
+ * A pinch gesture object notifies a client about a multi-finger pinch
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving towards
+ * each other or away from each other, or by two or more fingers rotating
+ * around a logical center of gravity. The precise conditions of when
+ * such a gesture is detected are implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ */
 extern const struct wl_interface zwp_pointer_gesture_pinch_v1_interface;
 
-#define ZWP_POINTER_GESTURES_V1_GET_SWIPE_GESTURE	0
-#define ZWP_POINTER_GESTURES_V1_GET_PINCH_GESTURE	1
+#define ZWP_POINTER_GESTURES_V1_GET_SWIPE_GESTURE 0
+#define ZWP_POINTER_GESTURES_V1_GET_PINCH_GESTURE 1
 
+
+/**
+ * @ingroup iface_zwp_pointer_gestures_v1
+ */
+#define ZWP_POINTER_GESTURES_V1_GET_SWIPE_GESTURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gestures_v1
+ */
+#define ZWP_POINTER_GESTURES_V1_GET_PINCH_GESTURE_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_pointer_gestures_v1 */
 static inline void
 zwp_pointer_gestures_v1_set_user_data(struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1, void *user_data)
 {
 	wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_gestures_v1, user_data);
 }
 
+/** @ingroup iface_zwp_pointer_gestures_v1 */
 static inline void *
 zwp_pointer_gestures_v1_get_user_data(struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1)
 {
 	return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_gestures_v1);
 }
 
+static inline uint32_t
+zwp_pointer_gestures_v1_get_version(struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_gestures_v1);
+}
+
+/** @ingroup iface_zwp_pointer_gestures_v1 */
 static inline void
 zwp_pointer_gestures_v1_destroy(struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1)
 {
 	wl_proxy_destroy((struct wl_proxy *) zwp_pointer_gestures_v1);
 }
 
+/**
+ * @ingroup iface_zwp_pointer_gestures_v1
+ *
+ * Create a swipe gesture object. See the
+ * wl_pointer_gesture_swipe interface for details.
+ */
 static inline struct zwp_pointer_gesture_swipe_v1 *
 zwp_pointer_gestures_v1_get_swipe_gesture(struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1, struct wl_pointer *pointer)
 {
@@ -52,6 +208,12 @@
 	return (struct zwp_pointer_gesture_swipe_v1 *) id;
 }
 
+/**
+ * @ingroup iface_zwp_pointer_gestures_v1
+ *
+ * Create a pinch gesture object. See the
+ * wl_pointer_gesture_pinch interface for details.
+ */
 static inline struct zwp_pointer_gesture_pinch_v1 *
 zwp_pointer_gestures_v1_get_pinch_gesture(struct zwp_pointer_gestures_v1 *zwp_pointer_gestures_v1, struct wl_pointer *pointer)
 {
@@ -64,37 +226,17 @@
 }
 
 /**
- * zwp_pointer_gesture_swipe_v1 - a swipe gesture object
- * @begin: multi-finger swipe begin
- * @update: multi-finger swipe motion
- * @end: multi-finger swipe end
- *
- * A swipe gesture object notifies a client about a multi-finger swipe
- * gesture detected on an indirect input device such as a touchpad. The
- * gesture is usually initiated by multiple fingers moving in the same
- * direction but once initiated the direction may change. The precise
- * conditions of when such a gesture is detected are
- * implementation-dependent.
- *
- * A gesture consists of three stages: begin, update (optional) and end.
- * There cannot be multiple simultaneous pinch or swipe gestures on a same
- * pointer/seat, how compositors prevent these situations is
- * implementation-dependent.
- *
- * A gesture may be cancelled by the compositor or the hardware. Clients
- * should not consider performing permanent or irreversible actions until
- * the end of a gesture has been received.
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ * @struct zwp_pointer_gesture_swipe_v1_listener
  */
 struct zwp_pointer_gesture_swipe_v1_listener {
 	/**
-	 * begin - multi-finger swipe begin
-	 * @serial: (none)
-	 * @time: timestamp with millisecond granularity
-	 * @surface: (none)
-	 * @fingers: number of fingers
+	 * multi-finger swipe begin
 	 *
 	 * This event is sent when a multi-finger swipe gesture is
 	 * detected on the device.
+	 * @param time timestamp with millisecond granularity
+	 * @param fingers number of fingers
 	 */
 	void (*begin)(void *data,
 		      struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
@@ -103,16 +245,16 @@
 		      struct wl_surface *surface,
 		      uint32_t fingers);
 	/**
-	 * update - multi-finger swipe motion
-	 * @time: timestamp with millisecond granularity
-	 * @dx: delta x coordinate in surface coordinate space
-	 * @dy: delta y coordinate in surface coordinate space
+	 * multi-finger swipe motion
 	 *
 	 * This event is sent when a multi-finger swipe gesture changes
 	 * the position of the logical center.
 	 *
 	 * The dx and dy coordinates are relative coordinates of the
 	 * logical center of the gesture compared to the previous event.
+	 * @param time timestamp with millisecond granularity
+	 * @param dx delta x coordinate in surface coordinate space
+	 * @param dy delta y coordinate in surface coordinate space
 	 */
 	void (*update)(void *data,
 		       struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
@@ -120,10 +262,7 @@
 		       wl_fixed_t dx,
 		       wl_fixed_t dy);
 	/**
-	 * end - multi-finger swipe end
-	 * @serial: (none)
-	 * @time: timestamp with millisecond granularity
-	 * @cancelled: 1 if the gesture was cancelled, 0 otherwise
+	 * multi-finger swipe end
 	 *
 	 * This event is sent when a multi-finger swipe gesture ceases to
 	 * be valid. This may happen when one or more fingers are lifted or
@@ -132,6 +271,8 @@
 	 * When a gesture is cancelled, the client should undo state
 	 * changes caused by this gesture. What causes a gesture to be
 	 * cancelled is implementation-dependent.
+	 * @param time timestamp with millisecond granularity
+	 * @param cancelled 1 if the gesture was cancelled, 0 otherwise
 	 */
 	void (*end)(void *data,
 		    struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
@@ -140,6 +281,9 @@
 		    int32_t cancelled);
 };
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
 static inline int
 zwp_pointer_gesture_swipe_v1_add_listener(struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
 					  const struct zwp_pointer_gesture_swipe_v1_listener *listener, void *data)
@@ -148,20 +292,49 @@
 				     (void (**)(void)) listener, data);
 }
 
-#define ZWP_POINTER_GESTURE_SWIPE_V1_DESTROY	0
+#define ZWP_POINTER_GESTURE_SWIPE_V1_DESTROY 0
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_BEGIN_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_UPDATE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_END_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_pointer_gesture_swipe_v1 */
 static inline void
 zwp_pointer_gesture_swipe_v1_set_user_data(struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, void *user_data)
 {
 	wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_gesture_swipe_v1, user_data);
 }
 
+/** @ingroup iface_zwp_pointer_gesture_swipe_v1 */
 static inline void *
 zwp_pointer_gesture_swipe_v1_get_user_data(struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1)
 {
 	return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_gesture_swipe_v1);
 }
 
+static inline uint32_t
+zwp_pointer_gesture_swipe_v1_get_version(struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_gesture_swipe_v1);
+}
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
 static inline void
 zwp_pointer_gesture_swipe_v1_destroy(struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1)
 {
@@ -172,37 +345,17 @@
 }
 
 /**
- * zwp_pointer_gesture_pinch_v1 - a pinch gesture object
- * @begin: multi-finger pinch begin
- * @update: multi-finger pinch motion
- * @end: multi-finger pinch end
- *
- * A pinch gesture object notifies a client about a multi-finger pinch
- * gesture detected on an indirect input device such as a touchpad. The
- * gesture is usually initiated by multiple fingers moving towards each
- * other or away from each other, or by two or more fingers rotating around
- * a logical center of gravity. The precise conditions of when such a
- * gesture is detected are implementation-dependent.
- *
- * A gesture consists of three stages: begin, update (optional) and end.
- * There cannot be multiple simultaneous pinch or swipe gestures on a same
- * pointer/seat, how compositors prevent these situations is
- * implementation-dependent.
- *
- * A gesture may be cancelled by the compositor or the hardware. Clients
- * should not consider performing permanent or irreversible actions until
- * the end of a gesture has been received.
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ * @struct zwp_pointer_gesture_pinch_v1_listener
  */
 struct zwp_pointer_gesture_pinch_v1_listener {
 	/**
-	 * begin - multi-finger pinch begin
-	 * @serial: (none)
-	 * @time: timestamp with millisecond granularity
-	 * @surface: (none)
-	 * @fingers: number of fingers
+	 * multi-finger pinch begin
 	 *
 	 * This event is sent when a multi-finger pinch gesture is
 	 * detected on the device.
+	 * @param time timestamp with millisecond granularity
+	 * @param fingers number of fingers
 	 */
 	void (*begin)(void *data,
 		      struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
@@ -211,12 +364,7 @@
 		      struct wl_surface *surface,
 		      uint32_t fingers);
 	/**
-	 * update - multi-finger pinch motion
-	 * @time: timestamp with millisecond granularity
-	 * @dx: delta x coordinate in surface coordinate space
-	 * @dy: delta y coordinate in surface coordinate space
-	 * @scale: scale relative to the initial finger position
-	 * @rotation: angle in degrees cw relative to the previous event
+	 * multi-finger pinch motion
 	 *
 	 * This event is sent when a multi-finger pinch gesture changes
 	 * the position of the logical center, the rotation or the relative
@@ -233,6 +381,11 @@
 	 * The rotation is the relative angle in degrees clockwise compared
 	 * to the previous pointer_gesture_pinch.begin or
 	 * pointer_gesture_pinch.update event.
+	 * @param time timestamp with millisecond granularity
+	 * @param dx delta x coordinate in surface coordinate space
+	 * @param dy delta y coordinate in surface coordinate space
+	 * @param scale scale relative to the initial finger position
+	 * @param rotation angle in degrees cw relative to the previous event
 	 */
 	void (*update)(void *data,
 		       struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
@@ -242,10 +395,7 @@
 		       wl_fixed_t scale,
 		       wl_fixed_t rotation);
 	/**
-	 * end - multi-finger pinch end
-	 * @serial: (none)
-	 * @time: timestamp with millisecond granularity
-	 * @cancelled: 1 if the gesture was cancelled, 0 otherwise
+	 * multi-finger pinch end
 	 *
 	 * This event is sent when a multi-finger pinch gesture ceases to
 	 * be valid. This may happen when one or more fingers are lifted or
@@ -254,6 +404,8 @@
 	 * When a gesture is cancelled, the client should undo state
 	 * changes caused by this gesture. What causes a gesture to be
 	 * cancelled is implementation-dependent.
+	 * @param time timestamp with millisecond granularity
+	 * @param cancelled 1 if the gesture was cancelled, 0 otherwise
 	 */
 	void (*end)(void *data,
 		    struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
@@ -262,6 +414,9 @@
 		    int32_t cancelled);
 };
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
 static inline int
 zwp_pointer_gesture_pinch_v1_add_listener(struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
 					  const struct zwp_pointer_gesture_pinch_v1_listener *listener, void *data)
@@ -270,20 +425,49 @@
 				     (void (**)(void)) listener, data);
 }
 
-#define ZWP_POINTER_GESTURE_PINCH_V1_DESTROY	0
+#define ZWP_POINTER_GESTURE_PINCH_V1_DESTROY 0
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_BEGIN_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_UPDATE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_END_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_pointer_gesture_pinch_v1 */
 static inline void
 zwp_pointer_gesture_pinch_v1_set_user_data(struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, void *user_data)
 {
 	wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_gesture_pinch_v1, user_data);
 }
 
+/** @ingroup iface_zwp_pointer_gesture_pinch_v1 */
 static inline void *
 zwp_pointer_gesture_pinch_v1_get_user_data(struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1)
 {
 	return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_gesture_pinch_v1);
 }
 
+static inline uint32_t
+zwp_pointer_gesture_pinch_v1_get_version(struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_gesture_pinch_v1);
+}
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
 static inline void
 zwp_pointer_gesture_pinch_v1_destroy(struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1)
 {
diff --git a/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-server-protocol.h b/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-server-protocol.h
index 8c76ad50..51e5e79c 100644
--- a/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-server-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/pointer-gestures-unstable-v1-server-protocol.h
@@ -1,36 +1,63 @@
+/* Generated by wayland-scanner 1.13.0 */
+
 #ifndef POINTER_GESTURES_UNSTABLE_V1_SERVER_PROTOCOL_H
 #define POINTER_GESTURES_UNSTABLE_V1_SERVER_PROTOCOL_H
 
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-#include <stdint.h>
-#include <stddef.h>
-#include "wayland-util.h"
-
 struct wl_client;
 struct wl_resource;
 
-struct zwp_pointer_gestures_v1;
-struct zwp_pointer_gesture_swipe_v1;
+/**
+ * @page page_pointer_gestures_unstable_v1 The pointer_gestures_unstable_v1 protocol
+ * @section page_ifaces_pointer_gestures_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_pointer_gestures_v1 - touchpad gestures
+ * - @subpage page_iface_zwp_pointer_gesture_swipe_v1 - a swipe gesture object
+ * - @subpage page_iface_zwp_pointer_gesture_pinch_v1 - a pinch gesture object
+ */
+struct wl_pointer;
+struct wl_surface;
 struct zwp_pointer_gesture_pinch_v1;
-
-extern const struct wl_interface zwp_pointer_gestures_v1_interface;
-extern const struct wl_interface zwp_pointer_gesture_swipe_v1_interface;
-extern const struct wl_interface zwp_pointer_gesture_pinch_v1_interface;
+struct zwp_pointer_gesture_swipe_v1;
+struct zwp_pointer_gestures_v1;
 
 /**
- * zwp_pointer_gestures_v1 - touchpad gestures
- * @get_swipe_gesture: get swipe gesture
- * @get_pinch_gesture: get pinch gesture
+ * @page page_iface_zwp_pointer_gestures_v1 zwp_pointer_gestures_v1
+ * @section page_iface_zwp_pointer_gestures_v1_desc Description
  *
  * A global interface to provide semantic touchpad gestures for a given
  * pointer.
  *
- * Two gestures are currently supported: swipe and zoom/rotate. All
- * gestures follow a three-stage cycle: begin, update, end and are
- * identified by a unique id.
+ * Two gestures are currently supported: swipe and zoom/rotate.
+ * All gestures follow a three-stage cycle: begin, update, end and
+ * are identified by a unique id.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ * @section page_iface_zwp_pointer_gestures_v1_api API
+ * See @ref iface_zwp_pointer_gestures_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_gestures_v1 The zwp_pointer_gestures_v1 interface
+ *
+ * A global interface to provide semantic touchpad gestures for a given
+ * pointer.
+ *
+ * Two gestures are currently supported: swipe and zoom/rotate.
+ * All gestures follow a three-stage cycle: begin, update, end and
+ * are identified by a unique id.
  *
  * Warning! The protocol described in this file is experimental and
  * backward incompatible changes may be made. Backward compatible changes
@@ -41,11 +68,99 @@
  * version number in the protocol and interface names are removed and the
  * interface version number is reset.
  */
+extern const struct wl_interface zwp_pointer_gestures_v1_interface;
+/**
+ * @page page_iface_zwp_pointer_gesture_swipe_v1 zwp_pointer_gesture_swipe_v1
+ * @section page_iface_zwp_pointer_gesture_swipe_v1_desc Description
+ *
+ * A swipe gesture object notifies a client about a multi-finger swipe
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving in the
+ * same direction but once initiated the direction may change.
+ * The precise conditions of when such a gesture is detected are
+ * implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ * @section page_iface_zwp_pointer_gesture_swipe_v1_api API
+ * See @ref iface_zwp_pointer_gesture_swipe_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_gesture_swipe_v1 The zwp_pointer_gesture_swipe_v1 interface
+ *
+ * A swipe gesture object notifies a client about a multi-finger swipe
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving in the
+ * same direction but once initiated the direction may change.
+ * The precise conditions of when such a gesture is detected are
+ * implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ */
+extern const struct wl_interface zwp_pointer_gesture_swipe_v1_interface;
+/**
+ * @page page_iface_zwp_pointer_gesture_pinch_v1 zwp_pointer_gesture_pinch_v1
+ * @section page_iface_zwp_pointer_gesture_pinch_v1_desc Description
+ *
+ * A pinch gesture object notifies a client about a multi-finger pinch
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving towards
+ * each other or away from each other, or by two or more fingers rotating
+ * around a logical center of gravity. The precise conditions of when
+ * such a gesture is detected are implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ * @section page_iface_zwp_pointer_gesture_pinch_v1_api API
+ * See @ref iface_zwp_pointer_gesture_pinch_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_gesture_pinch_v1 The zwp_pointer_gesture_pinch_v1 interface
+ *
+ * A pinch gesture object notifies a client about a multi-finger pinch
+ * gesture detected on an indirect input device such as a touchpad.
+ * The gesture is usually initiated by multiple fingers moving towards
+ * each other or away from each other, or by two or more fingers rotating
+ * around a logical center of gravity. The precise conditions of when
+ * such a gesture is detected are implementation-dependent.
+ *
+ * A gesture consists of three stages: begin, update (optional) and end.
+ * There cannot be multiple simultaneous pinch or swipe gestures on a
+ * same pointer/seat, how compositors prevent these situations is
+ * implementation-dependent.
+ *
+ * A gesture may be cancelled by the compositor or the hardware.
+ * Clients should not consider performing permanent or irreversible
+ * actions until the end of a gesture has been received.
+ */
+extern const struct wl_interface zwp_pointer_gesture_pinch_v1_interface;
+
+/**
+ * @ingroup iface_zwp_pointer_gestures_v1
+ * @struct zwp_pointer_gestures_v1_interface
+ */
 struct zwp_pointer_gestures_v1_interface {
 	/**
-	 * get_swipe_gesture - get swipe gesture
-	 * @id: (none)
-	 * @pointer: (none)
+	 * get swipe gesture
 	 *
 	 * Create a swipe gesture object. See the
 	 * wl_pointer_gesture_swipe interface for details.
@@ -55,9 +170,7 @@
 				  uint32_t id,
 				  struct wl_resource *pointer);
 	/**
-	 * get_pinch_gesture - get pinch gesture
-	 * @id: (none)
-	 * @pointer: (none)
+	 * get pinch gesture
 	 *
 	 * Create a pinch gesture object. See the
 	 * wl_pointer_gesture_pinch interface for details.
@@ -68,29 +181,23 @@
 				  struct wl_resource *pointer);
 };
 
+
 /**
- * zwp_pointer_gesture_swipe_v1 - a swipe gesture object
- * @destroy: destroy the pointer swipe gesture object
- *
- * A swipe gesture object notifies a client about a multi-finger swipe
- * gesture detected on an indirect input device such as a touchpad. The
- * gesture is usually initiated by multiple fingers moving in the same
- * direction but once initiated the direction may change. The precise
- * conditions of when such a gesture is detected are
- * implementation-dependent.
- *
- * A gesture consists of three stages: begin, update (optional) and end.
- * There cannot be multiple simultaneous pinch or swipe gestures on a same
- * pointer/seat, how compositors prevent these situations is
- * implementation-dependent.
- *
- * A gesture may be cancelled by the compositor or the hardware. Clients
- * should not consider performing permanent or irreversible actions until
- * the end of a gesture has been received.
+ * @ingroup iface_zwp_pointer_gestures_v1
+ */
+#define ZWP_POINTER_GESTURES_V1_GET_SWIPE_GESTURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gestures_v1
+ */
+#define ZWP_POINTER_GESTURES_V1_GET_PINCH_GESTURE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ * @struct zwp_pointer_gesture_swipe_v1_interface
  */
 struct zwp_pointer_gesture_swipe_v1_interface {
 	/**
-	 * destroy - destroy the pointer swipe gesture object
+	 * destroy the pointer swipe gesture object
 	 *
 	 * 
 	 */
@@ -98,22 +205,62 @@
 			struct wl_resource *resource);
 };
 
-#define ZWP_POINTER_GESTURE_SWIPE_V1_BEGIN	0
-#define ZWP_POINTER_GESTURE_SWIPE_V1_UPDATE	1
-#define ZWP_POINTER_GESTURE_SWIPE_V1_END	2
+#define ZWP_POINTER_GESTURE_SWIPE_V1_BEGIN 0
+#define ZWP_POINTER_GESTURE_SWIPE_V1_UPDATE 1
+#define ZWP_POINTER_GESTURE_SWIPE_V1_END 2
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_BEGIN_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_UPDATE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_END_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ */
+#define ZWP_POINTER_GESTURE_SWIPE_V1_DESTROY_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ * Sends an begin event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param fingers number of fingers
+ */
 static inline void
 zwp_pointer_gesture_swipe_v1_send_begin(struct wl_resource *resource_, uint32_t serial, uint32_t time, struct wl_resource *surface, uint32_t fingers)
 {
 	wl_resource_post_event(resource_, ZWP_POINTER_GESTURE_SWIPE_V1_BEGIN, serial, time, surface, fingers);
 }
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ * Sends an update event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param dx delta x coordinate in surface coordinate space
+ * @param dy delta y coordinate in surface coordinate space
+ */
 static inline void
 zwp_pointer_gesture_swipe_v1_send_update(struct wl_resource *resource_, uint32_t time, wl_fixed_t dx, wl_fixed_t dy)
 {
 	wl_resource_post_event(resource_, ZWP_POINTER_GESTURE_SWIPE_V1_UPDATE, time, dx, dy);
 }
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_swipe_v1
+ * Sends an end event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param cancelled 1 if the gesture was cancelled, 0 otherwise
+ */
 static inline void
 zwp_pointer_gesture_swipe_v1_send_end(struct wl_resource *resource_, uint32_t serial, uint32_t time, int32_t cancelled)
 {
@@ -121,28 +268,12 @@
 }
 
 /**
- * zwp_pointer_gesture_pinch_v1 - a pinch gesture object
- * @destroy: destroy the pinch gesture object
- *
- * A pinch gesture object notifies a client about a multi-finger pinch
- * gesture detected on an indirect input device such as a touchpad. The
- * gesture is usually initiated by multiple fingers moving towards each
- * other or away from each other, or by two or more fingers rotating around
- * a logical center of gravity. The precise conditions of when such a
- * gesture is detected are implementation-dependent.
- *
- * A gesture consists of three stages: begin, update (optional) and end.
- * There cannot be multiple simultaneous pinch or swipe gestures on a same
- * pointer/seat, how compositors prevent these situations is
- * implementation-dependent.
- *
- * A gesture may be cancelled by the compositor or the hardware. Clients
- * should not consider performing permanent or irreversible actions until
- * the end of a gesture has been received.
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ * @struct zwp_pointer_gesture_pinch_v1_interface
  */
 struct zwp_pointer_gesture_pinch_v1_interface {
 	/**
-	 * destroy - destroy the pinch gesture object
+	 * destroy the pinch gesture object
 	 *
 	 * 
 	 */
@@ -150,22 +281,64 @@
 			struct wl_resource *resource);
 };
 
-#define ZWP_POINTER_GESTURE_PINCH_V1_BEGIN	0
-#define ZWP_POINTER_GESTURE_PINCH_V1_UPDATE	1
-#define ZWP_POINTER_GESTURE_PINCH_V1_END	2
+#define ZWP_POINTER_GESTURE_PINCH_V1_BEGIN 0
+#define ZWP_POINTER_GESTURE_PINCH_V1_UPDATE 1
+#define ZWP_POINTER_GESTURE_PINCH_V1_END 2
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_BEGIN_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_UPDATE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_END_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ */
+#define ZWP_POINTER_GESTURE_PINCH_V1_DESTROY_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ * Sends an begin event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param fingers number of fingers
+ */
 static inline void
 zwp_pointer_gesture_pinch_v1_send_begin(struct wl_resource *resource_, uint32_t serial, uint32_t time, struct wl_resource *surface, uint32_t fingers)
 {
 	wl_resource_post_event(resource_, ZWP_POINTER_GESTURE_PINCH_V1_BEGIN, serial, time, surface, fingers);
 }
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ * Sends an update event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param dx delta x coordinate in surface coordinate space
+ * @param dy delta y coordinate in surface coordinate space
+ * @param scale scale relative to the initial finger position
+ * @param rotation angle in degrees cw relative to the previous event
+ */
 static inline void
 zwp_pointer_gesture_pinch_v1_send_update(struct wl_resource *resource_, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation)
 {
 	wl_resource_post_event(resource_, ZWP_POINTER_GESTURE_PINCH_V1_UPDATE, time, dx, dy, scale, rotation);
 }
 
+/**
+ * @ingroup iface_zwp_pointer_gesture_pinch_v1
+ * Sends an end event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param cancelled 1 if the gesture was cancelled, 0 otherwise
+ */
 static inline void
 zwp_pointer_gesture_pinch_v1_send_end(struct wl_resource *resource_, uint32_t serial, uint32_t time, int32_t cancelled)
 {
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
index 648fed50..bd18ed4 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.14.0 */
+/* Generated by wayland-scanner 1.13.0 */
 
 #ifndef REMOTE_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
 #define REMOTE_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
@@ -664,7 +664,7 @@
 	 * The compositor requested to change the bounds
 	 *
 	 * The compositor requested to change its bounds.
-	 * "bounds_chnage_reason" specifies the cause of the bounds change.
+	 * "bounds_change_reason" specifies the cause of the bounds change.
 	 * The client may apply the different move/resize strategy
 	 * depending on the reason.
 	 *
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
index 9c33560..6c128b9d 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.14.0 */
+/* Generated by wayland-scanner 1.13.0 */
 
 #ifndef REMOTE_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H
 #define REMOTE_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H
diff --git a/third_party/wayland-protocols/protocol/input-timestamps-v1-protocol.c b/third_party/wayland-protocols/protocol/input-timestamps-v1-protocol.c
new file mode 100644
index 0000000..33e91129
--- /dev/null
+++ b/third_party/wayland-protocols/protocol/input-timestamps-v1-protocol.c
@@ -0,0 +1,73 @@
+/* Generated by wayland-scanner 1.13.0 */
+
+/*
+ * Copyright © 2017 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_touch_interface;
+extern const struct wl_interface zwp_input_timestamps_v1_interface;
+
+static const struct wl_interface *types[] = {
+	NULL,
+	NULL,
+	NULL,
+	&zwp_input_timestamps_v1_interface,
+	&wl_keyboard_interface,
+	&zwp_input_timestamps_v1_interface,
+	&wl_pointer_interface,
+	&zwp_input_timestamps_v1_interface,
+	&wl_touch_interface,
+};
+
+static const struct wl_message zwp_input_timestamps_manager_v1_requests[] = {
+	{ "destroy", "", types + 0 },
+	{ "get_keyboard_timestamps", "no", types + 3 },
+	{ "get_pointer_timestamps", "no", types + 5 },
+	{ "get_touch_timestamps", "no", types + 7 },
+};
+
+WL_EXPORT const struct wl_interface zwp_input_timestamps_manager_v1_interface = {
+	"zwp_input_timestamps_manager_v1", 1,
+	4, zwp_input_timestamps_manager_v1_requests,
+	0, NULL,
+};
+
+static const struct wl_message zwp_input_timestamps_v1_requests[] = {
+	{ "destroy", "", types + 0 },
+};
+
+static const struct wl_message zwp_input_timestamps_v1_events[] = {
+	{ "timestamp", "uuu", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface zwp_input_timestamps_v1_interface = {
+	"zwp_input_timestamps_v1", 1,
+	1, zwp_input_timestamps_v1_requests,
+	1, zwp_input_timestamps_v1_events,
+};
+
diff --git a/third_party/wayland-protocols/protocol/pointer-gestures-v1-protocol.c b/third_party/wayland-protocols/protocol/pointer-gestures-v1-protocol.c
index 6e54eb9f..842cb57 100644
--- a/third_party/wayland-protocols/protocol/pointer-gestures-v1-protocol.c
+++ b/third_party/wayland-protocols/protocol/pointer-gestures-v1-protocol.c
@@ -1,13 +1,13 @@
+/* Generated by wayland-scanner 1.13.0 */
+
 #include <stdlib.h>
 #include <stdint.h>
 #include "wayland-util.h"
 
-extern const struct wl_interface zwp_pointer_gesture_swipe_v1_interface;
 extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_surface_interface;
 extern const struct wl_interface zwp_pointer_gesture_pinch_v1_interface;
-extern const struct wl_interface wl_pointer_interface;
-extern const struct wl_interface wl_surface_interface;
-extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface zwp_pointer_gesture_swipe_v1_interface;
 
 static const struct wl_interface *types[] = {
 	NULL,
diff --git a/third_party/wayland-protocols/protocol/remote-shell-protocol.c b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
index 99e967b4..d3ac990 100644
--- a/third_party/wayland-protocols/protocol/remote-shell-protocol.c
+++ b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.14.0 */
+/* Generated by wayland-scanner 1.13.0 */
 
 /*
  * Copyright 2016 The Chromium Authors.
diff --git a/tools/android/memconsumer/java/AndroidManifest.xml b/tools/android/memconsumer/java/AndroidManifest.xml
index c7f12e42..f886d7b 100644
--- a/tools/android/memconsumer/java/AndroidManifest.xml
+++ b/tools/android/memconsumer/java/AndroidManifest.xml
@@ -9,6 +9,8 @@
     package="org.chromium.memconsumer" android:versionCode="1"
     android:versionName="1.0">
 
+    <uses-sdk android:minSdkVersion="16"/>
+
     <application
             android:label="MemConsumer">
         <activity android:name=".MemConsumer" android:icon="@drawable/icon" android:launchMode="singleTop">
diff --git a/tools/android/native_lib_memory/extract_symbols.py b/tools/android/native_lib_memory/extract_symbols.py
index 7973d9a..fa992719 100755
--- a/tools/android/native_lib_memory/extract_symbols.py
+++ b/tools/android/native_lib_memory/extract_symbols.py
@@ -221,6 +221,7 @@
                       required=True)
   parser.add_argument('--output-directory', type=str, help='Output directory',
                       required=True)
+  parser.add_argument('--arch', type=str, help='Architecture', default='arm')
   parser.add_argument('--start-server', action='store_true', default=False,
                       help='Run an HTTP server in the output directory')
   parser.add_argument('--port', type=int, default=8000,
@@ -233,6 +234,7 @@
   args = parser.parse_args()
   logging.basicConfig(level=logging.INFO)
 
+  symbol_extractor.SetArchitecture(args.arch)
   logging.info('Parsing object files in %s', args.build_directory)
   object_files_symbols = GetSymbolNameToFilename(args.build_directory)
   native_lib_filename = os.path.join(
diff --git a/tools/chrome_proxy/webdriver/emulation_server.py b/tools/chrome_proxy/webdriver/emulation_server.py
index 33a63284..06b647d 100644
--- a/tools/chrome_proxy/webdriver/emulation_server.py
+++ b/tools/chrome_proxy/webdriver/emulation_server.py
@@ -12,6 +12,16 @@
 
 from OpenSSL import crypto
 
+class BlackHoleHandler(SocketServer.BaseRequestHandler):
+  """This handler consumes all request input and makes no responses.
+  """
+  def handle(self):
+    """Consume the request and then do nothing.
+    """
+    data = self.request.recv(4096)
+    while len(data) > 0:
+      data = self.request.recv(4096)
+
 class InvalidTLSHandler(SocketServer.BaseRequestHandler):
   """This handler injects unencrypted TCP after a TLS handshake.
   """
@@ -136,4 +146,4 @@
     pkey_f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pk))
 
   # Return the filenames in a dict that can be expanded into ssl function args.
-  return {"certfile": cert_path, "keyfile": pkey_path}
\ No newline at end of file
+  return {"certfile": cert_path, "keyfile": pkey_path}
diff --git a/tools/chrome_proxy/webdriver/proxy_connection.py b/tools/chrome_proxy/webdriver/proxy_connection.py
index dddded4..03932ad1 100644
--- a/tools/chrome_proxy/webdriver/proxy_connection.py
+++ b/tools/chrome_proxy/webdriver/proxy_connection.py
@@ -6,7 +6,10 @@
 from common import TestDriver
 from common import IntegrationTest
 from decorators import ChromeVersionEqualOrAfterM
-from emulation_server import InvalidTLSHandler, TCPResetHandler, TLSResetHandler
+from emulation_server import BlackHoleHandler
+from emulation_server import InvalidTLSHandler
+from emulation_server import TCPResetHandler
+from emulation_server import TLSResetHandler
 
 class ProxyConnection(IntegrationTest):
 
@@ -82,5 +85,45 @@
       for response in responses:
         self.assertNotHasChromeProxyViaHeader(response)
 
+  @ChromeVersionEqualOrAfterM(66)
+  def testTCPBlackhole(self):
+    port = common.GetOpenPort()
+    with TestDriver() as t:
+      t.UseNetLog()
+      t.AddChromeArg('--enable-spdy-proxy-auth')
+      t.AddChromeArg('--enable-features='
+        'DataReductionProxyRobustConnection<DataReductionProxyRobustConnection')
+      t.AddChromeArg('--force-fieldtrials='
+        'DataReductionProxyRobustConnection/Enabled')
+      t.AddChromeArg('--force-fieldtrial-params='
+        'DataReductionProxyRobustConnection.Enabled:'
+        'warmup_fetch_callback_enabled/true')
+      t.AddChromeArg('--force-effective-connection-type=4G')
+      # The server should be 127.0.0.1, not localhost because the two are
+      # treated differently in Chrome internals. Using localhost invalidates the
+      # test.
+      t.AddChromeArg(
+        '--data-reduction-proxy-http-proxies=http://127.0.0.1:%d' % port)
+
+      t.UseEmulationServer(BlackHoleHandler, port=port)
+      # Start Chrome and wait for the proxy timeout to fail. At ECT=4G, this
+      # will take about 8 seconds.
+      t.LoadURL('data:,')
+      self.assertTrue(
+        t.SleepUntilHistogramHasEntry('DataReductionProxy.WarmupURL.NetError',
+          sleep_intervals=10))
+
+      # Check the WarmupURL Callback was called.
+      histogram = t.GetHistogram('DataReductionProxy.WarmupURLFetcherCallback.'
+        'SuccessfulFetch.InsecureProxy.NonCore')
+      self.assertEqual(1, histogram['count'])
+
+      # Verify DRP was not used.
+      t.LoadURL('http://check.googlezip.net/test.html')
+      responses = t.GetHTTPResponses()
+      self.assertEqual(2, len(responses))
+      for response in responses:
+        self.assertNotHasChromeProxyViaHeader(response)
+
 if __name__ == '__main__':
   IntegrationTest.RunAllTests()
diff --git a/tools/cygprofile/lightweight_cygprofile.cc b/tools/cygprofile/lightweight_cygprofile.cc
index 7d2cd930..ed5df4ca 100644
--- a/tools/cygprofile/lightweight_cygprofile.cc
+++ b/tools/cygprofile/lightweight_cygprofile.cc
@@ -161,7 +161,7 @@
 void SanityChecks() {
   CHECK_LT(base::android::kEndOfText - base::android::kStartOfText,
            kMaxTextSizeInBytes);
-  base::android::CheckOrderingSanity();
+  CHECK(base::android::IsOrderingSane());
 }
 
 bool SwitchToNextPhaseOrDump(int pid, uint64_t start_ns_since_epoch) {
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 3d29e50..f3391e8 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -227,7 +227,7 @@
 
   write_buildflag_header_manually(
       root_gen_dir, 'base/android/library_loader.h',
-      {'USE_LLD': 'false'})
+      {'USE_LLD': 'false', 'SUPPORTS_CODE_ORDERING': 'false'})
 
   write_gn_ninja(os.path.join(tempdir, 'build.ninja'),
                  root_gen_dir, options)
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6a7b87a..78b5fef8 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -17573,7 +17573,8 @@
   <int value="2228" label="DocumentPageShowRegistered"/>
   <int value="2229" label="DocumentPageShowFired"/>
   <int value="2230" label="ReplaceCharsetInXHR"/>
-  <int value="2231" label="RespondToSameOriginRequestWithCrossOriginResponse"/>
+  <int value="2231"
+      label="RespondToSameOriginRequestWithCrossOriginResponse (obsolete)"/>
   <int value="2232" label="LinkRelModulePreload"/>
   <int value="2233" label="PerformanceMeasurePassedInObject"/>
   <int value="2234" label="PerformanceMeasurePassedInNavigationTiming"/>
@@ -23117,6 +23118,8 @@
   <int value="2" label="Client connection error"/>
   <int value="3" label="Tethering unsupported"/>
   <int value="4" label="No cellular data"/>
+  <int value="5" label="Enabling hotspot failed"/>
+  <int value="6" label="Enabling hotspot timed out"/>
 </enum>
 
 <enum name="InstantTethering_ConnectionToHostResult_Failure_ClientConnection">
@@ -38825,6 +38828,7 @@
   <int value="13" label="ForeignFetchMismatchedOrigin"/>
   <int value="14" label="RedirectedResponseForNotFollowRequest"/>
   <int value="15" label="DataPipeCreationFailed (insufficient resources)"/>
+  <int value="16" label="ResponseTypeCORSForRequestModeSameOrigin"/>
 </enum>
 
 <enum name="ServiceWorkerSite">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1c012bb9..326f27be 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -48291,6 +48291,9 @@
 </histogram>
 
 <histogram name="Net.SSLRecordSizeRead" units="bytes">
+  <obsolete>
+    Removed in January 2018.
+  </obsolete>
   <owner>davidben@chromium.org</owner>
   <owner>svaldez@chromium.org</owner>
   <summary>
@@ -96246,6 +96249,19 @@
 </histogram>
 
 <histogram name="WebApk.LaunchInterval" units="ms">
+  <obsolete>
+    Deprecated 2018-01. Replaced by WebApk.LaunchInterval2
+  </obsolete>
+  <owner>hanxi@chromium.org</owner>
+  <owner>pkotwicz@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    Records the amount of time since the user last launched the WebAPK from the
+    homescreen. Not recorded on first launch.
+  </summary>
+</histogram>
+
+<histogram name="WebApk.LaunchInterval2" units="minutes">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -97415,6 +97431,114 @@
   </summary>
 </histogram>
 
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.DeletedTombstonesSize"
+    units="bytes">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records the total size of tombstones deleted by the IndexedDB Tombstone
+    Sweeper. Recorded on the browser side (back end) when the sweeper has
+    completed scanning and it is in the 'deletion' mode. See
+    https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram
+    name="WebCore.IndexedDB.TombstoneSweeper.DeletionCommitTime.Complete"
+    units="ms">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records the time it takes for the IndexedDB Tombstone Sweeper to commit
+    tombstone deletions. Recorded on the browser side (back end) when the
+    sweeper has completed a round of sweeping and, it's in 'deletion' mode, and
+    it has tombstones to delete. See https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.DeletionTotalTime.Complete"
+    units="ms">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records the time it takes for the IndexedDB Tombstone Sweeper to fully sweep
+    the indexes. Recorded on the browser side (back end) when the sweeper has
+    completed sweeping all indexes (so partial sweeps are not recorded) and it
+    is in 'deletion' mode. See https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.DeletionWriteError"
+    units="LevelDBStatus">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records when an error occurs during deletion of index tombstones by the
+    IndexedDB Tombstone Sweeper. Recorded on the browser side (back end) when
+    the sweeper has completed a round of sweeping and, it's in 'deletion' mode,
+    and it has tombstones to delete. See https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.IndexScanPercent"
+    units="%/5">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Recorded on the browser side (back end) when the IndexedDB Tombstone Sweeper
+    has completed scanning. Records the percentage of the indexes the scanner
+    fully scanned before it was stopped. To reduce the number of buckets, the
+    recorded value is the percentage divided by 5. See https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.NumDeletedTombstones"
+    units="Index Tombstones">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records the number of tombstones deleted by the IndexedDB Tombstone Sweeper.
+    Recorded on the browser side (back end) when the sweeper has completed
+    scanning and it is in 'deletion' mode. See https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.NumTombstones"
+    units="Index Tombstones">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records the number of tombstones encountered by the IndexedDB Tombstone
+    Sweeper. Recorded on the browser side (back end) when the sweeper has
+    completed scanning and it is in 'statistics' mode. See
+    https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.StatsTotalTime.Complete"
+    units="ms">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records the time it takes for the IndexedDB Tombstone Sweeper to fully scan
+    the indexes. Recorded on the browser side (back end) when the sweeper has
+    completed scanning all indexes (so partial scans are not recorded) and it is
+    in 'statistics' mode. See https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.SweepError"
+    enum="LevelDBStatus">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Recorded on the browser side (back end) when the IndexedDB Tombstone Sweeper
+    encounters an error while sweeping. See https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
+<histogram name="WebCore.IndexedDB.TombstoneSweeper.TombstonesSize"
+    units="bytes">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    Records the total size of tombstones encountered by the IndexedDB Tombstone
+    Sweeper. Recorded on the browser side (back end) when the sweeper has
+    completed scanning and it is in the 'statistics' mode. See
+    https://goo.gl/coKwA7.
+  </summary>
+</histogram>
+
 <histogram name="WebCore.IndexedDB.Transaction.ReadOnly.SizeOnCommit"
     units="KB">
   <obsolete>
@@ -111790,6 +111914,25 @@
   </affected-histogram>
 </histogram_suffixes>
 
+<histogram_suffixes name="SweeperCompletionTypes" separator=".">
+  <affected-histogram
+      name="WebCore.IndexedDB.TombstoneSweeper.DeletedTombstonesSize"/>
+  <affected-histogram
+      name="WebCore.IndexedDB.TombstoneSweeper.NumDeletedTombstones"/>
+  <suffix name="Complete" label="All indexes are scanned."/>
+  <suffix name="ConnectionOpened"
+      label="Scanning is interrupted by an new connection to the database."/>
+  <suffix name="TimeoutReached" label="Scanning is stopped by the timeout."/>
+  <suffix name="MaxIterations"
+      label="Scanning is stopped because the maximum record iteration count
+             was hit."/>
+  <suffix name="SweepError"
+      label="Scanning is stopped because a leveldb error was encountered
+             during sweeping."/>
+  <affected-histogram name="WebCore.IndexedDB.TombstoneSweeper.NumTombstones"/>
+  <affected-histogram name="WebCore.IndexedDB.TombstoneSweeper.TombstonesSize"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="SyncModelType" separator=".">
   <suffix name="APP" label="APP"/>
   <suffix name="APP_LIST" label="APP_LIST"/>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index bbfa20e..9e61ad17 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -8,6 +8,7 @@
 # tags: Nexus5X_Webview
 
 # Benchmark: battor.steady_state
+crbug.com/805520 [ Mac_10.11 ] battor.steady_state/* [ Skip ]
 crbug.com/505990 [ All ] battor.steady_state/http://abcnews.go.com/ [ Skip ]
 
 # Benchmark: blink_perf.bindings
@@ -185,6 +186,7 @@
 crbug.com/784025 [ Win ] speedometer2-future/Speedometer2 [ Skip ]
 
 # Benchmark: system_health.common_desktop
+crbug.com/805520 [ Mac_10.11 ] system_health.common_desktop/* [ Skip ]
 crbug.com/728576 [ Mac ] system_health.common_desktop/browse:news:cnn [ Skip ]
 crbug.com/64939 [ All ] system_health.common_desktop/play:media:pandora [ Skip ]
 crbug.com/676336 [ Win ] system_health.common_desktop/browse:news:hackernews [ Skip ]
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 9f1591f..f7afa7b 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -2706,7 +2706,7 @@
       // used to indicate a real native window object. It is automatically
       // created by oleacc.dll as a parent of the root of our hierarchy,
       // matching the HWND.
-      return ROLE_SYSTEM_APPLICATION;
+      return ROLE_SYSTEM_PANE;
 
     // TODO(dmazzoni): figure out the proper MSAA role for roles listed below.
     case AX_ROLE_BLOCKQUOTE:
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index bbbdbc6..9424d7c 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -1192,6 +1192,12 @@
   if (app_list_state_ == AppListViewState::CLOSED)
     return;
 
+  if (fullscreen_widget_->GetLayer()->GetAnimator()->IsAnimatingProperty(
+          ui::LayerAnimationElement::TRANSFORM)) {
+    fullscreen_widget_->GetLayer()->GetAnimator()->StopAnimatingProperty(
+        ui::LayerAnimationElement::TRANSFORM);
+  }
+
   SetIsInDrag(true);
   background_opacity_ = background_opacity;
   gfx::Rect new_widget_bounds = fullscreen_widget_->GetWindowBoundsInScreen();
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc
index ff49462..02c7e0f6 100644
--- a/ui/app_list/views/app_list_view_unittest.cc
+++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -1500,9 +1500,9 @@
   // Send SCROLL_START and SCROLL_UPDATE events, simulating dragging the
   // launcher.
   base::TimeTicks timestamp = base::TimeTicks::Now();
-  const gfx::Point start = view_->get_fullscreen_widget_for_test()
-                               ->GetWindowBoundsInScreen()
-                               .top_right();
+  gfx::Point start = view_->get_fullscreen_widget_for_test()
+                         ->GetWindowBoundsInScreen()
+                         .top_right();
   int delta_y = 0;
   ui::GestureEvent start_event = ui::GestureEvent(
       start.x(), start.y(), ui::EF_NONE, timestamp,
@@ -1512,6 +1512,7 @@
   // Drag down the launcher.
   timestamp += base::TimeDelta::FromMilliseconds(25);
   delta_y += 10;
+  start.Offset(0, 1);
   ui::GestureEvent update_event = ui::GestureEvent(
       start.x(), start.y(), ui::EF_NONE, timestamp,
       ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 0, delta_y));
@@ -1533,6 +1534,7 @@
   // Ends to drag the launcher.
   EXPECT_TRUE(SetAppListState(ash::AppListState::kStateApps));
   timestamp += base::TimeDelta::FromMilliseconds(25);
+  start.Offset(0, 1);
   ui::GestureEvent end_event =
       ui::GestureEvent(start.x(), start.y() + delta_y, ui::EF_NONE, timestamp,
                        ui::GestureEventDetails(ui::ET_GESTURE_END));
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn
index 3c0a68c..f9a33289 100644
--- a/ui/events/ozone/BUILD.gn
+++ b/ui/events/ozone/BUILD.gn
@@ -33,6 +33,8 @@
       "device/udev/device_manager_udev.cc",
       "device/udev/device_manager_udev.h",
       "events_ozone_export.h",
+      "keyboard/event_auto_repeat_handler.cc",
+      "keyboard/event_auto_repeat_handler.h",
     ]
 
     deps = [
@@ -70,8 +72,6 @@
     sources = [
       "evdev/device_event_dispatcher_evdev.cc",
       "evdev/device_event_dispatcher_evdev.h",
-      "evdev/event_auto_repeat_handler.cc",
-      "evdev/event_auto_repeat_handler.h",
       "evdev/event_converter_evdev.cc",
       "evdev/event_converter_evdev.h",
       "evdev/event_converter_evdev_impl.cc",
diff --git a/ui/events/ozone/evdev/keyboard_evdev.h b/ui/events/ozone/evdev/keyboard_evdev.h
index b4ee004..eba0dc0 100644
--- a/ui/events/ozone/evdev/keyboard_evdev.h
+++ b/ui/events/ozone/evdev/keyboard_evdev.h
@@ -12,10 +12,10 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "ui/events/ozone/evdev/event_auto_repeat_handler.h"
 #include "ui/events/ozone/evdev/event_device_util.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
 #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+#include "ui/events/ozone/keyboard/event_auto_repeat_handler.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 
 namespace ui {
diff --git a/ui/events/ozone/evdev/event_auto_repeat_handler.cc b/ui/events/ozone/keyboard/event_auto_repeat_handler.cc
similarity index 97%
rename from ui/events/ozone/evdev/event_auto_repeat_handler.cc
rename to ui/events/ozone/keyboard/event_auto_repeat_handler.cc
index ebfbb60d..3eea5cf 100644
--- a/ui/events/ozone/evdev/event_auto_repeat_handler.cc
+++ b/ui/events/ozone/keyboard/event_auto_repeat_handler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/events/ozone/evdev/event_auto_repeat_handler.h"
+#include "ui/events/ozone/keyboard/event_auto_repeat_handler.h"
 
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/events/base_event_utils.h"
diff --git a/ui/events/ozone/evdev/event_auto_repeat_handler.h b/ui/events/ozone/keyboard/event_auto_repeat_handler.h
similarity index 87%
rename from ui/events/ozone/evdev/event_auto_repeat_handler.h
rename to ui/events/ozone/keyboard/event_auto_repeat_handler.h
index 37b1896..f95430b 100644
--- a/ui/events/ozone/evdev/event_auto_repeat_handler.h
+++ b/ui/events/ozone/keyboard/event_auto_repeat_handler.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_EVENTS_OZONE_EVDEV_EVENT_AUTO_REPEAT_HANDLER_H
-#define UI_EVENTS_OZONE_EVDEV_EVENT_AUTO_REPEAT_HANDLER_H
+#ifndef UI_EVENTS_OZONE_KEYBOARD_EVENT_AUTO_REPEAT_HANDLER_H
+#define UI_EVENTS_OZONE_KEYBOARD_EVENT_AUTO_REPEAT_HANDLER_H
 
 #include <linux/input.h>
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "ui/events/events_export.h"
+#include "ui/events/ozone/events_ozone_export.h"
 
 namespace ui {
 
-class EVENTS_EXPORT EventAutoRepeatHandler {
+class EVENTS_OZONE_EXPORT EventAutoRepeatHandler {
  public:
   class Delegate {
    public:
@@ -36,6 +36,7 @@
                        bool down,
                        bool suppress_auto_repeat,
                        int device_id);
+  void StopKeyRepeat();
 
   // Configuration for key repeat.
   bool IsAutoRepeatEnabled();
@@ -46,7 +47,6 @@
 
  private:
   void StartKeyRepeat(unsigned int key, int device_id);
-  void StopKeyRepeat();
   void ScheduleKeyRepeat(const base::TimeDelta& delay);
   void OnRepeatTimeout(unsigned int sequence);
   void OnRepeatCommit(unsigned int sequence);
@@ -68,4 +68,4 @@
 
 }  // namespace ui
 
-#endif  // UI_EVENTS_OZONE_EVDEV_EVENT_AUTO_REPEAT_HANDLER_H
+#endif  // UI_EVENTS_OZONE_KEYBOARD_EVENT_AUTO_REPEAT_HANDLER_H
diff --git a/ui/gl/gl_image_io_surface_unittest.cc b/ui/gl/gl_image_io_surface_unittest.cc
index 3c10926..4d47cab 100644
--- a/ui/gl/gl_image_io_surface_unittest.cc
+++ b/ui/gl/gl_image_io_surface_unittest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/strings/string_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/mac/io_surface.h"
@@ -37,6 +38,10 @@
     IOReturn status = IOSurfaceLock(surface_ref, 0, nullptr);
     EXPECT_NE(status, kIOReturnCannotLock);
 
+    static const bool is_nvidia =
+        base::StartsWith(reinterpret_cast<const char*>(glGetString(GL_VENDOR)),
+                         "nvidia", base::CompareCase::INSENSITIVE_ASCII);
+
     uint8_t corrected_color[4];
     if (format == gfx::BufferFormat::RGBA_8888) {
       // GL_RGBA is not supported by CGLTexImageIOSurface2D(), so we pretend it
@@ -46,6 +51,15 @@
       corrected_color[1] = color[1];
       corrected_color[2] = color[0];
       corrected_color[3] = color[3];
+    } else if (format == gfx::BufferFormat::BGRX_1010102 && is_nvidia) {
+      // Framebuffers are wrongly interpreted as BGRA when using GL_RGB10_A2
+      // textures and/or IOSurfaces; swizzle the channels here in advance
+      // https://crbug.com/803473, http://www.openradar.me/36824694,
+      // rdar://36824694.
+      corrected_color[0] = color[2];
+      corrected_color[1] = color[1];
+      corrected_color[2] = color[0];
+      corrected_color[3] = color[3];
     } else {
       memcpy(corrected_color, color, arraysize(corrected_color));
     }
@@ -109,11 +123,11 @@
                               GLImageRGBTestTypes);
 
 using GLImageBindTestTypes = testing::Types<
-    // TODO(mcasas): enable BGRX_1010102, https://crbug.com/803473.
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRA_8888>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_8888>,
     GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_8888>,
-    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>>;
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::RGBA_F16>,
+    GLImageIOSurfaceTestDelegate<gfx::BufferFormat::BGRX_1010102>>;
 
 INSTANTIATE_TYPED_TEST_CASE_P(GLImageIOSurface,
                               GLImageBindTest,
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 4db7485..d044ae3 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -29,7 +29,6 @@
 #include "ui/gl/gl_context_egl.h"
 #include "ui/gl/gl_image.h"
 #include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_surface_presentation_helper.h"
 #include "ui/gl/gl_surface_stub.h"
 #include "ui/gl/gl_utils.h"
 #include "ui/gl/scoped_make_current.h"
@@ -985,9 +984,6 @@
         std::make_unique<EGLSyncControlVSyncProvider>(surface_);
   }
 
-  presentation_helper_ =
-      std::make_unique<GLSurfacePresentationHelper>(GetVSyncProvider());
-
   return true;
 }
 
@@ -1040,16 +1036,11 @@
   use_egl_timestamps_ = !supported_egl_timestamps_.empty();
 }
 
-bool NativeViewGLSurfaceEGL::SupportsPresentationCallback() {
-  return true;
-}
-
 bool NativeViewGLSurfaceEGL::InitializeNativeWindow() {
   return true;
 }
 
 void NativeViewGLSurfaceEGL::Destroy() {
-  presentation_helper_ = nullptr;
   vsync_provider_internal_ = nullptr;
 
   if (surface_) {
@@ -1084,17 +1075,17 @@
         !!eglGetNextFrameIdANDROID(GetDisplay(), surface_, &newFrameId);
   }
 
-  presentation_helper_->PreSwapBuffers(callback);
-  gfx::SwapResult swap_result = gfx::SwapResult::SWAP_ACK;
   if (!eglSwapBuffers(GetDisplay(), surface_)) {
     DVLOG(1) << "eglSwapBuffers failed with error "
              << GetLastEGLErrorString();
-    swap_result = gfx::SwapResult::SWAP_FAILED;
-  } else if (use_egl_timestamps_) {
+    return gfx::SwapResult::SWAP_FAILED;
+  }
+
+  if (use_egl_timestamps_) {
     UpdateSwapEvents(newFrameId, newFrameIdIsValid);
   }
-  presentation_helper_->PostSwapBuffers(swap_result);
-  return swap_result;
+
+  return gfx::SwapResult::SWAP_ACK;
 }
 
 void NativeViewGLSurfaceEGL::UpdateSwapEvents(EGLuint64KHR newFrameId,
@@ -1289,17 +1280,14 @@
     return gfx::SwapResult::SWAP_FAILED;
   }
 
-  presentation_helper_->PreSwapBuffers(callback);
-  gfx::SwapResult swap_result = gfx::SwapResult::SWAP_ACK;
   if (!eglSwapBuffersWithDamageKHR(GetDisplay(), surface_,
                                    const_cast<EGLint*>(rects.data()),
                                    static_cast<EGLint>(rects.size() / 4))) {
     DVLOG(1) << "eglSwapBuffersWithDamageKHR failed with error "
              << GetLastEGLErrorString();
-    swap_result = gfx::SwapResult::SWAP_FAILED;
+    return gfx::SwapResult::SWAP_FAILED;
   }
-  presentation_helper_->PostSwapBuffers(swap_result);
-  return swap_result;
+  return gfx::SwapResult::SWAP_ACK;
 }
 
 gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer(
@@ -1320,15 +1308,12 @@
     // bottom left.
     y = GetSize().height() - y - height;
   }
-  presentation_helper_->PreSwapBuffers(callback);
-  gfx::SwapResult swap_result = gfx::SwapResult::SWAP_ACK;
   if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
     DVLOG(1) << "eglPostSubBufferNV failed with error "
              << GetLastEGLErrorString();
-    swap_result = gfx::SwapResult::SWAP_FAILED;
+    return gfx::SwapResult::SWAP_FAILED;
   }
-  presentation_helper_->PostSwapBuffers(swap_result);
-  return swap_result;
+  return gfx::SwapResult::SWAP_ACK;
 }
 
 bool NativeViewGLSurfaceEGL::SupportsCommitOverlayPlanes() {
@@ -1350,11 +1335,6 @@
                                          : gfx::SwapResult::SWAP_FAILED;
 }
 
-bool NativeViewGLSurfaceEGL::OnMakeCurrent(GLContext* context) {
-  presentation_helper_->OnMakeCurrent(context, this);
-  return GLSurfaceEGL::OnMakeCurrent(context);
-}
-
 gfx::VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
   return vsync_provider_external_ ? vsync_provider_external_.get()
                                   : vsync_provider_internal_.get();
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index 1e8cb17..30a7196 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -28,8 +28,6 @@
 
 namespace gl {
 
-class GLSurfacePresentationHelper;
-
 // If adding a new type, also add it to EGLDisplayType in
 // tools/metrics/histograms/histograms.xml. Don't remove or reorder entries.
 enum DisplayType {
@@ -106,10 +104,10 @@
                          std::unique_ptr<gfx::VSyncProvider> vsync_provider);
 
   // Implement GLSurface.
+  using GLSurfaceEGL::Initialize;
   bool Initialize(GLSurfaceFormat format) override;
   bool SupportsSwapTimestamps() const override;
   void SetEnableSwapTimestamps() override;
-  bool SupportsPresentationCallback() override;
   void Destroy() override;
   bool Resize(const gfx::Size& size,
               float scale_factor,
@@ -129,7 +127,6 @@
   bool SupportsCommitOverlayPlanes() override;
   gfx::SwapResult CommitOverlayPlanes(
       const PresentationCallback& callback) override;
-  bool OnMakeCurrent(GLContext* context) override;
   gfx::VSyncProvider* GetVSyncProvider() override;
   bool ScheduleOverlayPlane(int z_order,
                             gfx::OverlayTransform transform,
@@ -183,8 +180,6 @@
 
   base::queue<SwapInfo> swap_info_queue_;
 
-  std::unique_ptr<GLSurfacePresentationHelper> presentation_helper_;
-
   DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceEGL);
 };
 
diff --git a/ui/gl/gl_surface_glx.cc b/ui/gl/gl_surface_glx.cc
index a8a05af..7579c74 100644
--- a/ui/gl/gl_surface_glx.cc
+++ b/ui/gl/gl_surface_glx.cc
@@ -675,7 +675,7 @@
                GetSize().width(), "height", GetSize().height());
   presentation_helper_->PreSwapBuffers(callback);
   glXSwapBuffers(g_display, GetDrawableHandle());
-  presentation_helper_->PostSwapBuffers(gfx::SwapResult::SWAP_ACK);
+  presentation_helper_->PostSwapBuffers();
   return gfx::SwapResult::SWAP_ACK;
 }
 
@@ -718,7 +718,7 @@
   DCHECK(g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
   presentation_helper_->PreSwapBuffers(callback);
   glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height);
-  presentation_helper_->PostSwapBuffers(gfx::SwapResult::SWAP_ACK);
+  presentation_helper_->PostSwapBuffers();
   return gfx::SwapResult::SWAP_ACK;
 }
 
diff --git a/ui/gl/gl_surface_presentation_helper.cc b/ui/gl/gl_surface_presentation_helper.cc
index 15e8dee..5391d73 100644
--- a/ui/gl/gl_surface_presentation_helper.cc
+++ b/ui/gl/gl_surface_presentation_helper.cc
@@ -25,7 +25,9 @@
 
 GLSurfacePresentationHelper::GLSurfacePresentationHelper(
     gfx::VSyncProvider* vsync_provider)
-    : vsync_provider_(vsync_provider), weak_ptr_factory_(this) {}
+    : vsync_provider_(vsync_provider), weak_ptr_factory_(this) {
+  DCHECK(vsync_provider_);
+}
 
 GLSurfacePresentationHelper::GLSurfacePresentationHelper(
     base::TimeTicks timebase,
@@ -82,19 +84,9 @@
   pending_frames_.push_back(Frame(std::move(timer), callback));
 }
 
-void GLSurfacePresentationHelper::PostSwapBuffers(gfx::SwapResult result) {
-  DCHECK(!pending_frames_.empty());
-  if (result != gfx::SwapResult::SWAP_ACK) {
-    auto frame = std::move(pending_frames_.back());
-    pending_frames_.pop_back();
-    if (frame.timer) {
-      bool has_context = gl_context_ && gl_context_->IsCurrent(surface_);
-      frame.timer->Destroy(has_context);
-    }
-    frame.callback.Run(gfx::PresentationFeedback());
-  } else if (!waiting_for_vsync_parameters_) {
+void GLSurfacePresentationHelper::PostSwapBuffers() {
+  if (!waiting_for_vsync_parameters_)
     CheckPendingFrames();
-  }
 }
 
 void GLSurfacePresentationHelper::CheckPendingFrames() {
@@ -117,8 +109,7 @@
   if (gl_context_ && !gl_context_->IsCurrent(surface_)) {
     gpu_timing_client_ = nullptr;
     for (auto& frame : pending_frames_) {
-      if (frame.timer)
-        frame.timer->Destroy(false /* has_context */);
+      frame.timer->Destroy(false /* has_context */);
       frame.callback.Run(gfx::PresentationFeedback());
     }
     pending_frames_.clear();
diff --git a/ui/gl/gl_surface_presentation_helper.h b/ui/gl/gl_surface_presentation_helper.h
index 234f08e5..e0e8b693 100644
--- a/ui/gl/gl_surface_presentation_helper.h
+++ b/ui/gl/gl_surface_presentation_helper.h
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "ui/gfx/swap_result.h"
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_surface.h"
 
@@ -36,7 +35,7 @@
 
   void OnMakeCurrent(GLContext* context, GLSurface* surface);
   void PreSwapBuffers(const GLSurface::PresentationCallback& callback);
-  void PostSwapBuffers(gfx::SwapResult result);
+  void PostSwapBuffers();
 
  private:
   struct Frame {
diff --git a/ui/gl/test/gl_image_test_support.cc b/ui/gl/test/gl_image_test_support.cc
index 675d383..fb4dcf42 100644
--- a/ui/gl/test/gl_image_test_support.cc
+++ b/ui/gl/test/gl_image_test_support.cc
@@ -24,6 +24,7 @@
 #if defined(USE_OZONE)
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
+  params.using_mojo = true;
   ui::OzonePlatform::InitializeForGPU(params);
 #endif
 
diff --git a/ui/gl/test/gl_surface_test_support.cc b/ui/gl/test/gl_surface_test_support.cc
index e4039b6..a1cab69 100644
--- a/ui/gl/test/gl_surface_test_support.cc
+++ b/ui/gl/test/gl_surface_test_support.cc
@@ -37,6 +37,7 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
   ui::test::EnableTestConfigForPlatformWindows();
@@ -116,6 +117,7 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
   InitializeOneOffImplementation(kGLImplementationMockGL, false);
@@ -126,6 +128,7 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 #endif
 
   InitializeOneOffImplementation(kGLImplementationStubGL, false);
diff --git a/ui/ozone/demo/ozone_demo.cc b/ui/ozone/demo/ozone_demo.cc
index 38d3c919..9598ed8 100644
--- a/ui/ozone/demo/ozone_demo.cc
+++ b/ui/ozone/demo/ozone_demo.cc
@@ -206,6 +206,7 @@
   ui::OzonePlatform::InitParams params;
   params.single_process = true;
   ui::OzonePlatform::InitializeForGPU(params);
+  ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(kDisableGpu) && gl::init::InitializeGLOneOff() &&
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
index 3eee627..99fc0d66 100644
--- a/ui/ozone/platform/drm/BUILD.gn
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -81,6 +81,8 @@
     "gpu/screen_manager.h",
     "host/drm_cursor.cc",
     "host/drm_cursor.h",
+    "host/drm_device_connector.cc",
+    "host/drm_device_connector.h",
     "host/drm_device_handle.cc",
     "host/drm_device_handle.h",
     "host/drm_display_host.cc",
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index a00011f..eb840a7 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -78,16 +78,18 @@
 }  // namespace
 
 DrmThread::DrmThread()
-    : base::Thread("DrmThread"), binding_(this), weak_ptr_factory_(this) {}
+    : base::Thread("DrmThread"), drm_binding_(this), weak_ptr_factory_(this) {}
 
 DrmThread::~DrmThread() {
   Stop();
 }
 
-void DrmThread::Start() {
+void DrmThread::Start(base::OnceClosure binding_completer) {
+  complete_early_binding_requests_ = std::move(binding_completer);
   base::Thread::Options thread_options;
   thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
   thread_options.priority = base::ThreadPriority::DISPLAY;
+
   if (!StartWithOptions(thread_options))
     LOG(FATAL) << "Failed to create DRM thread";
 }
@@ -104,6 +106,13 @@
 
   display_manager_.reset(
       new DrmGpuDisplayManager(screen_manager_.get(), device_manager_.get()));
+
+  DCHECK(task_runner())
+      << "DrmThread::Init -- thread doesn't have a task_runner";
+
+  // DRM thread is running now so can safely handle binding requests. So drain
+  // the queue of as-yet unhandled binding requests if there are any.
+  std::move(complete_early_binding_requests_).Run();
 }
 
 void DrmThread::CreateBuffer(gfx::AcceleratedWidget widget,
@@ -343,12 +352,12 @@
 // be used from multiple threads in multiple processes.
 void DrmThread::AddBindingCursorDevice(
     ozone::mojom::DeviceCursorRequest request) {
-  bindings_.AddBinding(this, std::move(request));
+  cursor_bindings_.AddBinding(this, std::move(request));
 }
 
 void DrmThread::AddBindingDrmDevice(ozone::mojom::DrmDeviceRequest request) {
   TRACE_EVENT0("drm", "DrmThread::AddBindingDrmDevice");
-  binding_.Bind(std::move(request));
+  drm_binding_.Bind(std::move(request));
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h
index 5c0dcad..ea944803 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -62,7 +62,7 @@
   DrmThread();
   ~DrmThread() override;
 
-  void Start();
+  void Start(base::OnceClosure binding_completer);
 
   // Must be called on the DRM thread. All methods for use from the GPU thread.
   // DrmThreadProxy (on GPU)thread) is the client for these methods.
@@ -150,12 +150,14 @@
   std::unique_ptr<ScreenManager> screen_manager_;
   std::unique_ptr<DrmGpuDisplayManager> display_manager_;
 
+  base::OnceClosure complete_early_binding_requests_;
+
   // The mojo implementation requires a BindingSet because the DrmThread serves
   // requests from two different client threads.
-  mojo::BindingSet<ozone::mojom::DeviceCursor> bindings_;
+  mojo::BindingSet<ozone::mojom::DeviceCursor> cursor_bindings_;
 
   // The mojo implementation of DrmDevice can use a simple binding.
-  mojo::Binding<ozone::mojom::DrmDevice> binding_;
+  mojo::Binding<ozone::mojom::DrmDevice> drm_binding_;
 
   base::WeakPtrFactory<DrmThread> weak_ptr_factory_;
 
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
index 24a88ec..6e1d4a74 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
@@ -26,10 +26,6 @@
 
 void DrmThreadMessageProxy::OnFilterAdded(IPC::Channel* channel) {
   sender_ = channel;
-
-  // The DRM thread needs to be started late since we need to wait for the
-  // sandbox to start.
-  drm_thread_->Start();
 }
 
 bool DrmThreadMessageProxy::OnMessageReceived(const IPC::Message& message) {
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
index bdc798c..2bad52d 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -17,13 +17,15 @@
 
 DrmThreadProxy::~DrmThreadProxy() {}
 
+// Used only with the paramtraits implementation.
 void DrmThreadProxy::BindThreadIntoMessagingProxy(
     InterThreadMessagingProxy* messaging_proxy) {
   messaging_proxy->SetDrmThread(&drm_thread_);
 }
 
-void DrmThreadProxy::StartDrmThread() {
-  drm_thread_.Start();
+// Used only for the mojo implementation.
+void DrmThreadProxy::StartDrmThread(base::OnceClosure binding_drainer) {
+  drm_thread_.Start(std::move(binding_drainer));
 }
 
 std::unique_ptr<DrmWindowProxy> DrmThreadProxy::CreateDrmWindowProxy(
@@ -36,7 +38,10 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage) {
+  DCHECK(drm_thread_.task_runner())
+      << "no task runner! in DrmThreadProxy::CreateBuffer";
   scoped_refptr<GbmBuffer> buffer;
+
   PostSyncTask(
       drm_thread_.task_runner(),
       base::Bind(&DrmThread::CreateBuffer, base::Unretained(&drm_thread_),
@@ -77,6 +82,9 @@
 
 void DrmThreadProxy::AddBindingDrmDevice(
     ozone::mojom::DrmDeviceRequest request) {
+  DCHECK(drm_thread_.task_runner()) << "DrmThreadProxy::AddBindingDrmDevice "
+                                       "drm_thread_ task runner missing";
+
   drm_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&DrmThread::AddBindingDrmDevice,
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
index c8a0b4b..d46de5a 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
@@ -27,7 +27,7 @@
 
   void BindThreadIntoMessagingProxy(InterThreadMessagingProxy* messaging_proxy);
 
-  void StartDrmThread();
+  void StartDrmThread(base::OnceClosure binding_drainer);
 
   std::unique_ptr<DrmWindowProxy> CreateDrmWindowProxy(
       gfx::AcceleratedWidget widget);
diff --git a/ui/ozone/platform/drm/host/drm_device_connector.cc b/ui/ozone/platform/drm/host/drm_device_connector.cc
new file mode 100644
index 0000000..c0468196
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_device_connector.cc
@@ -0,0 +1,101 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/drm/host/drm_device_connector.h"
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/ui/public/interfaces/constants.mojom.h"
+#include "ui/ozone/platform/drm/host/host_drm_device.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+
+namespace {
+// TODO(rjkroege): In the future when ozone/drm is always mojo-based, remove
+// this utility code.
+using BinderCallback = ui::GpuPlatformSupportHost::GpuHostBindInterfaceCallback;
+
+void BindInterfaceInGpuProcess(const std::string& interface_name,
+                               mojo::ScopedMessagePipeHandle interface_pipe,
+                               const BinderCallback& binder_callback) {
+  return binder_callback.Run(interface_name, std::move(interface_pipe));
+}
+
+template <typename Interface>
+void BindInterfaceInGpuProcess(mojo::InterfaceRequest<Interface> request,
+                               const BinderCallback& binder_callback) {
+  BindInterfaceInGpuProcess(
+      Interface::Name_, std::move(request.PassMessagePipe()), binder_callback);
+}
+
+}  // namespace
+
+namespace ui {
+
+DrmDeviceConnector::DrmDeviceConnector(
+    service_manager::Connector* connector,
+    scoped_refptr<HostDrmDevice> host_drm_device_)
+    : connector_(connector), host_drm_device_(host_drm_device_) {}
+
+DrmDeviceConnector::~DrmDeviceConnector() {}
+
+void DrmDeviceConnector::OnGpuProcessLaunched(
+    int host_id,
+    scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+    const base::RepeatingCallback<void(IPC::Message*)>& send_callback) {
+  NOTREACHED();
+}
+
+void DrmDeviceConnector::OnChannelDestroyed(int host_id) {
+  // TODO(rjkroege): Handle Viz restarting.
+  NOTIMPLEMENTED();
+}
+
+void DrmDeviceConnector::OnGpuServiceLaunched(
+    scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+    GpuHostBindInterfaceCallback binder) {
+  // We need to preserve |binder| to let us bind interfaces later.
+  binder_callback_ = std::move(binder);
+
+  ui::ozone::mojom::DrmDevicePtr drm_device_ptr;
+  BindInterfaceDrmDevice(&drm_device_ptr);
+  ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui, cursor_ptr_io;
+  BindInterfaceDeviceCursor(&cursor_ptr_ui);
+  BindInterfaceDeviceCursor(&cursor_ptr_io);
+
+  ui_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&HostDrmDevice::OnGpuServiceLaunched, host_drm_device_,
+                     std::move(drm_device_ptr), std::move(cursor_ptr_ui),
+                     std::move(cursor_ptr_io)));
+}
+
+void DrmDeviceConnector::OnMessageReceived(const IPC::Message& message) {
+  NOTREACHED() << "This class should only be used with mojo transport but here "
+                  "we're wrongly getting invoked to handle IPC communication.";
+}
+
+void DrmDeviceConnector::BindInterfaceDrmDevice(
+    ui::ozone::mojom::DrmDevicePtr* drm_device_ptr) const {
+  if (connector_) {
+    connector_->BindInterface(ui::mojom::kServiceName, drm_device_ptr);
+  } else {
+    auto request = mojo::MakeRequest(drm_device_ptr);
+    BindInterfaceInGpuProcess(std::move(request), binder_callback_);
+  }
+}
+
+void DrmDeviceConnector::BindInterfaceDeviceCursor(
+    ui::ozone::mojom::DeviceCursorPtr* cursor_ptr) const {
+  if (connector_) {
+    connector_->BindInterface(ui::mojom::kServiceName, cursor_ptr);
+  } else {
+    auto request = mojo::MakeRequest(cursor_ptr);
+    BindInterfaceInGpuProcess(std::move(request), binder_callback_);
+  }
+}
+
+}  // namespace ui
\ No newline at end of file
diff --git a/ui/ozone/platform/drm/host/drm_device_connector.h b/ui/ozone/platform/drm/host/drm_device_connector.h
new file mode 100644
index 0000000..c717662
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_device_connector.h
@@ -0,0 +1,70 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_CONNECTOR_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_CONNECTOR_H_
+
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/interfaces/device_cursor.mojom.h"
+#include "ui/ozone/public/interfaces/drm_device.mojom.h"
+
+namespace service_manager {
+class Connector;
+}
+
+namespace ui {
+class HostDrmDevice;
+
+// DrmDeviceConnector sets up mojo pipes connecting the Viz host to the DRM
+// service. It operates in two modes: running on the I/O thread when invoked
+// from content and running on the VizHost main thread when operating with a
+// service_manager.
+class DrmDeviceConnector : public GpuPlatformSupportHost {
+ public:
+  DrmDeviceConnector(service_manager::Connector* connector,
+                     scoped_refptr<HostDrmDevice> host_drm_device_);
+  ~DrmDeviceConnector() override;
+
+  // GpuPlatformSupportHost:
+  void OnGpuProcessLaunched(
+      int host_id,
+      scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+      const base::RepeatingCallback<void(IPC::Message*)>& send_callback)
+      override;
+  void OnChannelDestroyed(int host_id) override;
+  void OnMessageReceived(const IPC::Message& message) override;
+  void OnGpuServiceLaunched(
+      scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+      GpuHostBindInterfaceCallback binder) override;
+
+  // BindInterface arranges for the drm_device_ptr to be connected.
+  void BindInterfaceDrmDevice(
+      ui::ozone::mojom::DrmDevicePtr* drm_device_ptr) const;
+
+  // BindInterface arranges for the cursor_ptr to be wired up.
+  void BindInterfaceDeviceCursor(
+      ui::ozone::mojom::DeviceCursorPtr* cursor_ptr) const;
+
+  // BindableNow returns true if this DrmDeviceConnector is capable of binding a
+  // mojo endpoint for the DrmDevice service.
+  bool BindableNow() const { return !!connector_; }
+
+ private:
+  // This will be present if the Viz host has a service manager.
+  service_manager::Connector* connector_;
+
+  // This will be used if we are operating under content/gpu without a service
+  // manager.
+  GpuHostBindInterfaceCallback binder_callback_;
+
+  scoped_refptr<HostDrmDevice> host_drm_device_;
+
+  DISALLOW_COPY_AND_ASSIGN(DrmDeviceConnector);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRM_HOST_DRM_DEVICE_CONNECTOR_H_
\ No newline at end of file
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
index c8267a2..df8585d 100644
--- a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
@@ -117,6 +117,14 @@
   return host_id_ >= 0 && channel_established_;
 }
 
+void DrmGpuPlatformSupportHost::OnGpuServiceLaunched(
+    scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+    GpuHostBindInterfaceCallback binder) {
+  NOTREACHED() << "DrmGpuPlatformSupportHost::OnGpuServiceLaunched shouldn't "
+                  "be used with pre-mojo IPC";
+}
+
 void DrmGpuPlatformSupportHost::OnGpuProcessLaunched(
     int host_id,
     scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
diff --git a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
index 1de15ce..ebcb9d5e 100644
--- a/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
+++ b/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h
@@ -41,6 +41,10 @@
       scoped_refptr<base::SingleThreadTaskRunner> send_runner,
       const base::Callback<void(IPC::Message*)>& send_callback) override;
   void OnChannelDestroyed(int host_id) override;
+  void OnGpuServiceLaunched(
+      scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+      GpuHostBindInterfaceCallback binder) override;
 
   void OnMessageReceived(const IPC::Message& message) override;
 
diff --git a/ui/ozone/platform/drm/host/host_cursor_proxy.cc b/ui/ozone/platform/drm/host/host_cursor_proxy.cc
index ba5baeec..fa2880d 100644
--- a/ui/ozone/platform/drm/host/host_cursor_proxy.cc
+++ b/ui/ozone/platform/drm/host/host_cursor_proxy.cc
@@ -6,15 +6,17 @@
 
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/ui/public/interfaces/constants.mojom.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
 
 namespace ui {
 
-// We assume that this is invoked only on the UI thread.
-HostCursorProxy::HostCursorProxy(service_manager::Connector* connector)
-    : connector_(connector->Clone()) {
-  ui_thread_ref_ = base::PlatformThread::CurrentRef();
-  connector->BindInterface(ui::mojom::kServiceName, &main_cursor_ptr_);
-}
+// We assume that this is invoked only on the Mus/UI thread.
+HostCursorProxy::HostCursorProxy(
+    ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr,
+    ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr)
+    : main_cursor_ptr_(std::move(main_cursor_ptr)),
+      evdev_cursor_ptr_(std::move(evdev_cursor_ptr)),
+      ui_thread_ref_(base::PlatformThread::CurrentRef()) {}
 
 HostCursorProxy::~HostCursorProxy() {}
 
@@ -46,8 +48,14 @@
 // when the GpuThread/DrmThread pair are once again running), we need to run it
 // on cursor motions.
 void HostCursorProxy::InitializeOnEvdevIfNecessary() {
+  // TODO(rjkroege): Rebind on Viz process restart.
+  if (evdev_bound_)
+    return;
+
   if (ui_thread_ref_ != base::PlatformThread::CurrentRef()) {
-    connector_->BindInterface(ui::mojom::kServiceName, &evdev_cursor_ptr_);
+    // Rebind the mojo pipe on the current thread. We expect this to be the
+    // thread running EVDEV.
+    evdev_cursor_ptr_.Bind(evdev_cursor_ptr_.PassInterface());
   }
 }
 
diff --git a/ui/ozone/platform/drm/host/host_cursor_proxy.h b/ui/ozone/platform/drm/host/host_cursor_proxy.h
index 42feece..87115dd 100644
--- a/ui/ozone/platform/drm/host/host_cursor_proxy.h
+++ b/ui/ozone/platform/drm/host/host_cursor_proxy.h
@@ -9,10 +9,6 @@
 #include "ui/ozone/platform/drm/host/drm_cursor.h"
 #include "ui/ozone/public/interfaces/device_cursor.mojom.h"
 
-namespace service_manager {
-class Connector;
-}
-
 namespace ui {
 
 // Ozone requires a IPC from the browser (or mus-ws) process to the gpu (or
@@ -22,7 +18,8 @@
 // priviledged process.
 class HostCursorProxy : public DrmCursorProxy {
  public:
-  explicit HostCursorProxy(service_manager::Connector* connector);
+  HostCursorProxy(ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr,
+                  ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr);
   ~HostCursorProxy() override;
 
  private:
@@ -34,13 +31,13 @@
   void Move(gfx::AcceleratedWidget window, const gfx::Point& point) override;
   void InitializeOnEvdevIfNecessary() override;
 
-  std::unique_ptr<service_manager::Connector> connector_;
-
   // Mojo implementation of the DrmCursorProxy.
-  ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr_;
-  ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr_;
+  ui::ozone::mojom::DeviceCursorPtr main_cursor_ptr_ = nullptr;
+  ui::ozone::mojom::DeviceCursorPtr evdev_cursor_ptr_ = nullptr;
 
   base::PlatformThreadRef ui_thread_ref_;
+  bool evdev_bound_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(HostCursorProxy);
 };
 
diff --git a/ui/ozone/platform/drm/host/host_drm_device.cc b/ui/ozone/platform/drm/host/host_drm_device.cc
index 9d1311b..682942ae 100644
--- a/ui/ozone/platform/drm/host/host_drm_device.cc
+++ b/ui/ozone/platform/drm/host/host_drm_device.cc
@@ -13,19 +13,15 @@
 #include "services/ui/public/interfaces/constants.mojom.h"
 #include "ui/display/types/display_snapshot.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/host/drm_device_connector.h"
 #include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
 #include "ui/ozone/platform/drm/host/drm_overlay_manager.h"
 #include "ui/ozone/platform/drm/host/host_cursor_proxy.h"
 
 namespace ui {
 
-HostDrmDevice::HostDrmDevice(DrmCursor* cursor,
-                             service_manager::Connector* connector)
-    : cursor_(cursor), connector_(connector), weak_ptr_factory_(this) {
-  // Bind the viz process pointer here.
-  // TODO(rjkroege): Reconnect on error as that would indicate that the Viz
-  // process has failed.
-  connector->BindInterface(ui::mojom::kServiceName, &drm_device_ptr_);
+HostDrmDevice::HostDrmDevice(DrmCursor* cursor) : cursor_(cursor) {
+  DETACH_FROM_THREAD(on_io_thread_);
 }
 
 HostDrmDevice::~HostDrmDevice() {
@@ -34,15 +30,39 @@
     observer.OnGpuThreadRetired();
 }
 
-void HostDrmDevice::AsyncStartDrmDevice() {
-  auto callback = base::BindOnce(&HostDrmDevice::OnDrmServiceStartedCallback,
-                                 weak_ptr_factory_.GetWeakPtr());
+// Setup the DRM device if we are using the ServiceManager.
+void HostDrmDevice::AsyncStartDrmDevice(const DrmDeviceConnector& connector) {
+  DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
+
+  // We bind here using the provided connector object.
+  if (!connector.BindableNow())
+    return;
+
+  connector.BindInterfaceDrmDevice(&drm_device_ptr_);
+
+  // Launch the DRM thread.
+  auto callback =
+      base::BindOnce(&HostDrmDevice::OnDrmServiceStartedCallback, this);
   drm_device_ptr_->StartDrmDevice(std::move(callback));
+
+  // Bind the cursor interface pointers.
+  ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui, cursor_ptr_io;
+  connector.BindInterfaceDeviceCursor(&cursor_ptr_ui);
+
+  // This interface pointer is bound on the wrong thread. But that's OK because
+  // we'll re-bind it the first time that it's used from the I/O thread in
+  // HostCursorProxy.
+  connector.BindInterfaceDeviceCursor(&cursor_ptr_io);
+
+  // Stash the cursor_proxy so that we can install it in the callback.
+  cursor_proxy_ = std::make_unique<HostCursorProxy>(std::move(cursor_ptr_ui),
+                                                    std::move(cursor_ptr_io));
 }
 
+// TODO(rjkroege): Remove the need for this entry point.
 void HostDrmDevice::BlockingStartDrmDevice() {
   // Wait until startup related tasks posted to this thread that must precede
-  // blocking on
+  // blocking.
   base::RunLoop().RunUntilIdle();
 
   bool success;
@@ -54,15 +74,20 @@
   return;
 }
 
+// The callback is executed in response to getting back a message from a
+// DrmDevice service that we launched earlier via ServiceManager.
 void HostDrmDevice::OnDrmServiceStartedCallback(bool success) {
   // This can be called multiple times in the course of single-threaded startup.
+  // Ignore invocations after we've started.
   if (connected_)
     return;
+
   if (success == true) {
     connected_ = true;
     RunObservers();
   }
-  // TODO(rjkroege): Handle failure of launching a viz process.
+  // TODO(rjkroege): Handle failure of launching a viz process with the
+  // ServiceManager.
 }
 
 void HostDrmDevice::ProvideManagers(DrmDisplayHostManager* display_manager,
@@ -78,10 +103,9 @@
     observer.OnGpuThreadReady();
   }
 
-  // The cursor is special since it will process input events on the IO thread
-  // and can by-pass the UI thread. This means that we need to special case it
-  // and notify it after all other observers/handlers are notified.
-  cursor_->SetDrmCursorProxy(std::make_unique<HostCursorProxy>(connector_));
+  DCHECK(cursor_proxy_)
+      << "We should have already created a cursor proxy previously";
+  cursor_->SetDrmCursorProxy(std::move(cursor_proxy_));
 
   // TODO(rjkroege): Call ResetDrmCursorProxy when the mojo connection to the
   // DRM thread is broken.
@@ -146,14 +170,15 @@
     return false;
 
   drm_device_ptr_->SetWindowBounds(widget, bounds);
+
   return true;
 }
 
 // Services needed for DrmOverlayManager.
 void HostDrmDevice::RegisterHandlerForDrmOverlayManager(
     DrmOverlayManager* handler) {
-  // TODO(rjkroege): Permit overlay manager to run in viz when the display
-  // compositor runs in viz.
+  // TODO(rjkroege): Permit overlay manager to run in Viz when the display
+  // compositor runs in Viz.
   DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
   overlay_manager_ = handler;
 }
@@ -171,11 +196,11 @@
     return false;
 
   auto callback =
-      base::BindOnce(&HostDrmDevice::GpuCheckOverlayCapabilitiesCallback,
-                     weak_ptr_factory_.GetWeakPtr());
+      base::BindOnce(&HostDrmDevice::GpuCheckOverlayCapabilitiesCallback, this);
 
   drm_device_ptr_->CheckOverlayCapabilities(widget, overlays,
                                             std::move(callback));
+
   return true;
 }
 
@@ -183,10 +208,11 @@
   DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
   if (!IsConnected())
     return false;
+
   auto callback =
-      base::BindOnce(&HostDrmDevice::GpuRefreshNativeDisplaysCallback,
-                     weak_ptr_factory_.GetWeakPtr());
+      base::BindOnce(&HostDrmDevice::GpuRefreshNativeDisplaysCallback, this);
   drm_device_ptr_->RefreshNativeDisplays(std::move(callback));
+
   return true;
 }
 
@@ -200,11 +226,11 @@
   // TODO(rjkroege): Remove the use of mode here.
   auto mode = CreateDisplayModeFromParams(pmode);
   auto callback =
-      base::BindOnce(&HostDrmDevice::GpuConfigureNativeDisplayCallback,
-                     weak_ptr_factory_.GetWeakPtr());
+      base::BindOnce(&HostDrmDevice::GpuConfigureNativeDisplayCallback, this);
 
   drm_device_ptr_->ConfigureNativeDisplay(id, std::move(mode), origin,
                                           std::move(callback));
+
   return true;
 }
 
@@ -213,9 +239,10 @@
   if (!IsConnected())
     return false;
   auto callback =
-      base::BindOnce(&HostDrmDevice::GpuDisableNativeDisplayCallback,
-                     weak_ptr_factory_.GetWeakPtr());
+      base::BindOnce(&HostDrmDevice::GpuDisableNativeDisplayCallback, this);
+
   drm_device_ptr_->DisableNativeDisplay(id, std::move(callback));
+
   return true;
 }
 
@@ -223,9 +250,11 @@
   DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
   if (!IsConnected())
     return false;
-  auto callback = base::BindOnce(&HostDrmDevice::GpuTakeDisplayControlCallback,
-                                 weak_ptr_factory_.GetWeakPtr());
+  auto callback =
+      base::BindOnce(&HostDrmDevice::GpuTakeDisplayControlCallback, this);
+
   drm_device_ptr_->TakeDisplayControl(std::move(callback));
+
   return true;
 }
 
@@ -234,9 +263,10 @@
   if (!IsConnected())
     return false;
   auto callback =
-      base::BindOnce(&HostDrmDevice::GpuRelinquishDisplayControlCallback,
-                     weak_ptr_factory_.GetWeakPtr());
+      base::BindOnce(&HostDrmDevice::GpuRelinquishDisplayControlCallback, this);
+
   drm_device_ptr_->RelinquishDisplayControl(std::move(callback));
+
   return true;
 }
 
@@ -246,7 +276,9 @@
   if (!IsConnected())
     return false;
   base::File file(fd.release());
+
   drm_device_ptr_->AddGraphicsDevice(path, std::move(file));
+
   return true;
 }
 
@@ -254,7 +286,9 @@
   DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
   if (!IsConnected())
     return false;
+
   drm_device_ptr_->RemoveGraphicsDevice(std::move(path));
+
   return true;
 }
 
@@ -262,9 +296,10 @@
   DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
   if (!IsConnected())
     return false;
-  auto callback = base::BindOnce(&HostDrmDevice::GpuGetHDCPStateCallback,
-                                 weak_ptr_factory_.GetWeakPtr());
+  auto callback = base::BindOnce(&HostDrmDevice::GpuGetHDCPStateCallback, this);
+
   drm_device_ptr_->GetHDCPState(display_id, std::move(callback));
+
   return true;
 }
 
@@ -273,9 +308,10 @@
   DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
   if (!IsConnected())
     return false;
-  auto callback = base::BindOnce(&HostDrmDevice::GpuSetHDCPStateCallback,
-                                 weak_ptr_factory_.GetWeakPtr());
+  auto callback = base::BindOnce(&HostDrmDevice::GpuSetHDCPStateCallback, this);
+
   drm_device_ptr_->SetHDCPState(display_id, state, std::move(callback));
+
   return true;
 }
 
@@ -345,4 +381,30 @@
   display_manager_->GpuUpdatedHDCPState(display_id, success);
 }
 
+// Invoked in response to the successful launching of the GPU service.
+void HostDrmDevice::OnGpuServiceLaunched(
+    ui::ozone::mojom::DrmDevicePtr drm_device_ptr,
+    ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui,
+    ui::ozone::mojom::DeviceCursorPtr cursor_ptr_io) {
+  DCHECK_CALLED_ON_VALID_THREAD(on_window_server_thread_);
+
+  // Rebind InterfacePtrs to the window server thread.
+  cursor_ptr_ui.Bind(cursor_ptr_ui.PassInterface());
+  drm_device_ptr.Bind(drm_device_ptr.PassInterface());
+
+  drm_device_ptr_ = std::move(drm_device_ptr);
+
+  // Make sure that we've launched the DRM device service in the Viz process.
+  auto callback =
+      base::BindOnce(&HostDrmDevice::OnDrmServiceStartedCallback, this);
+  drm_device_ptr_->StartDrmDevice(std::move(callback));
+
+  // The cursor is special since it will process input events on the IO thread
+  // and can by-pass the UI thread. As a result, it has an InterfacePtr for both
+  // the window server and I/O thread.  cursor_ptr_io is already bound correctly
+  // to an I/O thread by GpuProcessHost.
+  cursor_proxy_ = std::make_unique<HostCursorProxy>(std::move(cursor_ptr_ui),
+                                                    std::move(cursor_ptr_io));
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/host/host_drm_device.h b/ui/ozone/platform/drm/host/host_drm_device.h
index 47c5b18..4562cc5f 100644
--- a/ui/ozone/platform/drm/host/host_drm_device.h
+++ b/ui/ozone/platform/drm/host/host_drm_device.h
@@ -14,6 +14,7 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/platform/drm/host/drm_cursor.h"
 #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
 #include "ui/ozone/public/interfaces/device_cursor.mojom.h"
 #include "ui/ozone/public/interfaces/drm_device.mojom.h"
 
@@ -21,25 +22,23 @@
 class DisplaySnapshot;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 namespace ui {
 class DrmDisplayHostManager;
 class DrmOverlayManager;
 class GpuThreadObserver;
+class DrmDeviceConnector;
+class HostCursorProxy;
 
 // This is the Viz host-side library for the DRM device service provided by the
 // viz process.
-class HostDrmDevice : public GpuThreadAdapter {
+class HostDrmDevice : public base::RefCountedThreadSafe<HostDrmDevice>,
+                      public GpuThreadAdapter {
  public:
-  HostDrmDevice(DrmCursor* cursor, service_manager::Connector* connector);
-  ~HostDrmDevice() override;
+  explicit HostDrmDevice(DrmCursor* cursor);
 
   // Start the DRM service. Runs the |OnDrmServiceStartedCallback| when the
   // service has launched and initiates the remaining startup.
-  void AsyncStartDrmDevice();
+  void AsyncStartDrmDevice(const DrmDeviceConnector& connector);
 
   // Blocks until the DRM service has come up. Use this entry point only when
   // supporting launch of the service where the ozone UI and GPU
@@ -49,6 +48,10 @@
   void ProvideManagers(DrmDisplayHostManager* display_manager,
                        DrmOverlayManager* overlay_manager);
 
+  void OnGpuServiceLaunched(ui::ozone::mojom::DrmDevicePtr drm_device_ptr,
+                            ui::ozone::mojom::DeviceCursorPtr cursor_ptr_ui,
+                            ui::ozone::mojom::DeviceCursorPtr cursor_ptr_io);
+
   // GpuThreadAdapter
   void AddGpuThreadObserver(GpuThreadObserver* observer) override;
   void RemoveGpuThreadObserver(GpuThreadObserver* observer) override;
@@ -93,8 +96,24 @@
                               const gfx::Rect& bounds) override;
 
  private:
+  friend class base::RefCountedThreadSafe<HostDrmDevice>;
+  ~HostDrmDevice() override;
+
+  void HostOnGpuServiceLaunched();
+
+  // BindInterface arranges for the drm_device_ptr to be wired up.
+  void BindInterfaceDrmDevice(
+      ui::ozone::mojom::DrmDevicePtr* drm_device_ptr) const;
+
+  // BindInterface arranges for the cursor_ptr to be wired up.
+  void BindInterfaceDeviceCursor(
+      ui::ozone::mojom::DeviceCursorPtr* cursor_ptr) const;
+
   void OnDrmServiceStartedCallback(bool success);
+
+  // TODO(rjkroege): Get rid of the need for this method in a subsequent CL.
   void PollForSingleThreadReady(int previous_delay);
+
   void RunObservers();
 
   void GpuCheckOverlayCapabilitiesCallback(
@@ -115,21 +134,25 @@
                                display::HDCPState state) const;
   void GpuSetHDCPStateCallback(int64_t display_id, bool success) const;
 
-  // Mojo implementation of the DrmDevice.
+  // Mojo implementation of the DrmDevice. Will be bound on the "main" thread.
   ui::ozone::mojom::DrmDevicePtr drm_device_ptr_;
 
   DrmDisplayHostManager* display_manager_;  // Not owned.
   DrmOverlayManager* overlay_manager_;      // Not owned.
   DrmCursor* cursor_;                       // Not owned.
 
-  service_manager::Connector* connector_;
+  std::unique_ptr<HostCursorProxy> cursor_proxy_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> ws_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
+
+  THREAD_CHECKER(on_io_thread_);  // Needs to be rebound as is allocated on the
+                                  // window server  thread.
   THREAD_CHECKER(on_window_server_thread_);
 
   bool connected_ = false;
   base::ObserverList<GpuThreadObserver> gpu_thread_observers_;
 
-  base::WeakPtrFactory<HostDrmDevice> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(HostDrmDevice);
 };
 
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index 3ad0de48..bd56715d 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -37,6 +37,7 @@
 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 #include "ui/ozone/platform/drm/host/drm_cursor.h"
+#include "ui/ozone/platform/drm/host/drm_device_connector.h"
 #include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
 #include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
 #include "ui/ozone/platform/drm/host/drm_native_display_delegate.h"
@@ -100,47 +101,85 @@
     return event_factory_ozone_->input_controller();
   }
   IPC::MessageFilter* GetGpuMessageFilter() override {
-    return gpu_message_filter_.get();
+    if (using_mojo_) {
+      return nullptr;
+    } else {
+      return gpu_message_filter_.get();
+    }
   }
+
   GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
-    return gpu_platform_support_host_.get();
+    if (using_mojo_) {
+      return drm_device_connector_.get();
+    } else {
+      return gpu_platform_support_host_.get();
+    }
   }
+
   std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override {
     return event_factory_ozone_->CreateSystemInputInjector();
   }
 
+  // In multi-process mode, this function must be executed in Viz as it sets up
+  // the callbacks needed  for Mojo bindings.  In single process mode, it may be
+  // called on any thread.  It must follow one of |InitializeUI| or
+  // |InitializeGPU|. Invocations of this method when not using mojo will be
+  // ignored. While the caller may choose to invoke this method before entering
+  // the sandbox, the actual interface adding has to happen on the DRM Device
+  // thread and so will be deferred until the DRM thread is running.
   void AddInterfaces(
       service_manager::BinderRegistryWithArgs<
           const service_manager::BindSourceInfo&>* registry) override {
+    if (!using_mojo_)
+      return;
+
     registry->AddInterface<ozone::mojom::DeviceCursor>(
         base::Bind(&OzonePlatformGbm::CreateDeviceCursorBinding,
                    weak_factory_.GetWeakPtr()),
-        gpu_task_runner_);
+        base::ThreadTaskRunnerHandle::Get());
 
     registry->AddInterface<ozone::mojom::DrmDevice>(
         base::Bind(&OzonePlatformGbm::CreateDrmDeviceBinding,
                    weak_factory_.GetWeakPtr()),
-        gpu_task_runner_);
+        base::ThreadTaskRunnerHandle::Get());
   }
+
+  // Runs on the thread where AddInterfaces was invoked. But the endpoint is
+  // always bound on the DRM thread.
   void CreateDeviceCursorBinding(
       ozone::mojom::DeviceCursorRequest request,
       const service_manager::BindSourceInfo& source_info) {
-    if (drm_thread_proxy_)
+    if (drm_thread_started_)
       drm_thread_proxy_->AddBindingCursorDevice(std::move(request));
     else
       pending_cursor_requests_.push_back(std::move(request));
   }
-
+  // Runs on the thread where AddInterfaces was invoked. But the endpoint is
+  // always bound on the DRM thread.
   // service_manager::InterfaceFactory<ozone::mojom::DrmDevice>:
   void CreateDrmDeviceBinding(
       ozone::mojom::DrmDeviceRequest request,
       const service_manager::BindSourceInfo& source_info) {
-    if (drm_thread_proxy_)
+    if (drm_thread_started_)
       drm_thread_proxy_->AddBindingDrmDevice(std::move(request));
     else
       pending_gpu_adapter_requests_.push_back(std::move(request));
   }
 
+  // Runs on the thread that invoked |AddInterfaces| to drain the queue of
+  // binding requests that could not be satisfied until the DRM thread is
+  // available (i.e. if waiting until the sandbox has been entered.)
+  void DrainBindingRequests() {
+    for (auto& request : pending_cursor_requests_)
+      drm_thread_proxy_->AddBindingCursorDevice(std::move(request));
+    pending_cursor_requests_.clear();
+    for (auto& request : pending_gpu_adapter_requests_)
+      drm_thread_proxy_->AddBindingDrmDevice(std::move(request));
+    pending_gpu_adapter_requests_.clear();
+
+    drm_thread_started_ = true;
+  }
+
   std::unique_ptr<PlatformWindow> CreatePlatformWindow(
       PlatformWindowDelegate* delegate,
       const gfx::Rect& bounds) override {
@@ -159,20 +198,30 @@
       override {
     return std::make_unique<DrmNativeDisplayDelegate>(display_manager_.get());
   }
+
   void InitializeUI(const InitParams& args) override {
-    // Ozone drm can operate in three modes configured at runtime:
+    // Ozone drm can operate in four modes configured at
+    // runtime. Three process modes:
     //   1. legacy mode where host and viz components communicate
     //      via param traits IPC.
     //   2. single-process mode where host and viz components
-    //      communicate via in-process mojo.
+    //      communicate via in-process mojo. Single-process mode can be single
+    //      or multi-threaded.
     //   3. multi-process mode where host and viz components communicate
     //      via mojo IPC.
-    single_process_ = args.single_process;
-    using_mojo_ = args.connector != nullptr;
-    host_thread_ = base::PlatformThread::CurrentRef();
+    //
+    // and 2 connection modes
+    //   a. Viz is launched via content::GpuProcessHost and it notifies the
+    //   ozone host when Viz becomes available. b. The ozone host uses a service
+    //   manager to launch and connect to Viz.
+    //
+    // Combinations 1a, 2b, and 3a, and 3b are supported and expected to work.
+    // Combination 1a will hopefully be deprecated and replaced with 3a.
+    // Combination 2b adds undesirable code-debt and the intent is to remove it.
 
-    DCHECK(!(using_mojo_ && !single_process_))
-        << "Multiprocess Mojo is not supported yet.";
+    single_process_ = args.single_process;
+    using_mojo_ = args.using_mojo || args.connector != nullptr;
+    host_thread_ = base::PlatformThread::CurrentRef();
 
     device_manager_ = CreateDeviceManager();
     window_manager_.reset(new DrmWindowHostManager());
@@ -195,8 +244,9 @@
       gl_api_loader_.reset(new GlApiLoader());
 
     if (using_mojo_) {
-      host_drm_device_ =
-          std::make_unique<HostDrmDevice>(cursor_.get(), args.connector);
+      host_drm_device_ = base::MakeRefCounted<HostDrmDevice>(cursor_.get());
+      drm_device_connector_ = std::make_unique<DrmDeviceConnector>(
+          args.connector, host_drm_device_);
       adapter = host_drm_device_.get();
     } else {
       gpu_platform_support_host_.reset(
@@ -214,17 +264,12 @@
     if (using_mojo_) {
       host_drm_device_->ProvideManagers(display_manager_.get(),
                                         overlay_manager_.get());
-      host_drm_device_->AsyncStartDrmDevice();
+      host_drm_device_->AsyncStartDrmDevice(*drm_device_connector_);
     }
   }
 
   void InitializeGPU(const InitParams& args) override {
-    // TODO(rjkroege): services/ui should initialize this with a connector.
-    // However, in-progress refactorings in services/ui make it difficult to
-    // require this at present. Set using_mojo_ like below once this is
-    // complete.
-    // TODO(rjk): Make it possible to turn this on.
-    // using_mojo_ = args.connector != nullptr;
+    using_mojo_ = args.using_mojo;
     gpu_task_runner_ = base::ThreadTaskRunnerHandle::Get();
 
     if (!single_process_)
@@ -239,48 +284,50 @@
     }
 
     // NOTE: Can't start the thread here since this is called before sandbox
-    // initialization in multi-process Chrome. In mus, we start the DRM thread.
+    // initialization in multi-process Chrome.
     drm_thread_proxy_.reset(new DrmThreadProxy());
 
     surface_factory_.reset(new GbmSurfaceFactory(drm_thread_proxy_.get()));
     if (!using_mojo_) {
       drm_thread_proxy_->BindThreadIntoMessagingProxy(itmp);
-    } else {
-      drm_thread_proxy_->StartDrmThread();
     }
 
-    // When the viz process (and hence the gpu portion of ozone/gbm) is
-    // operating in a single process, the AddInterfaces method is best
-    // invoked before the GPU thread launches.  As a result, requests to add
-    // mojom bindings to the as yet un-launched service will fail so we queue
-    // incoming binding requests until the GPU thread is running and play them
-    // back here.
-    for (auto& request : pending_cursor_requests_)
-      drm_thread_proxy_->AddBindingCursorDevice(std::move(request));
-    pending_cursor_requests_.clear();
-    for (auto& request : pending_gpu_adapter_requests_)
-      drm_thread_proxy_->AddBindingDrmDevice(std::move(request));
-    pending_gpu_adapter_requests_.clear();
-
     // If InitializeGPU and InitializeUI are invoked on the same thread, startup
     // sequencing is complicated because tasks are queued on the unbound mojo
     // pipe connecting the UI (the host) to the DRM thread before the DRM thread
-    // is launched above. Special case this sequence vis the
+    // is launched above. Special case this sequence via the
     // BlockingStartDrmDevice API.
     // TODO(rjkroege): In a future when we have completed splitting Viz, it will
     // be possible to simplify this logic.
-    if (using_mojo_ && single_process_ &&
-        host_thread_ == base::PlatformThread::CurrentRef()) {
+    if (using_mojo_ && single_process_) {
       CHECK(host_drm_device_)
           << "Mojo single-process mode requires a HostDrmDevice.";
-      host_drm_device_->BlockingStartDrmDevice();
+
+      // Wait here if host and gpu are one and the same thread.
+      if (host_thread_ == base::PlatformThread::CurrentRef()) {
+        // One-thread exection does not permit use of the sandbox.
+        AfterSandboxEntry();
+        host_drm_device_->BlockingStartDrmDevice();
+      }
     }
   }
 
+  // The DRM thread needs to be started late because we need to wait for the
+  // sandbox to start. This entry point in the Ozne API gives platforms
+  // flexibility in handing this requirement.
+  void AfterSandboxEntry() override {
+    CHECK(drm_thread_proxy_) << "AfterSandboxEntry before InitializeForGPU is "
+                                "invalid startup order.\n";
+    // Defer the actual startup of the DRM thread to here.
+    auto safe_binding_resquest_drainer = CreateSafeOnceCallback(base::BindOnce(
+        &OzonePlatformGbm::DrainBindingRequests, weak_factory_.GetWeakPtr()));
+
+    drm_thread_proxy_->StartDrmThread(std::move(safe_binding_resquest_drainer));
+  }
+
  private:
   bool using_mojo_;
   bool single_process_;
-  base::PlatformThreadRef host_thread_;
 
   // Objects in the GPU process.
   std::unique_ptr<DrmThreadProxy> drm_thread_proxy_;
@@ -293,6 +340,7 @@
   // running in single process mode.
   std::vector<ozone::mojom::DeviceCursorRequest> pending_cursor_requests_;
   std::vector<ozone::mojom::DrmDeviceRequest> pending_gpu_adapter_requests_;
+  bool drm_thread_started_;
 
   // gpu_platform_support_host_ is the IPC bridge to the GPU process while
   // host_drm_device_ is the mojo bridge to the Viz process. Only one can be in
@@ -304,9 +352,11 @@
   // To avoid a use after free, the following two members should be declared
   // before the two managers, so that they're deleted after them.
   std::unique_ptr<DrmGpuPlatformSupportHost> gpu_platform_support_host_;
-  std::unique_ptr<HostDrmDevice> host_drm_device_;
 
-  // Objects in the Browser process.
+  // Objects in the host process.
+  std::unique_ptr<DrmDeviceConnector> drm_device_connector_;
+  scoped_refptr<HostDrmDevice> host_drm_device_;
+  base::PlatformThreadRef host_thread_;
   std::unique_ptr<DeviceManager> device_manager_;
   std::unique_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_;
   std::unique_ptr<DrmWindowHostManager> window_manager_;
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 849e68d..274f5158 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -61,6 +61,7 @@
     "//ui/display/manager",
     "//ui/events",
     "//ui/events:dom_keycode_converter",
+    "//ui/events/ozone:events_ozone",
     "//ui/events/ozone:events_ozone_layout",
     "//ui/events/platform",
     "//ui/gfx",
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.cc b/ui/ozone/platform/wayland/wayland_keyboard.cc
index 570a346..a2b2329d 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.cc
+++ b/ui/ozone/platform/wayland/wayland_keyboard.cc
@@ -5,7 +5,6 @@
 #include "ui/ozone/platform/wayland/wayland_keyboard.h"
 
 #include <sys/mman.h>
-#include <wayland-client.h>
 
 #include "base/files/scoped_file.h"
 #include "ui/base/ui_features.h"
@@ -30,9 +29,14 @@
 
 }  // namespace
 
+// static
+const wl_callback_listener WaylandKeyboard::callback_listener_ = {
+    WaylandKeyboard::SyncCallback,
+};
+
 WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard,
                                  const EventDispatchCallback& callback)
-    : obj_(keyboard), callback_(callback) {
+    : obj_(keyboard), callback_(callback), auto_repeat_handler_(this) {
   static const wl_keyboard_listener listener = {
       &WaylandKeyboard::Keymap,    &WaylandKeyboard::Enter,
       &WaylandKeyboard::Leave,     &WaylandKeyboard::Key,
@@ -86,6 +90,12 @@
                             uint32_t serial,
                             wl_surface* surface) {
   WaylandWindow::FromSurface(surface)->set_keyboard_focus(false);
+
+  WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
+  DCHECK(keyboard);
+
+  // Upon window focus lose, reset the key repeat timers.
+  keyboard->auto_repeat_handler_.StopKeyRepeat();
 }
 
 void WaylandKeyboard::Key(void* data,
@@ -100,12 +110,15 @@
   keyboard->connection_->set_serial(serial);
 
   bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED;
+  int device_id = keyboard->obj_.id();
+
+  keyboard->auto_repeat_handler_.UpdateKeyRepeat(
+      key, down, false /*suppress_auto_repeat*/, device_id);
 
   // TODO(tonikitoo,msisov): Handler 'repeat' parameter below.
   keyboard->DispatchKey(
       key, down, false /*repeat*/,
-      base::TimeTicks() + base::TimeDelta::FromMilliseconds(time),
-      keyboard->obj_.id());
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(time), device_id);
 }
 
 void WaylandKeyboard::Modifiers(void* data,
@@ -126,8 +139,26 @@
                                  wl_keyboard* obj,
                                  int32_t rate,
                                  int32_t delay) {
-  // TODO(tonikitoo): Implement proper repeat handling.
-  NOTIMPLEMENTED();
+  WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
+  DCHECK(keyboard);
+
+  keyboard->auto_repeat_handler_.SetAutoRepeatRate(
+      base::TimeDelta::FromMilliseconds(delay),
+      base::TimeDelta::FromMilliseconds(rate));
+}
+
+void WaylandKeyboard::FlushInput(base::OnceClosure closure) {
+  if (sync_callback_)
+    return;
+
+  auto_repeat_closure_ = std::move(closure);
+
+  // wl_display_sync gives a chance for any key "up" events to arrive.
+  // With a well behaved wayland compositor this should ensure we never
+  // get spurious repeats.
+  sync_callback_.reset(wl_display_sync(connection_->display()));
+  wl_callback_add_listener(sync_callback_.get(), &callback_listener_, this);
+  wl_display_flush(connection_->display());
 }
 
 void WaylandKeyboard::DispatchKey(uint32_t key,
@@ -159,6 +190,17 @@
   callback_.Run(&event);
 }
 
+void WaylandKeyboard::SyncCallback(void* data,
+                                   struct wl_callback* cb,
+                                   uint32_t time) {
+  WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
+  DCHECK(keyboard);
+
+  std::move(keyboard->auto_repeat_closure_).Run();
+  DCHECK(keyboard->auto_repeat_closure_.is_null());
+  keyboard->sync_callback_.reset();
+}
+
 void WaylandKeyboard::UpdateModifier(int modifier_flag, bool down) {
   if (modifier_flag == EF_NONE)
     return;
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.h b/ui/ozone/platform/wayland/wayland_keyboard.h
index 70251f6d..18b535a6 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.h
+++ b/ui/ozone/platform/wayland/wayland_keyboard.h
@@ -5,15 +5,18 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_
 #define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_KEYBOARD_H_
 
+#include <wayland-client.h>
+
 #include "ui/events/event_modifiers.h"
 #include "ui/events/ozone/evdev/event_dispatch_callback.h"
+#include "ui/events/ozone/keyboard/event_auto_repeat_handler.h"
 #include "ui/ozone/platform/wayland/wayland_object.h"
 
 namespace ui {
 
 class WaylandConnection;
 
-class WaylandKeyboard {
+class WaylandKeyboard : public EventAutoRepeatHandler::Delegate {
  public:
   WaylandKeyboard(wl_keyboard* keyboard, const EventDispatchCallback& callback);
   virtual ~WaylandKeyboard();
@@ -58,18 +61,28 @@
                          int32_t rate,
                          int32_t delay);
 
+  static void SyncCallback(void* data, struct wl_callback* cb, uint32_t time);
+
   void UpdateModifier(int modifier_flag, bool down);
 
+  // EventAutoRepeatHandler::Delegate
+  void FlushInput(base::OnceClosure closure) override;
   void DispatchKey(unsigned int key,
                    bool down,
                    bool repeat,
                    base::TimeTicks timestamp,
-                   int device_id);
+                   int device_id) override;
 
   WaylandConnection* connection_ = nullptr;
   wl::Object<wl_keyboard> obj_;
   EventDispatchCallback callback_;
   EventModifiers event_modifiers_;
+
+  // Key repeat handler.
+  static const wl_callback_listener callback_listener_;
+  EventAutoRepeatHandler auto_repeat_handler_;
+  base::OnceClosure auto_repeat_closure_;
+  wl::Object<wl_callback> sync_callback_;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc b/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
index f5a7d80..7ce077a 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_keyboard_unittest.cc
@@ -5,13 +5,13 @@
 #include <linux/input.h>
 #include <wayland-server.h>
 
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/timer/timer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event.h"
 #include "ui/ozone/platform/wayland/fake_server.h"
 #include "ui/ozone/platform/wayland/wayland_test.h"
-#include "ui/ozone/platform/wayland/wayland_window.h"
-#include "ui/ozone/test/mock_platform_window_delegate.h"
 
 #if BUILDFLAG(USE_XKBCOMMON)
 #include "base/memory/free_deleter.h"
@@ -326,6 +326,138 @@
 }
 #endif
 
+TEST_P(WaylandKeyboardTest, EventAutoRepeat) {
+  struct wl_array empty;
+  wl_array_init(&empty);
+
+  wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+  wl_array_release(&empty);
+
+  // Auto repeat info in ms.
+  uint32_t rate = 75;
+  uint32_t delay = 25;
+
+  wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay);
+
+  wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */,
+                       WL_KEYBOARD_KEY_STATE_PRESSED);
+
+  std::unique_ptr<Event> event;
+  EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+
+  Sync();
+
+  {
+    scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner =
+        new base::TestMockTimeTaskRunner();
+    base::TestMockTimeTaskRunner::ScopedContext scoped_context(
+        mock_time_task_runner.get());
+
+    // Keep it pressed for doubled the rate time, to ensure events get fired.
+    mock_time_task_runner->FastForwardBy(
+        base::TimeDelta::FromMilliseconds(rate * 2));
+  }
+
+  Sync();
+
+  std::unique_ptr<Event> event2;
+  EXPECT_CALL(delegate, DispatchEvent(_)).WillRepeatedly(CloneEvent(&event2));
+
+  wl_keyboard_send_key(keyboard->resource(), 3, 0, 30 /* a */,
+                       WL_KEYBOARD_KEY_STATE_RELEASED);
+  Sync();
+}
+
+TEST_P(WaylandKeyboardTest, NoEventAutoRepeatOnLeave) {
+  struct wl_array empty;
+  wl_array_init(&empty);
+
+  wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+  wl_array_release(&empty);
+
+  // Auto repeat info in ms.
+  uint32_t rate = 75;
+  uint32_t delay = 25;
+
+  wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay);
+
+  wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */,
+                       WL_KEYBOARD_KEY_STATE_PRESSED);
+
+  std::unique_ptr<Event> event;
+  EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+
+  Sync();
+
+  {
+    scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner =
+        new base::TestMockTimeTaskRunner();
+    base::TestMockTimeTaskRunner::ScopedContext scoped_context(
+        mock_time_task_runner.get());
+
+    // Keep it pressed for doubled the rate time, to ensure events get fired.
+    mock_time_task_runner->FastForwardBy(
+        base::TimeDelta::FromMilliseconds(rate * 2));
+  }
+
+  wl_keyboard_send_leave(keyboard->resource(), 3, surface->resource());
+
+  Sync();
+
+  EXPECT_CALL(delegate, DispatchEvent(_)).Times(0);
+
+  wl_keyboard_send_key(keyboard->resource(), 4, 0, 30 /* a */,
+                       WL_KEYBOARD_KEY_STATE_RELEASED);
+  Sync();
+}
+
+TEST_P(WaylandKeyboardTest, NoEventAutoRepeatBeforeTimeout) {
+  struct wl_array empty;
+  wl_array_init(&empty);
+
+  wl_keyboard_send_enter(keyboard->resource(), 1, surface->resource(), &empty);
+  wl_array_release(&empty);
+
+  // Auto repeat info in ms.
+  uint32_t rate = 500;
+  uint32_t delay = 50;
+
+  wl_keyboard_send_repeat_info(keyboard->resource(), rate, delay);
+
+  wl_keyboard_send_key(keyboard->resource(), 2, 0, 30 /* a */,
+                       WL_KEYBOARD_KEY_STATE_PRESSED);
+
+  std::unique_ptr<Event> event;
+  EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event));
+
+  Sync();
+
+  {
+    scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner =
+        new base::TestMockTimeTaskRunner();
+    base::TestMockTimeTaskRunner::ScopedContext scoped_context(
+        mock_time_task_runner.get());
+
+    // Keep it pressed for a fifth of the rate time, and no auto repeat events
+    // should get dispatched.
+    mock_time_task_runner->FastForwardBy(
+        base::TimeDelta::FromMilliseconds(rate / 5));
+  }
+
+  wl_keyboard_send_key(keyboard->resource(), 4, 0, 30 /* a */,
+                       WL_KEYBOARD_KEY_STATE_RELEASED);
+
+  std::unique_ptr<Event> event2;
+  EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event2));
+
+  Sync();
+  ASSERT_TRUE(event2);
+  ASSERT_TRUE(event2->IsKeyEvent());
+
+  auto* key_event2 = event2->AsKeyEvent();
+  EXPECT_EQ(ET_KEY_RELEASED, key_event2->type());
+}
+
 INSTANTIATE_TEST_CASE_P(XdgVersionV5Test,
                         WaylandKeyboardTest,
                         ::testing::Values(kXdgShellV5));
diff --git a/ui/ozone/platform/wayland/wayland_object.cc b/ui/ozone/platform/wayland/wayland_object.cc
index f800a9c..5196eb0 100644
--- a/ui/ozone/platform/wayland/wayland_object.cc
+++ b/ui/ozone/platform/wayland/wayland_object.cc
@@ -37,6 +37,10 @@
 const wl_interface* ObjectTraits<wl_buffer>::interface = &wl_buffer_interface;
 void (*ObjectTraits<wl_buffer>::deleter)(wl_buffer*) = &wl_buffer_destroy;
 
+const wl_interface* ObjectTraits<wl_callback>::interface =
+    &wl_callback_interface;
+void (*ObjectTraits<wl_callback>::deleter)(wl_callback*) = &wl_callback_destroy;
+
 const wl_interface* ObjectTraits<wl_compositor>::interface =
     &wl_compositor_interface;
 void (*ObjectTraits<wl_compositor>::deleter)(wl_compositor*) =
diff --git a/ui/ozone/platform/wayland/wayland_object.h b/ui/ozone/platform/wayland/wayland_object.h
index d6512fb6..0ca7568 100644
--- a/ui/ozone/platform/wayland/wayland_object.h
+++ b/ui/ozone/platform/wayland/wayland_object.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 struct wl_buffer;
+struct wl_callback;
 struct wl_compositor;
 struct wl_keyboard;
 struct wl_output;
@@ -37,6 +38,12 @@
 };
 
 template <>
+struct ObjectTraits<wl_callback> {
+  static const wl_interface* interface;
+  static void (*deleter)(wl_callback*);
+};
+
+template <>
 struct ObjectTraits<wl_compositor> {
   static const wl_interface* interface;
   static void (*deleter)(wl_compositor*);
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc
index 88881bf..f11b82b1 100644
--- a/ui/ozone/platform/wayland/wayland_window.cc
+++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -48,7 +48,7 @@
       connection_(connection),
       xdg_shell_objects_factory_(new XDGShellObjectFactory()),
       bounds_(bounds),
-      state_(ui::PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN) {}
+      state_(PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN) {}
 
 WaylandWindow::~WaylandWindow() {
   if (xdg_surface_) {
@@ -143,32 +143,47 @@
 
 void WaylandWindow::ToggleFullscreen() {
   DCHECK(xdg_surface_);
-  DCHECK(!IsMinimized());
 
   // TODO(msisov, tonikitoo): add multiscreen support. As the documentation says
   // if xdg_surface_set_fullscreen() is not provided with wl_output, it's up to
   // the compositor to choose which display will be used to map this surface.
-  if (!IsFullscreen())
+  if (!IsFullscreen()) {
+    // Client might have requested a fullscreen state while the window was in
+    // a maximized state. Thus, |restored_bounds_| can contain the bounds of a
+    // "normal" state before the window was maximized. We don't override them
+    // unless they are empty, because |bounds_| can contain bounds of a
+    // maximized window instead.
+    if (restored_bounds_.IsEmpty())
+      restored_bounds_ = bounds_;
     xdg_surface_->SetFullscreen();
-  else
+  } else {
     xdg_surface_->UnSetFullscreen();
+  }
+
   connection_->ScheduleFlush();
 }
 
 void WaylandWindow::Maximize() {
   DCHECK(xdg_surface_);
-  DCHECK(!IsMaximized());
 
   if (IsFullscreen())
     ToggleFullscreen();
 
+  // Keeps track of the previous bounds, which are used to restore a window
+  // after unmaximize call. We don't override |restored_bounds_| if they have
+  // already had value, which means the previous state has been a fullscreen
+  // state. That is, the bounds can be stored during a change from a normal
+  // state to a maximize state, and then preserved to be the same, when changing
+  // from maximized to fullscreen and back to a maximized state.
+  if (restored_bounds_.IsEmpty())
+    restored_bounds_ = bounds_;
+
   xdg_surface_->SetMaximized();
   connection_->ScheduleFlush();
 }
 
 void WaylandWindow::Minimize() {
   DCHECK(xdg_surface_);
-  DCHECK(!IsMinimized());
 
   DCHECK(xdg_surface_);
   xdg_surface_->SetMinimized();
@@ -177,7 +192,7 @@
   // Wayland doesn't say if a window is minimized. Handle this case manually
   // here. We can track if the window was unminimized once wayland sends the
   // window is activated, and the previous state was minimized.
-  state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED;
+  state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED;
 }
 
 void WaylandWindow::Restore() {
@@ -240,34 +255,25 @@
                                            bool is_maximized,
                                            bool is_fullscreen,
                                            bool is_activated) {
-  // Change the window state only if the window is activated, because it's the
-  // only way to know if the window is not minimized.
-  if (is_activated) {
-    bool was_minimized = IsMinimized();
+  // Propagate the window state information to the client.
+  PlatformWindowState old_state = state_;
+  if (IsMinimized() && !is_activated)
+    state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED;
+  else if (is_fullscreen)
+    state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN;
+  else if (is_maximized)
+    state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED;
+  else
+    state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL;
 
-    state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL;
-    if (is_maximized && !is_fullscreen)
-      state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED;
-    else if (is_fullscreen)
-      state_ = ui::PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN;
-
-    // Do not flood the WindowServer unless the previous state was minimized.
-    if (was_minimized)
-      delegate_->OnWindowStateChanged(state_);
-  }
-
-  // Width or height set 0 means that we should decide on width and height by
-  // ourselves, but we don't want to set to anything else. Use previous size.
-  if (width == 0 || height == 0) {
-    width = GetBounds().width();
-    height = GetBounds().height();
-  }
+  if (old_state != state_)
+    delegate_->OnWindowStateChanged(state_);
 
   // Rather than call SetBounds here for every configure event, just save the
   // most recent bounds, and have WaylandConnection call ApplyPendingBounds
   // when it has finished processing events. We may get many configure events
   // in a row during an interactive resize, and only the last one matters.
-  pending_bounds_ = gfx::Rect(0, 0, width, height);
+  SetPendingBounds(width, height);
 }
 
 void WaylandWindow::OnCloseRequest() {
@@ -275,15 +281,36 @@
 }
 
 bool WaylandWindow::IsMinimized() const {
-  return state_ == ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED;
+  return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_MINIMIZED;
 }
 
 bool WaylandWindow::IsMaximized() const {
-  return state_ == ui::PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED;
+  return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_MAXIMIZED;
 }
 
 bool WaylandWindow::IsFullscreen() const {
-  return state_ == ui::PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN;
+  return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN;
+}
+
+void WaylandWindow::SetPendingBounds(int32_t width, int32_t height) {
+  // Width or height set to 0 means that we should decide on width and height by
+  // ourselves, but we don't want to set them to anything else. Use restored
+  // bounds size or the current bounds.
+  //
+  // Note: if the browser was started with --start-fullscreen and a user exits
+  // the fullscreen mode, wayland may set the width and height to be 1. Instead,
+  // explicitly set the bounds to the current desired ones or the previous
+  // bounds.
+  if (width <= 1 || height <= 1) {
+    pending_bounds_.set_size(restored_bounds_.IsEmpty()
+                                 ? GetBounds().size()
+                                 : restored_bounds_.size());
+  } else {
+    pending_bounds_ = gfx::Rect(0, 0, width, height);
+  }
+
+  if (!IsFullscreen() && !IsMaximized())
+    restored_bounds_ = gfx::Rect();
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h
index a448591..4de9d69 100644
--- a/ui/ozone/platform/wayland/wayland_window.h
+++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -83,6 +83,8 @@
   bool IsMaximized() const;
   bool IsFullscreen() const;
 
+  void SetPendingBounds(int32_t width, int32_t height);
+
   // Creates a surface window, which is visible as a main window.
   void CreateXdgSurface();
 
@@ -103,6 +105,8 @@
 
   gfx::Rect bounds_;
   gfx::Rect pending_bounds_;
+  // The bounds of our window before we were maximized or fullscreen.
+  gfx::Rect restored_bounds_;
   bool has_pointer_focus_ = false;
   bool has_keyboard_focus_ = false;
 
diff --git a/ui/ozone/platform/wayland/wayland_window_unittest.cc b/ui/ozone/platform/wayland/wayland_window_unittest.cc
index a36d769..2c2e2679 100644
--- a/ui/ozone/platform/wayland/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_window_unittest.cc
@@ -94,24 +94,47 @@
 }
 
 TEST_P(WaylandWindowTest, MaximizeAndRestore) {
-  uint32_t serial = 12;
   wl_array states;
   InitializeWlArrayWithActivatedState(&states);
 
+  EXPECT_CALL(delegate,
+              OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_MAXIMIZED)));
   SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
 
   EXPECT_CALL(*GetXdgSurface(), SetMaximized());
-  EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
   window->Maximize();
-  SendConfigureEvent(0, 0, serial, &states);
+  SendConfigureEvent(0, 0, 1, &states);
   Sync();
 
+  EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
+  EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
   window->Restore();
+  // Reinitialize wl_array, which removes previous old states.
+  InitializeWlArrayWithActivatedState(&states);
+  SendConfigureEvent(0, 0, 2, &states);
+  Sync();
 }
 
 TEST_P(WaylandWindowTest, Minimize) {
+  wl_array states;
+  wl_array_init(&states);
+
+  // Initialize to normal first.
+  EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
+  SendConfigureEvent(0, 0, 1, &states);
+  Sync();
+
   EXPECT_CALL(*GetXdgSurface(), SetMinimized());
+  // The state of the window must retain minimized, which means we are not
+  // notified about the state, because 1) minimized state was set manually
+  // in WaylandWindow, and it has been confirmed in a back call from the server,
+  // which resulted in the same state as before.
+  EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0);
   window->Minimize();
+  // Reinitialize wl_array, which removes previous old states.
+  wl_array_init(&states);
+  SendConfigureEvent(0, 0, 2, &states);
+  Sync();
 }
 
 TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
@@ -121,34 +144,173 @@
   SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
 
   EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
-  EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
+  EXPECT_CALL(delegate,
+              OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_FULLSCREEN)));
   window->ToggleFullscreen();
   SendConfigureEvent(0, 0, 1, &states);
   Sync();
 
+  EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
+  EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
   window->Restore();
+  // Reinitialize wl_array, which removes previous old states.
+  InitializeWlArrayWithActivatedState(&states);
+  SendConfigureEvent(0, 0, 2, &states);
+  Sync();
 }
 
 TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
   wl_array states;
   InitializeWlArrayWithActivatedState(&states);
 
-  EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
-  EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
   EXPECT_CALL(*GetXdgSurface(), SetMaximized());
-  EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
-
+  EXPECT_CALL(delegate,
+              OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_MAXIMIZED)));
   window->Maximize();
   SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
   SendConfigureEvent(0, 0, 2, &states);
   Sync();
 
+  EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
+  EXPECT_CALL(delegate,
+              OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_FULLSCREEN)));
   window->ToggleFullscreen();
   SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
   SendConfigureEvent(0, 0, 3, &states);
   Sync();
 
+  EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
+  EXPECT_CALL(*GetXdgSurface(), UnsetMaximized());
+  EXPECT_CALL(delegate, OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_NORMAL)));
   window->Restore();
+  // Reinitialize wl_array, which removes previous old states.
+  InitializeWlArrayWithActivatedState(&states);
+  SendConfigureEvent(0, 0, 4, &states);
+  Sync();
+}
+
+TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
+  const gfx::Rect current_bounds = window->GetBounds();
+
+  wl_array states;
+  InitializeWlArrayWithActivatedState(&states);
+
+  const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds)));
+  window->Maximize();
+  SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
+  SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1,
+                     &states);
+  Sync();
+
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds)));
+  // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
+  // Thus, using a toplevel object in XdgV6 case is not right thing. Use a
+  // surface here instead.
+  EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(),
+                                              current_bounds.height()));
+  window->Restore();
+  // Reinitialize wl_array, which removes previous old states.
+  InitializeWlArrayWithActivatedState(&states);
+  SendConfigureEvent(0, 0, 2, &states);
+  Sync();
+}
+
+TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
+  const gfx::Rect current_bounds = window->GetBounds();
+
+  wl_array states;
+  InitializeWlArrayWithActivatedState(&states);
+
+  const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720);
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(fullscreen_bounds)));
+  window->ToggleFullscreen();
+  SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
+  SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 1,
+                     &states);
+  Sync();
+
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds)));
+  // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
+  // Thus, using a toplevel object in XdgV6 case is not right thing. Use a
+  // surface here instead.
+  EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(),
+                                              current_bounds.height()));
+  window->Restore();
+  // Reinitialize wl_array, which removes previous old states.
+  InitializeWlArrayWithActivatedState(&states);
+  SendConfigureEvent(0, 0, 2, &states);
+  Sync();
+}
+
+TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
+  const gfx::Rect current_bounds = window->GetBounds();
+
+  wl_array states;
+  InitializeWlArrayWithActivatedState(&states);
+
+  const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds)));
+  window->Maximize();
+  SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
+  SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 1,
+                     &states);
+  Sync();
+
+  const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720);
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(fullscreen_bounds)));
+  window->ToggleFullscreen();
+  SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states);
+  SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 2,
+                     &states);
+  Sync();
+
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(maximized_bounds)));
+  window->Maximize();
+  // Reinitialize wl_array, which removes previous old states.
+  InitializeWlArrayWithActivatedState(&states);
+  SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states);
+  SendConfigureEvent(maximized_bounds.width(), maximized_bounds.height(), 3,
+                     &states);
+  Sync();
+
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(current_bounds)));
+  // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
+  // Thus, using a toplevel object in XdgV6 case is not right thing. Use a
+  // surface here instead.
+  EXPECT_CALL(*xdg_surface, SetWindowGeometry(0, 0, current_bounds.width(),
+                                              current_bounds.height()));
+  window->Restore();
+  // Reinitialize wl_array, which removes previous old states.
+  InitializeWlArrayWithActivatedState(&states);
+  SendConfigureEvent(0, 0, 4, &states);
+  Sync();
+}
+
+TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
+  const gfx::Rect initial_bounds = window->GetBounds();
+
+  const gfx::Rect new_bounds = gfx::Rect(0, 0, initial_bounds.width() + 10,
+                                         initial_bounds.height() + 10);
+  EXPECT_CALL(delegate, OnBoundsChanged(Eq(new_bounds)));
+  window->SetBounds(new_bounds);
+
+  wl_array states;
+  InitializeWlArrayWithActivatedState(&states);
+
+  // First case is when Wayland sends a configure event with 0,0 height and
+  // widht.
+  EXPECT_CALL(*xdg_surface,
+              SetWindowGeometry(0, 0, new_bounds.width(), new_bounds.height()))
+      .Times(2);
+  SendConfigureEvent(0, 0, 2, &states);
+  Sync();
+
+  // Second case is when Wayland sends a configure event with 1, 1 height and
+  // width. It looks more like a bug in Gnome Shell with Wayland as long as the
+  // documentation says it must be set to 0, 0, when wayland requests bounds.
+  SendConfigureEvent(0, 0, 3, &states);
+  Sync();
 }
 
 TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) {
diff --git a/ui/ozone/public/interfaces/DEPS b/ui/ozone/public/DEPS
similarity index 100%
rename from ui/ozone/public/interfaces/DEPS
rename to ui/ozone/public/DEPS
diff --git a/ui/ozone/public/gpu_platform_support_host.cc b/ui/ozone/public/gpu_platform_support_host.cc
index 98a23b1..586186c 100644
--- a/ui/ozone/public/gpu_platform_support_host.cc
+++ b/ui/ozone/public/gpu_platform_support_host.cc
@@ -23,6 +23,10 @@
 
   void OnChannelDestroyed(int host_id) override {}
   void OnMessageReceived(const IPC::Message&) override {}
+  void OnGpuServiceLaunched(
+      scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+      GpuHostBindInterfaceCallback binder) override {}
 };
 
 }  // namespace
diff --git a/ui/ozone/public/gpu_platform_support_host.h b/ui/ozone/public/gpu_platform_support_host.h
index 50db642..f1120e74 100644
--- a/ui/ozone/public/gpu_platform_support_host.h
+++ b/ui/ozone/public/gpu_platform_support_host.h
@@ -5,10 +5,13 @@
 #ifndef UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
 #define UI_OZONE_PUBLIC_GPU_PLATFORM_SUPPORT_HOST_H_
 
+#include <string>
+
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "ui/ozone/ozone_base_export.h"
 
 namespace ui {
@@ -24,6 +27,10 @@
 // to support additional messages needed by specific platforms.
 class OZONE_BASE_EXPORT GpuPlatformSupportHost {
  public:
+  using GpuHostBindInterfaceCallback =
+      base::RepeatingCallback<void(const std::string&,
+                                   mojo::ScopedMessagePipeHandle)>;
+
   GpuPlatformSupportHost();
   virtual ~GpuPlatformSupportHost();
 
@@ -42,6 +49,13 @@
   // Called to handle an IPC message. Note that this can be called from any
   // thread.
   virtual void OnMessageReceived(const IPC::Message& message) = 0;
+
+  // Called when the GPU service is launched.
+  // Called from the browser IO thread.
+  virtual void OnGpuServiceLaunched(
+      scoped_refptr<base::SingleThreadTaskRunner> host_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+      GpuHostBindInterfaceCallback binder) = 0;
 };
 
 // create a stub implementation.
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc
index 8b41780..58c114b 100644
--- a/ui/ozone/public/ozone_platform.cc
+++ b/ui/ozone/public/ozone_platform.cc
@@ -125,4 +125,6 @@
     service_manager::BinderRegistryWithArgs<
         const service_manager::BindSourceInfo&>* registry) {}
 
+void OzonePlatform::AfterSandboxEntry() {}
+
 }  // namespace ui
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
index b6335ea..f715a6af 100644
--- a/ui/ozone/public/ozone_platform.h
+++ b/ui/ozone/public/ozone_platform.h
@@ -13,6 +13,7 @@
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "ui/events/system_input_injector.h"
 #include "ui/ozone/ozone_export.h"
+//#include "ui/ozone/public/interfaces/drm_device.mojom.h"
 
 namespace display {
 class NativeDisplayDelegate;
@@ -64,14 +65,23 @@
   // retain a reference to this structure.
   struct InitParams {
     // Ozone may retain this pointer for later use. An Ozone platform embedder
-    // must set this parameter in order for the Ozone platform implementation to
-    // be able to use Mojo.
+    // may set this value if operating in the idiomatic mojo fashion with a
+    // service manager. Mojo transport does not require a service manager but in
+    // that case ozone will not be able to connect to the DRM and cursor
+    // services. Instead the host must invoke |OnGpuServiceLaunched| as
+    // described in ui/ozone/public/gpu_platform_support_host.h to inform the
+    // ozone host that a process containing these services is running.
     service_manager::Connector* connector = nullptr;
 
     // Setting this to true indicates that the platform implementation should
     // operate as a single process for platforms (i.e. drm) that are usually
-    // split between a main and gpu specific portion.
+    // split between a host and viz specific portion.
     bool single_process = false;
+
+    //  Setting this to true indicates that the platform implementation should
+    //  use mojo. Setting this to true requires calling |AddInterfaces|
+    //  afterwards in the Viz process and providing a connector as part
+    bool using_mojo = false;
   };
 
   // Ensures the OzonePlatform instance without doing any initialization.
@@ -131,11 +141,23 @@
   // service_manager::BinderRegistry* pointer to export all Mojo interfaces
   // defined within Ozone.
   //
+  // Requests arriving before they can be immediately handled will be queued and
+  // executed later.
+  //
   // A default do-nothing implementation is provided to permit platform
   // implementations to opt out of implementing any Mojo interfaces.
   virtual void AddInterfaces(service_manager::BinderRegistryWithArgs<
                              const service_manager::BindSourceInfo&>* registry);
 
+  // The GPU-specific portion of Ozone would typically run in a sandboxed
+  // process for additional security. Some startup might need to wait until
+  // after the sandbox has been configured. The embedder should use this method
+  // to specify that the sandbox is configured and that GPU-side setup should
+  // complete. A default do-nothing implementation is provided to permit
+  // platform implementations to ignore sandboxing and any associated launch
+  // ordering issues.
+  virtual void AfterSandboxEntry();
+
  private:
   virtual void InitializeUI(const InitParams& params) = 0;
   virtual void InitializeGPU(const InitParams& params) = 0;
diff --git a/ui/ozone/public/ozone_switches.cc b/ui/ozone/public/ozone_switches.cc
index f7a772a5..4669cfa 100644
--- a/ui/ozone/public/ozone_switches.cc
+++ b/ui/ozone/public/ozone_switches.cc
@@ -15,4 +15,9 @@
 // Try to enable drm atomic. This works only with drm platform.
 const char kEnableDrmAtomic[] = "enable-drm-atomic";
 
+// Use mojo communication in the drm platform instead of paramtraits. Remove
+// this switch (and associated code) when the drm platform always uses mojo
+// communication.
+const char kEnableDrmMojo[] = "enable-drm-mojo";
+
 }  // namespace switches
diff --git a/ui/ozone/public/ozone_switches.h b/ui/ozone/public/ozone_switches.h
index e53912bf..b8360e80 100644
--- a/ui/ozone/public/ozone_switches.h
+++ b/ui/ozone/public/ozone_switches.h
@@ -16,6 +16,8 @@
 
 OZONE_BASE_EXPORT extern const char kEnableDrmAtomic[];
 
+OZONE_BASE_EXPORT extern const char kEnableDrmMojo[];
+
 }  // namespace switches
 
 #endif  // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
diff --git a/ui/views/accessibility/native_view_accessibility_win_unittest.cc b/ui/views/accessibility/native_view_accessibility_win_unittest.cc
index 9a4d564..4856452 100644
--- a/ui/views/accessibility/native_view_accessibility_win_unittest.cc
+++ b/ui/views/accessibility/native_view_accessibility_win_unittest.cc
@@ -282,7 +282,7 @@
 
 TEST_F(NativeViewAccessibilityWinTest, WindowHasRoleApplication) {
   // We expect that our internal window object does not expose
-  // ROLE_SYSTEM_WINDOW, but ROLE_SYSTEM_APPLICATION instead.
+  // ROLE_SYSTEM_WINDOW, but ROLE_SYSTEM_PANE instead.
   Widget widget;
   Widget::InitParams init_params =
       CreateParams(Widget::InitParams::TYPE_WINDOW);
@@ -294,8 +294,8 @@
   ScopedVariant childid_self(CHILDID_SELF);
   ScopedVariant role;
   EXPECT_EQ(S_OK, accessible->get_accRole(childid_self, role.Receive()));
-  EXPECT_EQ(role.type(), VT_I4);
-  EXPECT_EQ(V_I4(role.ptr()), ROLE_SYSTEM_APPLICATION);
+  EXPECT_EQ(VT_I4, role.type());
+  EXPECT_EQ(ROLE_SYSTEM_PANE, V_I4(role.ptr()));
 }
 }  // namespace test
 }  // namespace views