diff --git a/BUILD.gn b/BUILD.gn
index 5fdb6c5f..7265673 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -952,7 +952,6 @@
     if (is_win) {
       data += [
         "//third_party/apache-win32/",
-        "//third_party/cygwin/",
         "//third_party/perl/",
       ]
     }
@@ -980,6 +979,41 @@
       "//mojo/public/js:new_bindings",
     ]
   }
+
+  group("webkit_python_tests") {
+    data = [
+      "//build/android/",
+      "//components/crash/content/tools/generate_breakpad_symbols.py",
+      "//testing/scripts/common.py",
+      "//testing/scripts/run_isolated_script_test.py",
+      "//testing/test_env.py",
+      "//testing/xvfb.py",
+      "//third_party/WebKit/LayoutTests/ASANExpectations",
+      "//third_party/WebKit/LayoutTests/LeakExpectations",
+      "//third_party/WebKit/LayoutTests/MSANExpectations",
+      "//third_party/WebKit/LayoutTests/NeverFixTests",
+      "//third_party/WebKit/LayoutTests/StaleTestExpectations",
+      "//third_party/WebKit/LayoutTests/SlowTests",
+      "//third_party/WebKit/LayoutTests/TestExpectations",
+      "//third_party/WebKit/LayoutTests/VirtualTestSuites",
+      "//third_party/WebKit/Source/bindings/scripts/",
+      "//third_party/WebKit/Tools/Scripts/",
+      "//third_party/blink/tools/",
+      "//third_party/catapult/common/py_utils/",
+      "//third_party/catapult/devil/",
+      "//third_party/catapult/dependency_manager/",
+      "//third_party/catapult/third_party/zipfile/",
+      "//third_party/depot_tools/pylint.py",
+      "//third_party/depot_tools/pylintrc",
+      "//third_party/depot_tools/third_party/logilab/",
+      "//third_party/depot_tools/third_party/pylint/",
+      "//third_party/depot_tools/third_party/pylint.py",
+      "//third_party/ply/",
+      "//third_party/pymock/",
+      "//third_party/typ/",
+      "//tools/idl_parser/",
+    ]
+  }
 }
 
 group("chromium_builder_perf") {
diff --git a/DEPS b/DEPS
index 43357f9..005b6e6 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd84d90b466ab60c989a33f0ef1dde10c7b53f1dc',
+  'skia_revision': '38702ab43b2857f2fe06afb8dad1339d76a2fd84',
   # 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': '051dd630426a6540b1c4a446cacdd99c8371cfc5',
+  'v8_revision': '7245c9da4622180b78ee142a7e4f7fcc9151fb04',
   # 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.
@@ -52,7 +52,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': '72b4e1e5bbbb2b6749bf49bdba287a85abade649',
+  'angle_revision': 'ad6e2b6a681062042b0cd3acf52f2318b2d3bbe8',
   # 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.
@@ -64,7 +64,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': '47a90b894ecca2d3547226169602d7f8729d564f',
+  'pdfium_revision': '555b31faa192c7a85c84979bea28d4914e93c784',
   # 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.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'd4179a057d4b2410cbe1d0eef9773558faec6a7c',
+  'catapult_revision': 'c9667ecd29cbb003b7fbdcd6f2da0f02bf0e7257',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -124,7 +124,7 @@
 
 deps = {
   'src/breakpad/src':
-    Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + 'e6bc67c33952f25a1d81be49ad9eb38aca9934a7',
+    Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + '252d20c849115ccee2611bfbdcded21dbefacb2a',
 
   'src/buildtools':
     Var('chromium_git') + '/chromium/buildtools.git' + '@' +  Var('buildtools_revision'),
@@ -241,7 +241,7 @@
     Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '59d92ff1288817c52b13f54871ea42619231cf7a', # commit position 19592
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '3fa5b7ba0a640ec6171536e98cbb290c34053959', # commit position 19716
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -318,12 +318,6 @@
 
 deps_os = {
   'win': {
-    'src/third_party/cygwin':
-      Var('chromium_git') + '/chromium/deps/cygwin.git' + '@' + 'c89e446b273697fadf3a10ff1007a97c0b7de6df',
-
-    'src/third_party/psyco_win32':
-      Var('chromium_git') + '/chromium/deps/psyco_win32.git' + '@' + 'f5af9f6910ee5a8075bbaeed0591469f1661d868',
-
     'src/third_party/bison':
       Var('chromium_git') + '/chromium/deps/bison.git' + '@' + '083c9a45e4affdd5464ee2b224c2df649c6e26c3',
 
@@ -410,7 +404,7 @@
 
     # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
     'src/third_party/chromite':
-      Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f542336f1ad33cbf13fe2fdecd90a7908d9e46e1',
+      Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '59ba2f846e9197a1e0912a6097d5efd1010d214e',
 
     # Dependency of chromite.git and skia.
     'src/third_party/pyelftools':
@@ -468,7 +462,7 @@
       Var('chromium_git') + '/external/android_protobuf.git' + '@' + '7fca48d8ce97f7ba3ab8eea5c472f1ad3711762f',
 
     'src/third_party/android_tools':
-      Var('chromium_git') + '/android_tools.git' + '@' + 'e9d4018e149d50172ed462a7c21137aa915940ec',
+      Var('chromium_git') + '/android_tools.git' + '@' + 'aadb2fed04af8606545b0afe4e3060bc1a15fad7',
 
     'src/third_party/apache-portable-runtime/src':
       Var('chromium_git') + '/external/apache-portable-runtime.git' + '@' + 'c76a8c4277e09a82eaa229e35246edea1ee0a6a1',
@@ -928,6 +922,7 @@
                 'src/third_party/depot_tools/download_from_google_storage.py',
                 '--no_resume',
                 '--no_auth',
+                '--num_threads=4',
                 '--bucket', 'chromium-binary-patching',
                 '-d', 'src/chrome/installer/zucchini/testdata',
     ],
diff --git a/WATCHLISTS b/WATCHLISTS
index 9a59c48..a77f384 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -357,11 +357,6 @@
     'blink_htmlparser': {
       'filepath': 'third_party/WebKit/Source/core/html/parser/'
     },
-    'blink_image_capture': {
-      'filepath': 'third_party/WebKit/Source/modules/imagecapture' \
-                  '|third_party/WebKit/LayoutTests/fast/imagecapture/' \
-                  '|third_party/WebKit/LayoutTests/imagecapture/'
-    },
     'blink_indexed_db': {
       'filepath': 'third_party/WebKit/Source/modules/indexeddb/' \
                   '|third_party/WebKit/Source/web/.*IDB' \
@@ -1343,7 +1338,6 @@
     },
     'scheduler': {
       'filepath': 'cc/scheduler'\
-                  '|components/scheduler'\
                   '|content/renderer/scheduler'
     },
     'screen_orientation': {
@@ -1759,8 +1753,7 @@
                       'nhiroki@chromium.org',
                       'tzik@chromium.org'],
     'blink_frames': ['blink-reviews-frames@chromium.org'],
-    'blink_geolocation': ['mcasas+geolocation@chromium.org',
-                          'mlamouri+watch-blink@chromium.org',
+    'blink_geolocation': ['mlamouri+watch-blink@chromium.org',
                           'timvolodine@chromium.org'],
     'blink_heap': ['ager@chromium.org',
                    'haraken@chromium.org',
@@ -1770,7 +1763,6 @@
                    'dglazkov+blink@chromium.org'],
     'blink_htmlparser': ['kinuko+watch@chromium.org',
                          'loading-reviews+parser@chromium.org'],
-    'blink_image_capture': ['mcasas+imagecapture@chromium.org'],
     'blink_indexed_db': ['cmumford@chromium.org',
                          'jsbell+idb@chromium.org'],
     'blink_input': ['dtapuska+blinkwatch@chromium.org',
@@ -2022,8 +2014,7 @@
                        'mikhail.pozdnyakov@intel.com',
                        'timvolodine@chromium.org',
                        'wanming.lin@intel.com'],
-    'geolocation': ['mcasas+geolocation@chromium.org',
-                    'mlamouri+watch-geolocation@chromium.org'],
+    'geolocation': ['mlamouri+watch-geolocation@chromium.org'],
     'gfx_geometry': ['cc-bugs@chromium.org'],
     'gfx_image': ['rsesek+watch@chromium.org'],
     'gn': ['agrieve+watch@chromium.org',
@@ -2086,8 +2077,7 @@
     'md_settings': ['michaelpg+watch-md-settings@chromium.org',
                     'stevenjb+watch-md-settings@chromium.org'],
     'media': ['feature-media-reviews@chromium.org'],
-    'media_capture_from_element': ['emircan+watch+capturefromdom@chromium.org',
-                                   'mcasas+capturefromelement@chromium.org'],
+    'media_capture_from_element': ['emircan+watch+capturefromdom@chromium.org'],
     'media_galleries': ['thestig@chromium.org',
                         'tommycli@chromium.org'],
     'media_mojo': ['alokp+watch@chromium.org'],
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 6267dbe..f574c7f 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -737,6 +737,7 @@
     "//net:extras",
     "//printing",
     "//services/service_manager/public/cpp",
+    "//services/viz/public/interfaces",
     "//skia",
     "//storage/browser",
     "//storage/common",
diff --git a/android_webview/apk/java/AndroidManifest.xml b/android_webview/apk/java/AndroidManifest.xml
index a25f6ba..23b55ecb 100644
--- a/android_webview/apk/java/AndroidManifest.xml
+++ b/android_webview/apk/java/AndroidManifest.xml
@@ -9,7 +9,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="{{package|default('com.android.webview')}}">
     <uses-sdk android:minSdkVersion="{{minsdk|default(21)}}"
-              android:targetSdkVersion="{{targetsdk|default(24)}}">
+              android:targetSdkVersion="{{targetsdk|default(26)}}">
     </uses-sdk>
 
     <uses-feature android:name="android.hardware.touchscreen"
diff --git a/android_webview/browser/aw_safe_browsing_whitelist_manager_unittest.cc b/android_webview/browser/aw_safe_browsing_whitelist_manager_unittest.cc
index bc24b0f..b3097b8 100644
--- a/android_webview/browser/aw_safe_browsing_whitelist_manager_unittest.cc
+++ b/android_webview/browser/aw_safe_browsing_whitelist_manager_unittest.cc
@@ -166,6 +166,14 @@
   EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://user1:pass@google.com")));
 }
 
+TEST_F(AwSafeBrowsingWhitelistManagerTest, WhitelistsWithPunycodeWorks) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("㯙㯜㯙㯟.com");
+  SetWhitelist(std::move(whitelist), true);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://xn--domain.com")));
+}
+
 TEST_F(AwSafeBrowsingWhitelistManagerTest,
        PathQueryAndReferenceWorksWithLeadingDot) {
   std::vector<std::string> whitelist;
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index 8337207f..1bc50b4 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -184,12 +184,14 @@
 void SurfacesInstance::SetSolidColorRootFrame() {
   DCHECK(!surface_size_.IsEmpty());
   gfx::Rect rect(surface_size_);
+  bool is_clipped = false;
+  bool are_contents_opaque = true;
   std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
   render_pass->SetNew(1, rect, rect, gfx::Transform());
   viz::SharedQuadState* quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  quad_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1.f,
-                     SkBlendMode::kSrcOver, 0);
+  quad_state->SetAll(gfx::Transform(), rect, rect, rect, is_clipped,
+                     are_contents_opaque, 1.f, SkBlendMode::kSrcOver, 0);
   cc::SolidColorDrawQuad* solid_quad =
       render_pass->CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>();
   solid_quad->SetNew(quad_state, rect, rect, SK_ColorBLACK, false);
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index d145c98..c7ca90f 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -251,9 +251,6 @@
 }
 
 test("android_webview_unittests") {
-  # Tests do not require any data, but our dependencies pull a lot in.
-  ignore_all_data_deps = true
-
   # Dependencies (e.g. Play services) make the binary reach the dex limit.
   enable_multidex = true
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 3d25b644..262c3ab1 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1677,6 +1677,8 @@
     "test/test_accessibility_delegate.h",
     "test/ui_controls_factory_ash.cc",
     "test/ui_controls_factory_ash.h",
+    "test_media_client.cc",
+    "test_media_client.h",
     "test_screenshot_delegate.cc",
     "test_screenshot_delegate.h",
     "test_shell_delegate.cc",
diff --git a/ash/README.md b/ash/README.md
index 556766a0..cbc736a 100644
--- a/ash/README.md
+++ b/ash/README.md
@@ -38,6 +38,36 @@
 referred to as "classic ash". Ash can run in either mode depending on the
 --mash command line flag.
 
+Prefs
+-----
+Ash supports both per-user prefs and device-wide prefs. These are called
+"profile prefs" and "local state" to match the naming conventions in chrome. Ash
+also supports "signin screen" prefs, bound to a special profile that allows
+users to toggle features like spoken feedback at the login screen.
+
+Local state prefs are loaded asynchronously during startup. User prefs are
+loaded asynchronously after login, and after adding a multiprofile user. Code
+that wants to observe prefs must wait until they are loaded. See
+ShellObserver::OnLocalStatePrefServiceInitialized() and
+SessionObserver::OnActiveUserPrefServiceChanged(). All PrefService objects exist
+for the lifetime of the login session, including the signin prefs.
+
+Pref names are in //ash/public/cpp so that code in chrome can also use the
+names. Prefs are registered in the classes that use them because those classes
+have the best knowledge of default values.
+
+All PrefService instances in ash are backed by the mojo preferences service.
+This means an update to a pref is asynchronous between code in ash and code in
+chrome. For example, if code in chrome changes a pref value then immediately
+calls a C++ function in ash, that ash function may not see the new value yet.
+(This pattern only happens in the classic ash configuration; code in chrome
+cannot call directly into the ash process in the mash config.)
+
+Prefs are either "owned" by ash or by chrome browser. New prefs used by ash
+should be owned by ash. See NightLightController and LogoutButtonTray for
+examples of ash-owned prefs. See //services/preferences/README.md for details of
+pref ownership and "foreign" prefs.
+
 Historical notes
 ----------------
 Ash shipped on Windows for a couple years to support Windows 8 Metro mode.
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index c09c3c1..2a07fec5 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -463,7 +463,12 @@
 void HandleToggleAppList(const ui::Accelerator& accelerator) {
   if (accelerator.key_code() == ui::VKEY_LWIN)
     base::RecordAction(UserMetricsAction("Accel_Search_LWin"));
-  Shell::Get()->ToggleAppList(app_list::kSearchKey);
+
+  Shell::Get()->app_list()->ToggleAppList(
+      display::Screen::GetScreen()
+          ->GetDisplayNearestWindow(Shell::GetRootWindowForNewWindows())
+          .id(),
+      app_list::kSearchKey);
 }
 
 void HandleToggleFullscreen(const ui::Accelerator& accelerator) {
diff --git a/ash/accelerators/accelerator_filter_unittest.cc b/ash/accelerators/accelerator_filter_unittest.cc
index 782080f..03aa7bb8 100644
--- a/ash/accelerators/accelerator_filter_unittest.cc
+++ b/ash/accelerators/accelerator_filter_unittest.cc
@@ -164,8 +164,8 @@
   EXPECT_FALSE(session_controller->IsScreenLocked());
 
   // Search+L is processed when the app_list target visibility is false.
-  Shell::Get()->DismissAppList();
-  EXPECT_FALSE(Shell::Get()->GetAppListTargetVisibility());
+  Shell::Get()->app_list()->Dismiss();
+  EXPECT_FALSE(Shell::Get()->app_list()->GetTargetVisibility());
   generator.PressKey(ui::VKEY_L, ui::EF_COMMAND_DOWN);
   generator.ReleaseKey(ui::VKEY_L, ui::EF_COMMAND_DOWN);
   session_controller->FlushMojoForTest();  // LockScreen is an async mojo call.
diff --git a/ash/accelerators/accelerator_router.cc b/ash/accelerators/accelerator_router.cc
index ee5b11f22..0a2948f0 100644
--- a/ash/accelerators/accelerator_router.cc
+++ b/ash/accelerators/accelerator_router.cc
@@ -9,6 +9,7 @@
 #include "ash/wm/window_state.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
+#include "ui/app_list/presenter/app_list.h"
 #include "ui/aura/window.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/events/event.h"
@@ -129,7 +130,7 @@
   if (accelerator_controller->IsPreferred(accelerator))
     return true;
 
-  return Shell::Get()->GetAppListTargetVisibility();
+  return Shell::Get()->app_list()->GetTargetVisibility();
 }
 
 }  // namespace ash
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc
index 6add410..2b3fdfb 100644
--- a/ash/app_list/app_list_presenter_delegate.cc
+++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -248,8 +248,9 @@
 void AppListPresenterDelegate::OnGestureEvent(ui::GestureEvent* event) {
   if (event->type() == ui::ET_GESTURE_TAP ||
       event->type() == ui::ET_GESTURE_TWO_FINGER_TAP ||
-      event->type() == ui::ET_GESTURE_LONG_PRESS)
+      event->type() == ui::ET_GESTURE_LONG_PRESS) {
     ProcessLocatedEvent(event);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index bfd1b9e..defc425 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -958,7 +958,7 @@
        Stylus battery is low
      </message>
      <message name="IDS_ASH_LOW_STYLUS_BATTERY_NOTIFICATION_BODY" desc="The message of the notification which notifies user of the battery level of a stylus.">
-       Please charge or replace the batteries.
+       Please replace the battery
      </message>
       <message name="IDS_ASH_SCREENSHOT_NOTIFICATION_TITLE_SUCCESS" desc="The title of the notification when a screenshot was taken.">
         Screenshot taken
diff --git a/ash/ash_touch_exploration_manager_chromeos.cc b/ash/ash_touch_exploration_manager_chromeos.cc
index ee97d8e..83b2330c 100644
--- a/ash/ash_touch_exploration_manager_chromeos.cc
+++ b/ash/ash_touch_exploration_manager_chromeos.cc
@@ -127,6 +127,11 @@
     delegate->PlaySpokenFeedbackToggleCountdown(tick_count);
 }
 
+void AshTouchExplorationManager::PlayTouchTypeEarcon() {
+  Shell::Get()->accessibility_delegate()->PlayEarcon(
+      chromeos::SOUND_TOUCH_TYPE);
+}
+
 void AshTouchExplorationManager::ToggleSpokenFeedback() {
   AccessibilityDelegate* delegate = Shell::Get()->accessibility_delegate();
   if (delegate->ShouldToggleSpokenFeedbackViaTouch())
diff --git a/ash/ash_touch_exploration_manager_chromeos.h b/ash/ash_touch_exploration_manager_chromeos.h
index 2d70ad2..97b7406 100644
--- a/ash/ash_touch_exploration_manager_chromeos.h
+++ b/ash/ash_touch_exploration_manager_chromeos.h
@@ -67,6 +67,7 @@
   void OnTwoFingerTouchStart() override;
   void OnTwoFingerTouchStop() override;
   void PlaySpokenFeedbackToggleCountdown(int tick_count) override;
+  void PlayTouchTypeEarcon() override;
   void ToggleSpokenFeedback() override;
 
   // wm::ActivationChangeObserver overrides:
diff --git a/ash/fast_ink/fast_ink_view.cc b/ash/fast_ink/fast_ink_view.cc
index 42f558c..db48a79 100644
--- a/ash/fast_ink/fast_ink_view.cc
+++ b/ash/fast_ink/fast_ink_view.cc
@@ -367,13 +367,13 @@
 
   viz::SharedQuadState* quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  quad_state->SetAll(buffer_to_target_transform,
-                     /*quad_layer_rect=*/output_rect,
-                     /*visible_quad_layer_rect=*/output_rect,
-                     /*clip_rect=*/gfx::Rect(),
-                     /*is_clipped=*/false, /*opacity=*/1.f,
-                     /*blend_mode=*/SkBlendMode::kSrcOver,
-                     /*sorting_context_id=*/0);
+  quad_state->SetAll(
+      buffer_to_target_transform,
+      /*quad_layer_rect=*/output_rect,
+      /*visible_quad_layer_rect=*/output_rect,
+      /*clip_rect=*/gfx::Rect(),
+      /*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
+      /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
 
   cc::CompositorFrame frame;
   // TODO(eseckler): FastInkView should use BeginFrames and set the ack
diff --git a/ash/media_controller.cc b/ash/media_controller.cc
index 6f320bff..8eefa64c3 100644
--- a/ash/media_controller.cc
+++ b/ash/media_controller.cc
@@ -22,6 +22,16 @@
   observers_.RemoveObserver(observer);
 }
 
+void MediaController::SetClient(mojom::MediaClientAssociatedPtrInfo client) {
+  client_.Bind(std::move(client));
+}
+
+void MediaController::NotifyCaptureState(
+    const std::vector<mojom::MediaCaptureState>& capture_states) {
+  for (auto& observer : observers_)
+    observer.OnMediaCaptureChanged(capture_states);
+}
+
 void MediaController::HandleMediaNextTrack() {
   if (client_)
     client_->HandleMediaNextTrack();
@@ -42,14 +52,9 @@
     client_->RequestCaptureState();
 }
 
-void MediaController::SetClient(mojom::MediaClientAssociatedPtrInfo client) {
-  client_.Bind(std::move(client));
-}
-
-void MediaController::NotifyCaptureState(
-    const std::vector<mojom::MediaCaptureState>& capture_states) {
-  for (auto& observer : observers_)
-    observer.OnMediaCaptureChanged(capture_states);
+void MediaController::SuspendMediaSessions() {
+  if (client_)
+    client_->SuspendMediaSessions();
 }
 
 }  // namespace ash
diff --git a/ash/media_controller.h b/ash/media_controller.h
index f0a4824..dfe7b9b7 100644
--- a/ash/media_controller.h
+++ b/ash/media_controller.h
@@ -38,20 +38,21 @@
   void AddObserver(MediaCaptureObserver* observer);
   void RemoveObserver(MediaCaptureObserver* observer);
 
+  // mojom::MediaController:
+  void SetClient(mojom::MediaClientAssociatedPtrInfo client) override;
+  void NotifyCaptureState(
+      const std::vector<mojom::MediaCaptureState>& capture_states) override;
+
   // mojom::MediaClient:
   void HandleMediaNextTrack() override;
   void HandleMediaPlayPause() override;
   void HandleMediaPrevTrack() override;
   void RequestCaptureState() override;
+  void SuspendMediaSessions() override;
 
  private:
   friend class MultiProfileMediaTrayItemTest;
 
-  // mojom::MediaController:
-  void SetClient(mojom::MediaClientAssociatedPtrInfo client) override;
-  void NotifyCaptureState(
-      const std::vector<mojom::MediaCaptureState>& capture_states) override;
-
   mojo::BindingSet<mojom::MediaController> bindings_;
 
   mojom::MediaClientAssociatedPtr client_;
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 8b3b6bb9..2e2eec8f 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -23,18 +23,15 @@
 const char kAccessibilityHighContrastEnabled[] =
     "settings.a11y.high_contrast_enabled";
 // A boolean pref which determines whether screen magnifier is enabled.
+// NOTE: We previously had prefs named settings.a11y.screen_magnifier_type and
+// settings.a11y.screen_magnifier_type2, but we only shipped one type (full).
+// See http://crbug.com/170850 for history.
 const char kAccessibilityScreenMagnifierEnabled[] =
     "settings.a11y.screen_magnifier";
 // A boolean pref which determines whether screen magnifier should center
 // the text input focus.
 const char kAccessibilityScreenMagnifierCenterFocus[] =
     "settings.a11y.screen_magnifier_center_focus";
-// An integer pref which determines what type of screen magnifier is enabled.
-// Note that: 'screen_magnifier_type' had been used as string pref. Hence,
-// we are using another name pref here.
-// NOTE: We only shipped one type (full). http://crbug.com/170850
-const char kAccessibilityScreenMagnifierType[] =
-    "settings.a11y.screen_magnifier_type2";
 // A double pref which determines a zooming scale of the screen magnifier.
 const char kAccessibilityScreenMagnifierScale[] =
     "settings.a11y.screen_magnifier_scale";
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index 4137014..200a703b 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -18,7 +18,6 @@
 ASH_PUBLIC_EXPORT extern const char kAccessibilityHighContrastEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityScreenMagnifierCenterFocus[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityScreenMagnifierEnabled[];
-ASH_PUBLIC_EXPORT extern const char kAccessibilityScreenMagnifierType[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityScreenMagnifierScale[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityVirtualKeyboardEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityMonoAudioEnabled[];
diff --git a/ash/public/interfaces/media.mojom b/ash/public/interfaces/media.mojom
index bf56de4..84cea32 100644
--- a/ash/public/interfaces/media.mojom
+++ b/ash/public/interfaces/media.mojom
@@ -39,4 +39,7 @@
 
   // Requests that the client resends the NotifyMediaCaptureChanged() message.
   RequestCaptureState();
+
+  // Suspends all WebContents-associated media sessions to stop managed players.
+  SuspendMediaSessions();
 };
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc
index a5f30cf..a764ff2 100644
--- a/ash/shelf/app_list_button.cc
+++ b/ash/shelf/app_list_button.cc
@@ -177,7 +177,7 @@
             base::Bind(&AppListButton::StartVoiceInteractionAnimation,
                        base::Unretained(this)));
       }
-      if (!Shell::Get()->IsAppListVisible())
+      if (!Shell::Get()->app_list()->IsVisible())
         AnimateInkDrop(views::InkDropState::ACTION_PENDING, event);
       ImageButton::OnGestureEvent(event);
       return;
@@ -270,7 +270,7 @@
 bool AppListButton::ShouldEnterPushedState(const ui::Event& event) {
   if (!shelf_view_->ShouldEventActivateButton(this, event))
     return false;
-  if (Shell::Get()->IsAppListVisible())
+  if (Shell::Get()->app_list()->IsVisible())
     return false;
   return views::ImageButton::ShouldEnterPushedState(event);
 }
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc
index 00e5f063..a5ce7d86 100644
--- a/ash/shelf/app_list_shelf_item_delegate.cc
+++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -9,6 +9,7 @@
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/shell.h"
 #include "ui/app_list/app_list_constants.h"
+#include "ui/app_list/presenter/app_list.h"
 
 namespace ash {
 
@@ -21,7 +22,7 @@
                                             int64_t display_id,
                                             ShelfLaunchSource source,
                                             ItemSelectedCallback callback) {
-  Shell::Get()->ToggleAppList(app_list::kShelfButton);
+  Shell::Get()->app_list()->ToggleAppList(display_id, app_list::kShelfButton);
   std::move(callback).Run(SHELF_ACTION_APP_LIST_SHOWN, base::nullopt);
 }
 
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 0fea3eb..52a03527 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -29,7 +29,6 @@
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/i18n/rtl.h"
-#include "base/metrics/histogram_macros.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_features.h"
 #include "ui/app_list/presenter/app_list.h"
@@ -1113,7 +1112,11 @@
   if (CanStartFullscreenAppListDrag(
           gesture_in_screen.details().scroll_y_hint())) {
     gesture_drag_status_ = GESTURE_DRAG_APPLIST_IN_PROGRESS;
-    Shell::Get()->ShowAppList(app_list::kSwipeFromShelf);
+    Shell::Get()->app_list()->Show(
+        display::Screen::GetScreen()
+            ->GetDisplayNearestWindow(shelf_widget_->GetNativeWindow())
+            .id(),
+        app_list::kSwipeFromShelf);
     Shell::Get()->app_list()->UpdateYPositionAndOpacity(
         gesture_in_screen.location().y(),
         GetAppListBackgroundOpacityOnShelfOpacity());
@@ -1138,7 +1141,7 @@
     // Dismiss the app list if the shelf changed to vertical alignment during
     // dragging.
     if (!shelf_->IsHorizontalAlignment()) {
-      Shell::Get()->DismissAppList();
+      Shell::Get()->app_list()->Dismiss();
       gesture_drag_amount_ = 0.f;
       gesture_drag_status_ = GESTURE_DRAG_NONE;
       return;
@@ -1247,16 +1250,13 @@
   }
 
   Shell::Get()->app_list()->EndDragFromShelf(app_list_state);
-  UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
-                            app_list::kSwipeFromShelf,
-                            app_list::kMaxAppListToggleMethod);
 
   gesture_drag_status_ = GESTURE_DRAG_NONE;
 }
 
 void ShelfLayoutManager::CancelGestureDrag() {
   if (gesture_drag_status_ == GESTURE_DRAG_APPLIST_IN_PROGRESS) {
-    Shell::Get()->DismissAppList();
+    Shell::Get()->app_list()->Dismiss();
   } else {
     gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS;
     UpdateVisibilityState();
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index bf765ca..08b55d4 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -1652,7 +1652,7 @@
 
   // Swiping up more than the peeking threshold should keep the app list at
   // FULLSCREEN_ALL_APPS state.
-  Shell::Get()->DismissAppList();
+  Shell::Get()->app_list()->Dismiss();
   delta.set_y(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold + 10);
   end = start - delta;
   generator.GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
diff --git a/ash/shell.cc b/ash/shell.cc
index 3ba9371..ad0d6bf3 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -130,7 +130,6 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/sys_info.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/trace_event/trace_event.h"
@@ -494,41 +493,6 @@
   shell_observers_.RemoveObserver(observer);
 }
 
-void Shell::ShowAppList(app_list::AppListShowSource toggle_method) {
-  if (IsAppListVisible()) {
-    UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
-                              toggle_method, app_list::kMaxAppListToggleMethod);
-  }
-  // Show the app list on the default display for new windows.
-  app_list_->Show(display::Screen::GetScreen()
-                      ->GetDisplayNearestWindow(GetRootWindowForNewWindows())
-                      .id());
-}
-
-void Shell::DismissAppList() {
-  app_list_->Dismiss();
-}
-
-void Shell::ToggleAppList(app_list::AppListShowSource toggle_method) {
-  if (IsAppListVisible()) {
-    UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
-                              toggle_method, app_list::kMaxAppListToggleMethod);
-  }
-  // Toggle the app list on the default display for new windows.
-  app_list_->ToggleAppList(
-      display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(GetRootWindowForNewWindows())
-          .id());
-}
-
-bool Shell::IsAppListVisible() const {
-  return app_list_->IsVisible();
-}
-
-bool Shell::GetAppListTargetVisibility() const {
-  return app_list_->GetTargetVisibility();
-}
-
 void Shell::UpdateAfterLoginStatusChange(LoginStatus status) {
   for (auto* root_window_controller : GetAllRootWindowControllers())
     root_window_controller->UpdateAfterLoginStatusChange(status);
diff --git a/ash/shell.h b/ash/shell.h
index dd4dbfde..451fdfd 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -538,24 +538,6 @@
   void AddShellObserver(ShellObserver* observer);
   void RemoveShellObserver(ShellObserver* observer);
 
-  // TODO(minch), move applist related functions to AppList.
-  // http://crbug.com/759909.
-  // Shows the app list on the active root window.
-  void ShowAppList(app_list::AppListShowSource toggle_method);
-
-  // Dismisses the app list.
-  void DismissAppList();
-
-  // Shows the app list if it's not visible. Dismisses it otherwise.
-  void ToggleAppList(app_list::AppListShowSource toggle_method);
-
-  // Returns app list actual visibility. This might differ from
-  // GetAppListTargetVisibility() when hiding animation is still in flight.
-  bool IsAppListVisible() const;
-
-  // Returns app list target visibility.
-  bool GetAppListTargetVisibility() const;
-
   // Called when the login status changes.
   // TODO(oshima): Investigate if we can merge this and |OnLoginStateChanged|.
   void UpdateAfterLoginStatusChange(LoginStatus status);
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index 3c32daf4..ff97ffe 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -24,6 +24,7 @@
 #include "ui/app_list/app_list_item_list.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/app_list_view_delegate.h"
+#include "ui/app_list/presenter/app_list.h"
 #include "ui/app_list/search_box_model.h"
 #include "ui/app_list/search_result.h"
 #include "ui/app_list/speech_ui_model.h"
@@ -271,7 +272,7 @@
 
   void Dismiss() override {
     DCHECK(ShellPort::HasInstance());
-    Shell::Get()->DismissAppList();
+    Shell::Get()->app_list()->Dismiss();
   }
 
   void ViewClosing() override {
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 035e71e..d9ad03b7 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -128,9 +128,6 @@
   // Toggles the status of touchpad between enabled and disabled.
   virtual void ToggleTouchpad() {}
 
-  // Suspends all WebContents-associated media sessions to stop managed players.
-  virtual void SuspendMediaSessions() {}
-
   // Creator of Shell owns this; it's assumed this outlives Shell.
   virtual ui::InputDeviceControllerClient* GetInputDeviceControllerClient() = 0;
 };
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index 1edac2d8..9a0cfd66 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/ime_menu/ime_menu_tray.h"
 
-#include "ash/accelerators/accelerator_controller.h"
 #include "ash/accessibility_delegate.h"
 #include "ash/ash_constants.h"
 #include "ash/ime/ime_controller.h"
@@ -505,18 +504,6 @@
 
 void ImeMenuTray::OnMouseExitedView() {}
 
-void ImeMenuTray::RegisterAccelerators(
-    const std::vector<ui::Accelerator>& accelerators,
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->Register(accelerators,
-                                                   tray_bubble_view);
-}
-
-void ImeMenuTray::UnregisterAllAccelerators(
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->UnregisterAll(tray_bubble_view);
-}
-
 base::string16 ImeMenuTray::GetAccessibleNameForBubble() {
   return l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME);
 }
diff --git a/ash/system/ime_menu/ime_menu_tray.h b/ash/system/ime_menu/ime_menu_tray.h
index c94b4331..0f88b271 100644
--- a/ash/system/ime_menu/ime_menu_tray.h
+++ b/ash/system/ime_menu/ime_menu_tray.h
@@ -65,10 +65,6 @@
   void BubbleViewDestroyed() override;
   void OnMouseEnteredView() override;
   void OnMouseExitedView() override;
-  void RegisterAccelerators(const std::vector<ui::Accelerator>& accelerators,
-                            views::TrayBubbleView* tray_bubble_view) override;
-  void UnregisterAllAccelerators(
-      views::TrayBubbleView* tray_bubble_view) override;
   base::string16 GetAccessibleNameForBubble() override;
   bool ShouldEnableExtraKeyboardAccessibility() override;
   void HideBubble(const views::TrayBubbleView* bubble_view) override;
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 43b0b7d5..53695e6b 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/palette/palette_tray.h"
 
-#include "ash/accelerators/accelerator_controller.h"
 #include "ash/accessibility_delegate.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/config.h"
@@ -318,18 +317,6 @@
 
 void PaletteTray::OnMouseExitedView() {}
 
-void PaletteTray::RegisterAccelerators(
-    const std::vector<ui::Accelerator>& accelerators,
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->Register(accelerators,
-                                                   tray_bubble_view);
-}
-
-void PaletteTray::UnregisterAllAccelerators(
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->UnregisterAll(tray_bubble_view);
-}
-
 base::string16 PaletteTray::GetAccessibleNameForBubble() {
   return GetAccessibleNameForTray();
 }
diff --git a/ash/system/palette/palette_tray.h b/ash/system/palette/palette_tray.h
index c9b4385..a1f22ba 100644
--- a/ash/system/palette/palette_tray.h
+++ b/ash/system/palette/palette_tray.h
@@ -111,10 +111,6 @@
   void BubbleViewDestroyed() override;
   void OnMouseEnteredView() override;
   void OnMouseExitedView() override;
-  void RegisterAccelerators(const std::vector<ui::Accelerator>& accelerators,
-                            views::TrayBubbleView* tray_bubble_view) override;
-  void UnregisterAllAccelerators(
-      views::TrayBubbleView* tray_bubble_view) override;
   base::string16 GetAccessibleNameForBubble() override;
   bool ShouldEnableExtraKeyboardAccessibility() override;
   void HideBubble(const views::TrayBubbleView* bubble_view) override;
diff --git a/ash/system/power/power_button_display_controller.cc b/ash/system/power/power_button_display_controller.cc
index 5895492..18b3853d 100644
--- a/ash/system/power/power_button_display_controller.cc
+++ b/ash/system/power/power_button_display_controller.cc
@@ -5,6 +5,7 @@
 #include "ash/system/power/power_button_display_controller.h"
 
 #include "ash/accessibility_delegate.h"
+#include "ash/media_controller.h"
 #include "ash/public/cpp/touchscreen_enabled_source.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
@@ -69,7 +70,7 @@
   UpdateTouchscreenStatus();
 
   if (backlights_forced_off_)
-    Shell::Get()->shell_delegate()->SuspendMediaSessions();
+    Shell::Get()->media_controller()->SuspendMediaSessions();
 
   // Send an a11y alert.
   Shell::Get()->accessibility_delegate()->TriggerAccessibilityAlert(
diff --git a/ash/system/power/tablet_power_button_controller_unittest.cc b/ash/system/power/tablet_power_button_controller_unittest.cc
index d385174ac..c88a27b 100644
--- a/ash/system/power/tablet_power_button_controller_unittest.cc
+++ b/ash/system/power/tablet_power_button_controller_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "ash/ash_switches.h"
+#include "ash/media_controller.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/touchscreen_enabled_source.h"
 #include "ash/session/session_controller.h"
@@ -14,6 +15,7 @@
 #include "ash/shell.h"
 #include "ash/shell_test_api.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test_media_client.h"
 #include "ash/test_shell_delegate.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/lock_state_controller_test_api.h"
@@ -702,11 +704,14 @@
 // Tests that when backlights get forced off due to tablet power button, media
 // sessions should be suspended.
 TEST_F(TabletPowerButtonControllerTest, SuspendMediaSessions) {
-  ASSERT_FALSE(shell_delegate_->media_sessions_suspended());
+  TestMediaClient client;
+  Shell::Get()->media_controller()->SetClient(client.CreateAssociatedPtrInfo());
+  ASSERT_FALSE(client.media_sessions_suspended());
+
   PressPowerButton();
   ReleasePowerButton();
   ASSERT_TRUE(GetBacklightsForcedOff());
-  EXPECT_TRUE(shell_delegate_->media_sessions_suspended());
+  EXPECT_TRUE(client.media_sessions_suspended());
 }
 
 // Tests that when system is suspended with backlights forced off, and then
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 3b3676d..82fd07f 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -8,7 +8,6 @@
 #include <map>
 #include <vector>
 
-#include "ash/accelerators/accelerator_controller.h"
 #include "ash/login_status.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/public/cpp/config.h"
@@ -603,18 +602,6 @@
     system_bubble_->bubble()->RestartAutoCloseTimer();
 }
 
-void SystemTray::RegisterAccelerators(
-    const std::vector<ui::Accelerator>& accelerators,
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->Register(accelerators,
-                                                   tray_bubble_view);
-}
-
-void SystemTray::UnregisterAllAccelerators(
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->UnregisterAll(tray_bubble_view);
-}
-
 base::string16 SystemTray::GetAccessibleNameForBubble() {
   return GetAccessibleNameForTray();
 }
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index 51308fb..7cf79acd 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -133,10 +133,6 @@
   void BubbleViewDestroyed() override;
   void OnMouseEnteredView() override;
   void OnMouseExitedView() override;
-  void RegisterAccelerators(const std::vector<ui::Accelerator>& accelerators,
-                            views::TrayBubbleView* tray_bubble_view) override;
-  void UnregisterAllAccelerators(
-      views::TrayBubbleView* tray_bubble_view) override;
   base::string16 GetAccessibleNameForBubble() override;
   bool ShouldEnableExtraKeyboardAccessibility() override;
   void HideBubble(const views::TrayBubbleView* bubble_view) override;
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc
index 8d5dc46..548aca2 100644
--- a/ash/system/tray/system_tray_unittest.cc
+++ b/ash/system/tray/system_tray_unittest.cc
@@ -24,6 +24,8 @@
 #include "ash/system/tray_drag_controller.h"
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
+#include "ash/test/ash_test_views_delegate.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_util.h"
 #include "base/memory/ptr_util.h"
@@ -57,6 +59,29 @@
   DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
 };
 
+class KeyEventConsumerView : public views::View {
+ public:
+  KeyEventConsumerView() : number_of_consumed_key_events_(0) {
+    SetFocusBehavior(FocusBehavior::ALWAYS);
+  }
+  ~KeyEventConsumerView() override {}
+
+  // Overriden from views::View
+  bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override {
+    return true;
+  }
+  void OnKeyEvent(ui::KeyEvent* key_event) override {
+    number_of_consumed_key_events_++;
+  }
+
+  int number_of_consumed_key_events() { return number_of_consumed_key_events_; }
+
+ private:
+  int number_of_consumed_key_events_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyEventConsumerView);
+};
+
 }  // namespace
 
 // TODO(minch): move swiping related tests from SystemTrayTest to
@@ -923,4 +948,81 @@
   EXPECT_EQ(kSeparatorWidth, views::Separator::kThickness);
 }
 
+// System tray is not activated by default. But it should be activated when user
+// presses tab key.
+TEST_F(SystemTrayTest, KeyboardNavigationWithOtherWindow) {
+  std::unique_ptr<views::Widget> widget(CreateTestWidget(
+      nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100)));
+  EXPECT_TRUE(widget->IsActive());
+
+  // Add a view which tries to handle key event by themselves, and focus on it.
+  KeyEventConsumerView key_event_consumer_view;
+  views::View* root_view = widget->GetContentsView();
+  root_view->AddChildView(&key_event_consumer_view);
+  key_event_consumer_view.RequestFocus();
+  EXPECT_EQ(&key_event_consumer_view,
+            key_event_consumer_view.GetFocusManager()->GetFocusedView());
+
+  // Show system tray.
+  SystemTray* tray = GetPrimarySystemTray();
+  tray->ShowDefaultView(BUBBLE_CREATE_NEW);
+  ASSERT_TRUE(tray->GetWidget());
+
+  // Confirms that system tray is not activated at this time.
+  EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
+  EXPECT_TRUE(widget->IsActive());
+
+  ui::test::EventGenerator& event_generator = GetEventGenerator();
+  int number_of_consumed_key_events =
+      key_event_consumer_view.number_of_consumed_key_events();
+
+  // Send A key event. Nothing should happen for the tray. Key event is consumed
+  // by the tray.
+  event_generator.PressKey(ui::VKEY_A, ui::EF_NONE);
+  event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE);
+
+  EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
+  EXPECT_TRUE(widget->IsActive());
+  EXPECT_EQ(number_of_consumed_key_events,
+            key_event_consumer_view.number_of_consumed_key_events());
+
+  // Send tab key event.
+  event_generator.PressKey(ui::VKEY_TAB, ui::EF_NONE);
+  event_generator.ReleaseKey(ui::VKEY_TAB, ui::EF_NONE);
+
+  // Confirms that system tray is activated.
+  EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
+  EXPECT_FALSE(widget->IsActive());
+  EXPECT_EQ(number_of_consumed_key_events,
+            key_event_consumer_view.number_of_consumed_key_events());
+}
+
+// System tray passes a key event to ViewsDelegate if it's not handled by the
+// tray. It closes the tray if ViewsDelegate returns CLOSE_MENU.
+TEST_F(SystemTrayTest, AcceleratorController) {
+  // Register A key as an accelerator which closes the menu.
+  ui::Accelerator accelerator(ui::VKEY_A, ui::EF_NONE);
+  AshTestViewsDelegate* views_delegate =
+      ash_test_helper()->test_views_delegate();
+  views_delegate->set_close_menu_accelerator(accelerator);
+
+  // Show system tray.
+  SystemTray* tray = GetPrimarySystemTray();
+  tray->ShowDefaultView(BUBBLE_CREATE_NEW);
+  ASSERT_TRUE(tray->GetWidget());
+  ASSERT_TRUE(tray->IsSystemBubbleVisible());
+
+  ui::test::EventGenerator& event_generator = GetEventGenerator();
+
+  // Send B key event and confirms that nothing happens.
+  event_generator.PressKey(ui::VKEY_B, ui::EF_NONE);
+  event_generator.ReleaseKey(ui::VKEY_B, ui::EF_NONE);
+  EXPECT_TRUE(tray->IsSystemBubbleVisible());
+
+  // Send A key event and confirms that system tray becomes invisible.
+  event_generator.PressKey(ui::VKEY_A, ui::EF_NONE);
+  event_generator.ReleaseKey(ui::VKEY_A, ui::EF_NONE);
+  EXPECT_FALSE(tray->IsSystemBubbleVisible());
+}
+
 }  // namespace ash
diff --git a/ash/system/tray_drag_controller.cc b/ash/system/tray_drag_controller.cc
index fc272dc..76ba49cd 100644
--- a/ash/system/tray_drag_controller.cc
+++ b/ash/system/tray_drag_controller.cc
@@ -7,6 +7,7 @@
 #include "ash/shell.h"
 #include "ash/system/tray/tray_background_view.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ui/app_list/presenter/app_list.h"
 
 namespace ash {
 
@@ -14,11 +15,6 @@
 
 void TrayDragController::ProcessGestureEvent(ui::GestureEvent* event,
                                              TrayBackgroundView* tray_view) {
-  if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
-    Shell::Get()->DismissAppList();
-    return;
-  }
-
   if (!Shell::Get()
            ->tablet_mode_controller()
            ->IsTabletModeWindowManagerEnabled() ||
@@ -26,6 +22,11 @@
     return;
   }
 
+  if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
+    Shell::Get()->app_list()->Dismiss();
+    return;
+  }
+
   tray_view_ = tray_view;
   is_on_bubble_ = event->target() != tray_view;
   if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index 0853799..dec66a7 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/web_notification/web_notification_tray.h"
 
-#include "ash/accelerators/accelerator_controller.h"
 #include "ash/accessibility_delegate.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
@@ -434,18 +433,6 @@
 
 void WebNotificationTray::OnMouseExitedView() {}
 
-void WebNotificationTray::RegisterAccelerators(
-    const std::vector<ui::Accelerator>& accelerators,
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->Register(accelerators,
-                                                   tray_bubble_view);
-}
-
-void WebNotificationTray::UnregisterAllAccelerators(
-    views::TrayBubbleView* tray_bubble_view) {
-  Shell::Get()->accelerator_controller()->UnregisterAll(tray_bubble_view);
-}
-
 base::string16 WebNotificationTray::GetAccessibleNameForBubble() {
   return GetAccessibleNameForTray();
 }
diff --git a/ash/system/web_notification/web_notification_tray.h b/ash/system/web_notification/web_notification_tray.h
index e55cdfc..1b9cc2f 100644
--- a/ash/system/web_notification/web_notification_tray.h
+++ b/ash/system/web_notification/web_notification_tray.h
@@ -88,10 +88,6 @@
   void BubbleViewDestroyed() override;
   void OnMouseEnteredView() override;
   void OnMouseExitedView() override;
-  void RegisterAccelerators(const std::vector<ui::Accelerator>& accelerators,
-                            views::TrayBubbleView* tray_bubble_view) override;
-  void UnregisterAllAccelerators(
-      views::TrayBubbleView* tray_bubble_view) override;
   base::string16 GetAccessibleNameForBubble() override;
   bool ShouldEnableExtraKeyboardAccessibility() override;
   void HideBubble(const views::TrayBubbleView* bubble_view) override;
diff --git a/ash/test/ash_test_views_delegate.cc b/ash/test/ash_test_views_delegate.cc
index 9cc768f..a5b43a0 100644
--- a/ash/test/ash_test_views_delegate.cc
+++ b/ash/test/ash_test_views_delegate.cc
@@ -34,4 +34,13 @@
   }
 }
 
+views::TestViewsDelegate::ProcessMenuAcceleratorResult
+AshTestViewsDelegate::ProcessAcceleratorWhileMenuShowing(
+    const ui::Accelerator& accelerator) {
+  if (accelerator == close_menu_accelerator_)
+    return ProcessMenuAcceleratorResult::CLOSE_MENU;
+
+  return ProcessMenuAcceleratorResult::LEAVE_MENU_OPEN;
+}
+
 }  // namespace ash
diff --git a/ash/test/ash_test_views_delegate.h b/ash/test/ash_test_views_delegate.h
index 6486ccf9..1883e68 100644
--- a/ash/test/ash_test_views_delegate.h
+++ b/ash/test/ash_test_views_delegate.h
@@ -38,8 +38,19 @@
       views::internal::NativeWidgetDelegate* delegate) override;
   void NotifyAccessibilityEvent(views::View* view,
                                 ui::AXEvent event_type) override;
+  views::TestViewsDelegate::ProcessMenuAcceleratorResult
+  ProcessAcceleratorWhileMenuShowing(
+      const ui::Accelerator& accelerator) override;
+
+  void set_close_menu_accelerator(const ui::Accelerator& accelerator) {
+    close_menu_accelerator_ = accelerator;
+  }
 
  private:
+  // ProcessAcceleratorWhileMenuShowing returns CLOSE_MENU if passed accelerator
+  // matches with this.
+  ui::Accelerator close_menu_accelerator_;
+
   // Not owned.
   TestAccessibilityEventDelegate* test_accessibility_event_delegate_ = nullptr;
 
diff --git a/ash/test_media_client.cc b/ash/test_media_client.cc
new file mode 100644
index 0000000..36dac7e
--- /dev/null
+++ b/ash/test_media_client.cc
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/test_media_client.h"
+
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+
+namespace ash {
+
+TestMediaClient::TestMediaClient() : binding_(this) {}
+
+TestMediaClient::~TestMediaClient() = default;
+
+mojom::MediaClientAssociatedPtrInfo TestMediaClient::CreateAssociatedPtrInfo() {
+  mojom::MediaClientAssociatedPtr ptr;
+  binding_.Bind(mojo::MakeIsolatedRequest(&ptr));
+  return ptr.PassInterface();
+}
+
+void TestMediaClient::HandleMediaNextTrack() {}
+
+void TestMediaClient::HandleMediaPlayPause() {}
+
+void TestMediaClient::HandleMediaPrevTrack() {}
+
+void TestMediaClient::RequestCaptureState() {}
+
+void TestMediaClient::SuspendMediaSessions() {
+  media_sessions_suspended_ = true;
+}
+
+}  // namespace ash
diff --git a/ash/test_media_client.h b/ash/test_media_client.h
new file mode 100644
index 0000000..f56b37d
--- /dev/null
+++ b/ash/test_media_client.h
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_TEST_MEDIA_CLIENT_H_
+#define ASH_TEST_MEDIA_CLIENT_H_
+
+#include "ash/public/interfaces/media.mojom.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+
+namespace ash {
+
+// Implement MediaClient mojo interface to simulate chrome behavior in tests.
+// This breaks the ash/chrome dependency to allow testing ash code in isolation.
+class TestMediaClient : public mojom::MediaClient {
+ public:
+  TestMediaClient();
+  ~TestMediaClient() override;
+
+  mojom::MediaClientAssociatedPtrInfo CreateAssociatedPtrInfo();
+
+  // mojom::MediaClient:
+  void HandleMediaNextTrack() override;
+  void HandleMediaPlayPause() override;
+  void HandleMediaPrevTrack() override;
+  void RequestCaptureState() override;
+  void SuspendMediaSessions() override;
+
+  bool media_sessions_suspended() const { return media_sessions_suspended_; }
+
+ private:
+  bool media_sessions_suspended_ = false;
+
+  mojo::AssociatedBinding<mojom::MediaClient> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMediaClient);
+};
+
+}  // namespace ash
+
+#endif  // ASH_TEST_MEDIA_CLIENT_H_
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index 47da152..7967085a 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -143,10 +143,6 @@
   global_touchscreen_enabled_ = enabled;
 }
 
-void TestShellDelegate::SuspendMediaSessions() {
-  media_sessions_suspended_ = true;
-}
-
 ui::InputDeviceControllerClient*
 TestShellDelegate::GetInputDeviceControllerClient() {
   return nullptr;
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index 8387ffe..f965d55 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -52,7 +52,6 @@
   bool GetTouchscreenEnabled(TouchscreenEnabledSource source) const override;
   void SetTouchscreenEnabled(bool enabled,
                              TouchscreenEnabledSource source) override;
-  void SuspendMediaSessions() override;
   ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
 
   int num_exit_requests() const { return num_exit_requests_; }
@@ -61,14 +60,11 @@
     force_maximize_on_first_run_ = maximize;
   }
 
-  bool media_sessions_suspended() const { return media_sessions_suspended_; }
-
  private:
   int num_exit_requests_ = 0;
   bool multi_profiles_enabled_ = false;
   bool force_maximize_on_first_run_ = false;
   bool global_touchscreen_enabled_ = true;
-  bool media_sessions_suspended_ = false;
   std::unique_ptr<ShelfInitializer> shelf_initializer_;
 
   DISALLOW_COPY_AND_ASSIGN(TestShellDelegate);
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index ff7a90c..c63f86d 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -35,6 +35,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/user_action_tester.h"
 #include "ui/app_list/app_list_constants.h"
+#include "ui/app_list/presenter/app_list.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/window_types.h"
@@ -512,9 +513,10 @@
   EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
   EXPECT_EQ(window1.get(), wm::GetFocusedWindow());
 
-  // Pass an enum to satisfy the function, it is arbitrary and will not effect
+  // Pass an enum to satisfy the function, it is arbitrary and will not affect
   // histograms.
-  Shell::Get()->ToggleAppList(app_list::kShelfButton);
+  Shell::Get()->app_list()->ToggleAppList(GetPrimaryDisplay().id(),
+                                          app_list::kShelfButton);
 
   // Activating overview cancels the App-list which normally would activate the
   // previously active |window1|. Overview mode should properly transfer focus
diff --git a/base/allocator/allocator_shim_default_dispatch_to_winheap.cc b/base/allocator/allocator_shim_default_dispatch_to_winheap.cc
index f65e54d..5eba850 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_winheap.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_winheap.cc
@@ -62,15 +62,25 @@
 
 }  // namespace
 
-const AllocatorDispatch AllocatorDispatch::default_dispatch = {
-    &DefaultWinHeapMallocImpl,
-    &DefaultWinHeapCallocImpl,
-    &DefaultWinHeapMemalignImpl,
-    &DefaultWinHeapReallocImpl,
-    &DefaultWinHeapFreeImpl,
-    &DefaultWinHeapGetSizeEstimateImpl,
-    nullptr, /* batch_malloc_function */
-    nullptr, /* batch_free_function */
-    nullptr, /* free_definite_size_function */
-    nullptr, /* next */
+#if defined(_MSC_VER) && _MSC_VER < 1911
+// VC++ 2015 (and maybe VC++ 2017 RTW) can't handle constexpr on static const
+// member variables.
+const
+#else
+// Guarantee that default_dispatch is compile-time initialized to avoid using
+// it before initialization (allocations before main in release builds with
+// optimizations disabled).
+constexpr
+#endif
+    AllocatorDispatch AllocatorDispatch::default_dispatch = {
+        &DefaultWinHeapMallocImpl,
+        &DefaultWinHeapCallocImpl,
+        &DefaultWinHeapMemalignImpl,
+        &DefaultWinHeapReallocImpl,
+        &DefaultWinHeapFreeImpl,
+        &DefaultWinHeapGetSizeEstimateImpl,
+        nullptr, /* batch_malloc_function */
+        nullptr, /* batch_free_function */
+        nullptr, /* free_definite_size_function */
+        nullptr, /* next */
 };
diff --git a/base/allocator/partition_allocator/page_allocator.cc b/base/allocator/partition_allocator/page_allocator.cc
index bad1c61..9d80e06 100644
--- a/base/allocator/partition_allocator/page_allocator.cc
+++ b/base/allocator/partition_allocator/page_allocator.cc
@@ -98,7 +98,7 @@
 static void* SystemAllocPages(void* hint,
                               size_t length,
                               PageAccessibilityConfiguration page_accessibility,
-                              bool commit = true) {
+                              bool commit) {
   DCHECK(!(length & kPageAllocationGranularityOffsetMask));
   DCHECK(!(reinterpret_cast<uintptr_t>(hint) &
            kPageAllocationGranularityOffsetMask));
@@ -147,15 +147,14 @@
   return ret;
 }
 
-}  // namespace
-
 // Trims base to given length and alignment. Windows returns null on failure and
 // frees base.
 static void* TrimMapping(void* base,
                          size_t base_length,
                          size_t trim_length,
                          uintptr_t align,
-                         PageAccessibilityConfiguration page_accessibility) {
+                         PageAccessibilityConfiguration page_accessibility,
+                         bool commit) {
   size_t pre_slack = reinterpret_cast<uintptr_t>(base) & (align - 1);
   if (pre_slack)
     pre_slack = align - pre_slack;
@@ -180,17 +179,20 @@
   if (pre_slack || post_slack) {
     ret = reinterpret_cast<char*>(base) + pre_slack;
     FreePages(base, base_length);
-    ret = SystemAllocPages(ret, trim_length, page_accessibility);
+    ret = SystemAllocPages(ret, trim_length, page_accessibility, commit);
   }
 #endif
 
   return ret;
 }
 
+}  // namespace
+
 void* AllocPages(void* address,
                  size_t length,
                  size_t align,
-                 PageAccessibilityConfiguration page_accessibility) {
+                 PageAccessibilityConfiguration page_accessibility,
+                 bool commit) {
   DCHECK(length >= kPageAllocationGranularity);
   DCHECK(!(length & kPageAllocationGranularityOffsetMask));
   DCHECK(align >= kPageAllocationGranularity);
@@ -210,7 +212,7 @@
 
   // First try to force an exact-size, aligned allocation from our random base.
   for (int count = 0; count < 3; ++count) {
-    void* ret = SystemAllocPages(address, length, page_accessibility);
+    void* ret = SystemAllocPages(address, length, page_accessibility, commit);
     if (kHintIsAdvisory || ret) {
       // If the alignment is to our liking, we're done.
       if (!(reinterpret_cast<uintptr_t>(ret) & align_offset_mask))
@@ -246,12 +248,11 @@
   do {
     // Don't continue to burn cycles on mandatory hints (Windows).
     address = kHintIsAdvisory ? GetRandomPageBase() : nullptr;
-    ret = SystemAllocPages(address, try_length, page_accessibility);
+    ret = SystemAllocPages(address, try_length, page_accessibility, commit);
     // The retries are for Windows, where a race can steal our mapping on
     // resize.
-  } while (ret &&
-           (ret = TrimMapping(ret, try_length, length, align,
-                              page_accessibility)) == nullptr);
+  } while (ret && (ret = TrimMapping(ret, try_length, length, align,
+                                     page_accessibility, commit)) == nullptr);
 
   return ret;
 }
@@ -359,12 +360,10 @@
 }
 
 bool ReserveAddressSpace(size_t size) {
-  DCHECK(size >= kPageAllocationGranularity);
-  DCHECK(!(size & kPageAllocationGranularityOffsetMask));
-
   // Don't take |s_reserveLock| while allocating, since a failure would invoke
   // ReleaseReservation and deadlock.
-  void* mem = SystemAllocPages(nullptr, size, PageInaccessible, false);
+  void* mem = AllocPages(nullptr, size, kPageAllocationGranularity,
+                         PageInaccessible, false);
   // We guarantee this alignment when reserving address space.
   DCHECK(!(reinterpret_cast<uintptr_t>(mem) &
            kPageAllocationGranularityOffsetMask));
diff --git a/base/allocator/partition_allocator/page_allocator.h b/base/allocator/partition_allocator/page_allocator.h
index f15062810..a16eaadf 100644
--- a/base/allocator/partition_allocator/page_allocator.h
+++ b/base/allocator/partition_allocator/page_allocator.h
@@ -53,7 +53,8 @@
 BASE_EXPORT void* AllocPages(void* address,
                              size_t length,
                              size_t align,
-                             PageAccessibilityConfiguration page_accessibility);
+                             PageAccessibilityConfiguration page_accessibility,
+                             bool commit = true);
 
 // Free one or more pages.
 // address and length must match a previous call to allocPages().
diff --git a/base/android/java/src/org/chromium/base/JavaHandlerThread.java b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
index 8805f68b..f3e945c 100644
--- a/base/android/java/src/org/chromium/base/JavaHandlerThread.java
+++ b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
@@ -56,7 +56,7 @@
     @CalledByNative
     private void stopOnThread(final long nativeThread) {
         nativeStopThread(nativeThread);
-        MessageQueue queue = mThread.getLooper().getQueue();
+        MessageQueue queue = Looper.myQueue();
         // Add an idle handler so that the thread cleanup code can run after the message loop has
         // detected an idle state and quit properly.
         // This matches the behavior of base::Thread in that it will keep running non-delayed posted
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
index d3f7a7f..bab1fb8e 100644
--- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -41,7 +41,7 @@
     protected SystemMessageHandler(long messagePumpDelegateNative, long messagePumpNative) {
         mMessagePumpDelegateNative = messagePumpDelegateNative;
         mMessagePumpNative = messagePumpNative;
-        Looper.myLooper().getQueue().addIdleHandler(mIdleHandler);
+        Looper.myQueue().addIdleHandler(mIdleHandler);
     }
 
     @Override
@@ -74,7 +74,7 @@
     private void removeAllPendingMessages() {
         removeMessages(SCHEDULED_WORK);
         removeMessages(DELAYED_SCHEDULED_WORK);
-        Looper.myLooper().getQueue().removeIdleHandler(mIdleHandler);
+        Looper.myQueue().removeIdleHandler(mIdleHandler);
     }
 
     private Message obtainAsyncMessage(int what) {
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index 99a000ed7..7821ebc 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -44,9 +44,7 @@
 #include "base/threading/thread_restrictions.h"
 
 // LazyInstance uses its own struct initializer-list style static
-// initialization, as base's LINKER_INITIALIZED requires a constructor and on
-// some compilers (notably gcc 4.4) this still ends up needing runtime
-// initialization.
+// initialization, which does not require a constructor.
 #define LAZY_INSTANCE_INITIALIZER {0}
 
 namespace base {
diff --git a/base/macros.h b/base/macros.h
index 154d4b0..79f07319 100644
--- a/base/macros.h
+++ b/base/macros.h
@@ -55,21 +55,7 @@
 inline void ignore_result(const T&) {
 }
 
-// The following enum should be used only as a constructor argument to indicate
-// that the variable has static storage class, and that the constructor should
-// do nothing to its state.  It indicates to the reader that it is legal to
-// declare a static instance of the class, provided the constructor is given
-// the base::LINKER_INITIALIZED argument.  Normally, it is unsafe to declare a
-// static variable that has a constructor or a destructor because invocation
-// order is undefined.  However, IF the type can be initialized by filling with
-// zeroes (which the loader does for static variables), AND the destructor also
-// does nothing to the storage, AND there are no virtual methods, then a
-// constructor declared as
-//       explicit MyClass(base::LinkerInitialized x) {}
-// and invoked as
-//       static MyClass my_variable_name(base::LINKER_INITIALIZED);
 namespace base {
-enum LinkerInitialized { LINKER_INITIALIZED };
 
 // Use these to declare and define a static local variable (static T;) so that
 // it is leaked so that its destructors are not called at exit. If you need
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.cc b/base/task_scheduler/scheduler_worker_pool_impl.cc
index b4b992c..52e8890 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task_scheduler/scheduler_worker_pool_impl.cc
@@ -10,6 +10,9 @@
 #include <utility>
 
 #include "base/atomicops.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram.h"
 #include "base/sequence_token.h"
@@ -24,6 +27,8 @@
 namespace base {
 namespace internal {
 
+constexpr TimeDelta SchedulerWorkerPoolImpl::kBlockedWorkersPollPeriod;
+
 namespace {
 
 constexpr char kPoolNameSuffix[] = "Pool";
@@ -83,6 +88,14 @@
   void BlockingScopeEntered(BlockingType blocking_type) override;
   void BlockingScopeExited(BlockingType blocking_type) override;
 
+  void MayBlockScopeEntered();
+  void WillBlockScopeEntered();
+
+  // Returns true iff this worker has been within a MAY_BLOCK ScopedBlockingCall
+  // for more than |outer_->MayBlockThreshold()|. The worker capacity must be
+  // incremented if this returns true.
+  bool MustIncrementWorkerCapacityLockRequired();
+
  private:
   // Returns true if |worker| is allowed to cleanup and remove itself from the
   // pool. Called from GetWork() when no work is available.
@@ -107,11 +120,18 @@
   // TaskScheduler.NumTasksBeforeDetach histogram was recorded.
   size_t num_tasks_since_last_detach_ = 0;
 
-  // Indicates whether the worker holding this delegate is on the idle worker's
-  // stack. This should only be accessed under the protection of
-  // |outer_->lock_|.
+  // Whether the worker holding this delegate is on the idle worker's stack.
+  // Access synchronized by |outer_->lock_|.
   bool is_on_idle_workers_stack_ = true;
 
+  // Whether |outer_->worker_capacity_| was incremented due to a
+  // ScopedBlockingCall on the thread. Access synchronized by |outer_->lock_|.
+  bool incremented_worker_capacity_since_blocked_ = false;
+
+  // Time when MayBlockScopeEntered() was last called. Reset when
+  // BlockingScopeExited() is called. Access synchronized by |outer_->lock_|.
+  TimeTicks may_block_start_time_;
+
   DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDelegateImpl);
 };
 
@@ -154,7 +174,9 @@
           50,
           HistogramBase::kUmaTargetedHistogramFlag)) {}
 
-void SchedulerWorkerPoolImpl::Start(const SchedulerWorkerPoolParams& params) {
+void SchedulerWorkerPoolImpl::Start(
+    const SchedulerWorkerPoolParams& params,
+    scoped_refptr<TaskRunner> service_thread_task_runner) {
   AutoSchedulerLock auto_lock(lock_);
 
   DCHECK(workers_.empty());
@@ -164,6 +186,8 @@
   suggested_reclaim_time_ = params.suggested_reclaim_time();
   backward_compatibility_ = params.backward_compatibility();
 
+  service_thread_task_runner_ = std::move(service_thread_task_runner);
+
   // The initial number of workers is |num_wake_ups_before_start_| + 1 to try to
   // keep one at least one standby thread at all times (capacity permitting).
   const int num_initial_workers = std::min(num_wake_ups_before_start_ + 1,
@@ -282,6 +306,10 @@
   return idle_workers_stack_.Size();
 }
 
+void SchedulerWorkerPoolImpl::MaximizeMayBlockThresholdForTesting() {
+  maximum_blocked_threshold_for_testing_.Set();
+}
+
 SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
     SchedulerWorkerDelegateImpl(SchedulerWorkerPoolImpl* outer)
     : outer_(outer) {}
@@ -477,16 +505,55 @@
 }
 #endif
 
-// TODO(crbug.com/757475): Support BlockingType::MAY_BLOCK.
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::BlockingScopeEntered(
     BlockingType blocking_type) {
-  if (blocking_type != BlockingType::WILL_BLOCK)
-    return;
+  switch (blocking_type) {
+    case BlockingType::MAY_BLOCK:
+      MayBlockScopeEntered();
+      break;
+    case BlockingType::WILL_BLOCK:
+      WillBlockScopeEntered();
+      break;
+  }
+}
+
+void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::BlockingScopeExited(
+    BlockingType blocking_type) {
+  AutoSchedulerLock auto_lock(outer_->lock_);
+  if (incremented_worker_capacity_since_blocked_)
+    outer_->DecrementWorkerCapacityLockRequired();
+  else if (!may_block_start_time_.is_null())
+    --outer_->num_pending_may_block_workers_;
+
+  incremented_worker_capacity_since_blocked_ = false;
+  may_block_start_time_ = TimeTicks();
+}
+
+void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
+    MayBlockScopeEntered() {
+  AutoSchedulerLock auto_lock(outer_->lock_);
+
+  DCHECK(!incremented_worker_capacity_since_blocked_);
+  DCHECK(may_block_start_time_.is_null());
+  may_block_start_time_ = TimeTicks::Now();
+  ++outer_->num_pending_may_block_workers_;
+
+  if (!outer_->polling_worker_capacity_ &&
+      outer_->ShouldPeriodicallyAdjustWorkerCapacityLockRequired()) {
+    outer_->PostAdjustWorkerCapacityTaskLockRequired();
+  }
+}
+
+void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
+    WillBlockScopeEntered() {
   std::unique_ptr<PriorityQueue::Transaction> shared_transaction(
       outer_->shared_priority_queue_.BeginTransaction());
   AutoSchedulerLock auto_lock(outer_->lock_);
 
-  ++outer_->worker_capacity_;
+  DCHECK(!incremented_worker_capacity_since_blocked_);
+  DCHECK(may_block_start_time_.is_null());
+  incremented_worker_capacity_since_blocked_ = true;
+  outer_->IncrementWorkerCapacityLockRequired();
 
   // If the number of workers was less than the old worker capacity, PostTask
   // would've handled creating extra workers during WakeUpOneWorker. Therefore,
@@ -504,13 +571,24 @@
   }
 }
 
-// TODO(crbug.com/757475): Support BlockingType::MAY_BLOCK.
-void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::BlockingScopeExited(
-    BlockingType blocking_type) {
-  if (blocking_type != BlockingType::WILL_BLOCK)
-    return;
-  AutoSchedulerLock auto_lock(outer_->lock_);
-  --outer_->worker_capacity_;
+bool SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
+    MustIncrementWorkerCapacityLockRequired() {
+  outer_->lock_.AssertAcquired();
+
+  if (!incremented_worker_capacity_since_blocked_ &&
+      !may_block_start_time_.is_null() &&
+      TimeTicks::Now() - may_block_start_time_ >= outer_->MayBlockThreshold()) {
+    incremented_worker_capacity_since_blocked_ = true;
+
+    // Reset |may_block_start_time_| so that BlockingScopeExited() knows that it
+    // doesn't have to decrement |outer_->num_pending_may_block_workers_|.
+    may_block_start_time_ = TimeTicks();
+    --outer_->num_pending_may_block_workers_;
+
+    return true;
+  }
+
+  return false;
 }
 
 void SchedulerWorkerPoolImpl::WaitForWorkersIdleLockRequiredForTesting(
@@ -546,6 +624,11 @@
   // Ensure that there is one worker that can run tasks on top of the idle
   // stack, capacity permitting.
   MaintainAtLeastOneIdleWorkerLockRequired();
+
+  if (!polling_worker_capacity_ &&
+      ShouldPeriodicallyAdjustWorkerCapacityLockRequired()) {
+    PostAdjustWorkerCapacityTaskLockRequired();
+  }
 }
 
 void SchedulerWorkerPoolImpl::WakeUpOneWorker() {
@@ -628,5 +711,98 @@
   return std::max<int>(0, workers_.size() - worker_capacity_);
 }
 
+void SchedulerWorkerPoolImpl::AdjustWorkerCapacity() {
+  std::unique_ptr<PriorityQueue::Transaction> shared_transaction(
+      shared_priority_queue_.BeginTransaction());
+  AutoSchedulerLock auto_lock(lock_);
+
+  const size_t original_worker_capacity = worker_capacity_;
+
+  // Increment worker capacity for each worker that has been within a MAY_BLOCK
+  // ScopedBlockingCall for more than MayBlockThreshold().
+  for (scoped_refptr<SchedulerWorker> worker : workers_) {
+    // The delegates of workers inside a SchedulerWorkerPoolImpl should be
+    // SchedulerWorkerDelegateImpls.
+    SchedulerWorkerDelegateImpl* delegate =
+        static_cast<SchedulerWorkerDelegateImpl*>(worker->delegate());
+    if (delegate->MustIncrementWorkerCapacityLockRequired())
+      IncrementWorkerCapacityLockRequired();
+  }
+
+  // Wake up a worker per pending sequence, capacity permitting.
+  const size_t num_pending_sequences = shared_transaction->Size();
+  const size_t num_wake_ups_needed = std::min(
+      worker_capacity_ - original_worker_capacity, num_pending_sequences);
+
+  for (size_t i = 0; i < num_wake_ups_needed; ++i)
+    WakeUpOneWorkerLockRequired();
+
+  MaintainAtLeastOneIdleWorkerLockRequired();
+}
+
+TimeDelta SchedulerWorkerPoolImpl::MayBlockThreshold() const {
+  if (maximum_blocked_threshold_for_testing_.IsSet())
+    return TimeDelta::Max();
+  // This value was set unscientifically based on intuition and may be adjusted
+  // in the future. This value is smaller than |kBlockedWorkersPollPeriod|
+  // because we hope than when multiple workers block around the same time, a
+  // single AdjustWorkerCapacity() call will perform all the necessary capacity
+  // adjustments.
+  return TimeDelta::FromMilliseconds(10);
+}
+
+void SchedulerWorkerPoolImpl::PostAdjustWorkerCapacityTaskLockRequired() {
+  lock_.AssertAcquired();
+
+  polling_worker_capacity_ = true;
+
+  service_thread_task_runner_->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](SchedulerWorkerPoolImpl* worker_pool) {
+            worker_pool->AdjustWorkerCapacity();
+
+            AutoSchedulerLock auto_lock(worker_pool->lock_);
+            DCHECK(worker_pool->polling_worker_capacity_);
+
+            if (worker_pool
+                    ->ShouldPeriodicallyAdjustWorkerCapacityLockRequired()) {
+              worker_pool->PostAdjustWorkerCapacityTaskLockRequired();
+            } else {
+              worker_pool->polling_worker_capacity_ = false;
+            }
+          },
+          Unretained(this)),
+      kBlockedWorkersPollPeriod);
+}
+
+bool SchedulerWorkerPoolImpl::
+    ShouldPeriodicallyAdjustWorkerCapacityLockRequired() {
+  lock_.AssertAcquired();
+  // AdjustWorkerCapacity() must be periodically called when (1) there are no
+  // idle workers that can do work (2) there are workers that are within the
+  // scope of a MAY_BLOCK ScopedBlockingCall but haven't cause a capacity
+  // increment yet.
+  //
+  // - When (1) is false: A newly posted task will be scheduled on one of the
+  //   idle workers that are allowed to do work. There is no hurry to increase
+  //   capacity.
+  // - When (2) is false: AdjustWorkerCapacity() would be a no-op.
+  const int idle_workers_that_can_do_work =
+      idle_workers_stack_.Size() - NumberOfExcessWorkersLockRequired();
+  return idle_workers_that_can_do_work <= 0 &&
+         num_pending_may_block_workers_ > 0;
+}
+
+void SchedulerWorkerPoolImpl::DecrementWorkerCapacityLockRequired() {
+  lock_.AssertAcquired();
+  --worker_capacity_;
+}
+
+void SchedulerWorkerPoolImpl::IncrementWorkerCapacityLockRequired() {
+  lock_.AssertAcquired();
+  ++worker_capacity_;
+}
+
 }  // namespace internal
 }  // namespace base
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.h b/base/task_scheduler/scheduler_worker_pool_impl.h
index f5c95f5a..47921ff 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl.h
+++ b/base/task_scheduler/scheduler_worker_pool_impl.h
@@ -18,6 +18,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/condition_variable.h"
+#include "base/task_runner.h"
 #include "base/task_scheduler/priority_queue.h"
 #include "base/task_scheduler/scheduler_lock.h"
 #include "base/task_scheduler/scheduler_worker.h"
@@ -60,8 +61,10 @@
       DelayedTaskManager* delayed_task_manager);
 
   // Creates workers following the |params| specification, allowing existing and
-  // future tasks to run. Can only be called once. CHECKs on failure.
-  void Start(const SchedulerWorkerPoolParams& params);
+  // future tasks to run. Uses |service_thread_task_runner| to monitor for
+  // blocked threads in the pool. Can only be called once. CHECKs on failure.
+  void Start(const SchedulerWorkerPoolParams& params,
+             scoped_refptr<TaskRunner> service_thread_task_runner);
 
   // Destroying a SchedulerWorkerPoolImpl returned by Create() is not allowed in
   // production; it is always leaked. In tests, it can only be destroyed after
@@ -108,9 +111,23 @@
   // Returns the number of workers that are idle (i.e. not running tasks).
   size_t NumberOfIdleWorkersForTesting();
 
+  // Sets the MayBlock waiting threshold to TimeDelta::Max().
+  void MaximizeMayBlockThresholdForTesting();
+
  private:
   class SchedulerWorkerDelegateImpl;
 
+  // Friend tests so that they can access |kBlockedWorkersPollPeriod| and
+  // BlockedThreshold().
+  friend class TaskSchedulerWorkerPoolBlockingEnterExitTest;
+  friend class TaskSchedulerWorkerPoolMayBlockTest;
+
+  // The period between calls to AdjustWorkerCapacity() when the pool is at
+  // capacity. This value was set unscientifically based on intuition and may be
+  // adjusted in the future.
+  static constexpr TimeDelta kBlockedWorkersPollPeriod =
+      TimeDelta::FromMilliseconds(50);
+
   SchedulerWorkerPoolImpl(const SchedulerWorkerPoolParams& params,
                           TaskTracker* task_tracker,
                           DelayedTaskManager* delayed_task_manager);
@@ -154,6 +171,26 @@
   // the pool being over worker capacity.
   size_t NumberOfExcessWorkersLockRequired() const;
 
+  // Examines the list of SchedulerWorkers and increments |worker_capacity_| for
+  // each worker that has been within the scope of a MAY_BLOCK
+  // ScopedBlockingCall for more than BlockedThreshold().
+  void AdjustWorkerCapacity();
+
+  // Returns the threshold after which the worker capacity is increased to
+  // compensate for a worker that is within a MAY_BLOCK ScopedBlockingCall.
+  TimeDelta MayBlockThreshold() const;
+
+  // Starts calling AdjustWorkerCapacity() periodically on
+  // |service_thread_task_runner_|.
+  void PostAdjustWorkerCapacityTaskLockRequired();
+
+  // Returns true if AdjustWorkerCapacity() should periodically be called on
+  // |service_thread_task_runner_|.
+  bool ShouldPeriodicallyAdjustWorkerCapacityLockRequired();
+
+  void DecrementWorkerCapacityLockRequired();
+  void IncrementWorkerCapacityLockRequired();
+
   const std::string name_;
   const ThreadPriority priority_hint_;
 
@@ -167,12 +204,14 @@
   SchedulerBackwardCompatibility backward_compatibility_;
 
   // Synchronizes accesses to |workers_|, |worker_capacity_|,
-  // |idle_workers_stack_|, |idle_workers_stack_cv_for_testing_|,
-  // |num_wake_ups_before_start_|, |cleanup_timestamps_|,
-  // |SchedulerWorkerDelegateImpl::is_on_idle_workers_stack_|, and
-  // |SchedulerWorkerDelegateImpl::increased_worker_capacity_since_blocked_|.
-  // Has |shared_priority_queue_|'s lock as its predecessor so that a worker can
-  // be pushed to |idle_workers_stack_| within the scope of a Transaction (more
+  // |num_pending_may_block_workers_|, |idle_workers_stack_|,
+  // |idle_workers_stack_cv_for_testing_|, |num_wake_ups_before_start_|,
+  // |cleanup_timestamps_|, |polling_worker_capacity_|,
+  // |SchedulerWorkerDelegateImpl::is_on_idle_workers_stack_|,
+  // |SchedulerWorkerDelegateImpl::incremented_worker_capacity_since_blocked_|
+  // and |SchedulerWorkerDelegateImpl::may_block_start_time_|. Has
+  // |shared_priority_queue_|'s lock as its predecessor so that a worker can be
+  // pushed to |idle_workers_stack_| within the scope of a Transaction (more
   // details in GetWork()).
   mutable SchedulerLock lock_;
 
@@ -186,6 +225,10 @@
   // Initial value of |worker_capacity_| as set in Start().
   size_t initial_worker_capacity_ = 0;
 
+  // Number workers that are within the scope of a MAY_BLOCK ScopedBlockingCall
+  // but haven't caused a worker capacity increase yet.
+  int num_pending_may_block_workers_ = 0;
+
   // Stack of idle workers. Initially, all workers are on this stack. A worker
   // is removed from the stack before its WakeUp() function is called and when
   // it receives work from GetWork() (a worker calls GetWork() when its sleep
@@ -204,6 +247,14 @@
   // Timestamps get popped off the stack as new workers are added.
   std::stack<TimeTicks, std::vector<TimeTicks>> cleanup_timestamps_;
 
+  // Whether we are currently polling for necessary adjustments to
+  // |worker_capacity_|.
+  bool polling_worker_capacity_ = false;
+
+  // Used for testing and makes MayBlockThreshold() return the maximum
+  // TimeDelta.
+  AtomicFlag maximum_blocked_threshold_for_testing_;
+
   // Signaled once JoinForTesting() has returned.
   WaitableEvent join_for_testing_returned_;
 
@@ -227,6 +278,8 @@
   // Intentionally leaked.
   HistogramBase* const num_tasks_between_waits_histogram_;
 
+  scoped_refptr<TaskRunner> service_thread_task_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerPoolImpl);
 };
 
diff --git a/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc b/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc
index 180e7efd..96a3ff0 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_pool_impl_unittest.cc
@@ -59,17 +59,16 @@
     TimeDelta::FromMilliseconds(500);
 constexpr TimeDelta kExtraTimeToWaitForCleanup = TimeDelta::FromSeconds(1);
 
-class TaskSchedulerWorkerPoolImplTest
-    : public testing::TestWithParam<test::ExecutionMode> {
+class TaskSchedulerWorkerPoolImplTestBase {
  protected:
-  TaskSchedulerWorkerPoolImplTest()
-      : service_thread_("TaskSchedulerServiceThread") {}
+  TaskSchedulerWorkerPoolImplTestBase()
+      : service_thread_("TaskSchedulerServiceThread"){};
 
-  void SetUp() override {
+  void SetUp() {
     CreateAndStartWorkerPool(TimeDelta::Max(), kNumWorkersInWorkerPool);
   }
 
-  void TearDown() override {
+  void TearDown() {
     service_thread_.Stop();
     task_tracker_.Flush();
     worker_pool_->WaitForAllWorkersIdleForTesting();
@@ -89,7 +88,8 @@
   void StartWorkerPool(TimeDelta suggested_reclaim_time, size_t num_workers) {
     ASSERT_TRUE(worker_pool_);
     worker_pool_->Start(
-        SchedulerWorkerPoolParams(num_workers, suggested_reclaim_time));
+        SchedulerWorkerPoolParams(num_workers, suggested_reclaim_time),
+        service_thread_.task_runner());
   }
 
   void CreateAndStartWorkerPool(TimeDelta suggested_reclaim_time,
@@ -106,9 +106,37 @@
  private:
   DelayedTaskManager delayed_task_manager_;
 
+  DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTestBase);
+};
+
+class TaskSchedulerWorkerPoolImplTest
+    : public TaskSchedulerWorkerPoolImplTestBase,
+      public testing::Test {
+ protected:
+  TaskSchedulerWorkerPoolImplTest() = default;
+
+  void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::SetUp(); }
+
+  void TearDown() override { TaskSchedulerWorkerPoolImplTestBase::TearDown(); }
+
+ private:
   DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTest);
 };
 
+class TaskSchedulerWorkerPoolImplTestParam
+    : public TaskSchedulerWorkerPoolImplTestBase,
+      public testing::TestWithParam<test::ExecutionMode> {
+ protected:
+  TaskSchedulerWorkerPoolImplTestParam() = default;
+
+  void SetUp() override { TaskSchedulerWorkerPoolImplTestBase::SetUp(); }
+
+  void TearDown() override { TaskSchedulerWorkerPoolImplTestBase::TearDown(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerPoolImplTestParam);
+};
+
 using PostNestedTask = test::TestTaskFactory::PostNestedTask;
 
 class ThreadPostingTasksWaitIdle : public SimpleThread {
@@ -146,7 +174,7 @@
 
 }  // namespace
 
-TEST_P(TaskSchedulerWorkerPoolImplTest, PostTasksWaitAllWorkersIdle) {
+TEST_P(TaskSchedulerWorkerPoolImplTestParam, PostTasksWaitAllWorkersIdle) {
   // Create threads to post tasks. To verify that workers can sleep and be woken
   // up when new tasks are posted, wait for all workers to become idle before
   // posting a new task.
@@ -169,7 +197,7 @@
   worker_pool_->WaitForAllWorkersIdleForTesting();
 }
 
-TEST_P(TaskSchedulerWorkerPoolImplTest, PostTasksWithOneAvailableWorker) {
+TEST_P(TaskSchedulerWorkerPoolImplTestParam, PostTasksWithOneAvailableWorker) {
   // Post blocking tasks to keep all workers busy except one until |event| is
   // signaled. Use different factories so that tasks are added to different
   // sequences and can run simultaneously when the execution mode is SEQUENCED.
@@ -202,7 +230,7 @@
   worker_pool_->WaitForAllWorkersIdleForTesting();
 }
 
-TEST_P(TaskSchedulerWorkerPoolImplTest, Saturate) {
+TEST_P(TaskSchedulerWorkerPoolImplTestParam, Saturate) {
   // Verify that it is possible to have |kNumWorkersInWorkerPool|
   // tasks/sequences running simultaneously. Use different factories so that the
   // blocking tasks are added to different sequences and can run simultaneously
@@ -228,10 +256,10 @@
 }
 
 INSTANTIATE_TEST_CASE_P(Parallel,
-                        TaskSchedulerWorkerPoolImplTest,
+                        TaskSchedulerWorkerPoolImplTestParam,
                         ::testing::Values(test::ExecutionMode::PARALLEL));
 INSTANTIATE_TEST_CASE_P(Sequenced,
-                        TaskSchedulerWorkerPoolImplTest,
+                        TaskSchedulerWorkerPoolImplTestParam,
                         ::testing::Values(test::ExecutionMode::SEQUENCED));
 
 namespace {
@@ -659,11 +687,14 @@
 TEST(TaskSchedulerWorkerPoolStandbyPolicyTest, InitOne) {
   TaskTracker task_tracker;
   DelayedTaskManager delayed_task_manager;
-  delayed_task_manager.Start(make_scoped_refptr(new TestSimpleTaskRunner));
+  scoped_refptr<TaskRunner> service_thread_task_runner =
+      MakeRefCounted<TestSimpleTaskRunner>();
+  delayed_task_manager.Start(service_thread_task_runner);
   auto worker_pool = std::make_unique<SchedulerWorkerPoolImpl>(
       "OnePolicyWorkerPool", ThreadPriority::NORMAL, &task_tracker,
       &delayed_task_manager);
-  worker_pool->Start(SchedulerWorkerPoolParams(8U, TimeDelta::Max()));
+  worker_pool->Start(SchedulerWorkerPoolParams(8U, TimeDelta::Max()),
+                     service_thread_task_runner);
   ASSERT_TRUE(worker_pool);
   EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting());
   worker_pool->JoinForTesting();
@@ -676,12 +707,15 @@
 
   TaskTracker task_tracker;
   DelayedTaskManager delayed_task_manager;
-  delayed_task_manager.Start(MakeRefCounted<TestSimpleTaskRunner>());
+  scoped_refptr<TaskRunner> service_thread_task_runner =
+      MakeRefCounted<TestSimpleTaskRunner>();
+  delayed_task_manager.Start(service_thread_task_runner);
   auto worker_pool = std::make_unique<SchedulerWorkerPoolImpl>(
       "StandbyThreadWorkerPool", ThreadPriority::NORMAL, &task_tracker,
       &delayed_task_manager);
   worker_pool->Start(
-      SchedulerWorkerPoolParams(worker_capacity, kReclaimTimeForCleanupTests));
+      SchedulerWorkerPoolParams(worker_capacity, kReclaimTimeForCleanupTests),
+      service_thread_task_runner);
   ASSERT_TRUE(worker_pool);
   EXPECT_EQ(1U, worker_pool->NumberOfWorkersForTesting());
 
@@ -722,47 +756,74 @@
 }
 
 class TaskSchedulerWorkerPoolBlockingEnterExitTest
-    : public TaskSchedulerWorkerPoolImplTest {
+    : public TaskSchedulerWorkerPoolImplTestBase,
+      public testing::TestWithParam<BlockingType> {
  public:
   TaskSchedulerWorkerPoolBlockingEnterExitTest()
-      : TaskSchedulerWorkerPoolImplTest(),
-        blocking_thread_running_(WaitableEvent::ResetPolicy::AUTOMATIC,
+      : blocking_thread_running_(WaitableEvent::ResetPolicy::AUTOMATIC,
                                  WaitableEvent::InitialState::NOT_SIGNALED),
         blocking_thread_continue_(WaitableEvent::ResetPolicy::MANUAL,
                                   WaitableEvent::InitialState::NOT_SIGNALED) {}
 
   void SetUp() override {
-    TaskSchedulerWorkerPoolImplTest::SetUp();
+    TaskSchedulerWorkerPoolImplTestBase::SetUp();
     task_runner_ =
         worker_pool_->CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()});
   }
 
+  void TearDown() override { TaskSchedulerWorkerPoolImplTestBase::TearDown(); }
+
  protected:
   // Saturates the worker pool with a task that first blocks, waits to be
   // unblocked, then exits.
-  void SaturateWithBlockingTasks() {
+  void SaturateWithBlockingTasks(BlockingType blocking_type) {
     RepeatingClosure blocking_thread_running_closure =
         BarrierClosure(kNumWorkersInWorkerPool,
                        BindOnce(&WaitableEvent::Signal,
                                 Unretained(&blocking_thread_running_)));
+
     for (size_t i = 0; i < kNumWorkersInWorkerPool; ++i) {
       task_runner_->PostTask(
           FROM_HERE,
           BindOnce(
               [](Closure* blocking_thread_running_closure,
-                 WaitableEvent* blocking_thread_continue_) {
-                ScopedBlockingCall scoped_will_block(BlockingType::WILL_BLOCK);
+                 WaitableEvent* blocking_thread_continue_,
+                 BlockingType blocking_type) {
+                ScopedBlockingCall scoped_will_block(blocking_type);
 
                 blocking_thread_running_closure->Run();
                 blocking_thread_continue_->Wait();
 
               },
               Unretained(&blocking_thread_running_closure),
-              Unretained(&blocking_thread_continue_)));
+              Unretained(&blocking_thread_continue_), blocking_type));
     }
     blocking_thread_running_.Wait();
   }
 
+  // Returns how long we can expect a change to |worker_capacity_| to occur
+  // after a task has become blocked.
+  TimeDelta GetWorkerCapacityChangeSleepTime() {
+    return std::max(SchedulerWorkerPoolImpl::kBlockedWorkersPollPeriod,
+                    worker_pool_->MayBlockThreshold()) +
+           TestTimeouts::tiny_timeout();
+  }
+
+  // Waits up to some amount of time until |worker_pool_|'s worker capacity
+  // reaches |expected_worker_capacity|.
+  void ExpectWorkerCapacityAfterDelay(size_t expected_worker_capacity) {
+    constexpr int kMaxAttempts = 4;
+    for (int i = 0;
+         i < kMaxAttempts && worker_pool_->GetWorkerCapacityForTesting() !=
+                                 expected_worker_capacity;
+         ++i) {
+      PlatformThread::Sleep(GetWorkerCapacityChangeSleepTime());
+    }
+
+    EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(),
+              expected_worker_capacity);
+  }
+
   // Unblocks tasks posted by SaturateWithBlockingTasks().
   void UnblockTasks() { blocking_thread_continue_.Signal(); }
 
@@ -778,11 +839,13 @@
 // Verify that BlockingScopeEntered() causes worker capacity to increase and
 // creates a worker if needed. Also verify that BlockingScopeExited() decreases
 // worker capacity after an increase.
-TEST_F(TaskSchedulerWorkerPoolBlockingEnterExitTest, ThreadBlockedUnblocked) {
+TEST_P(TaskSchedulerWorkerPoolBlockingEnterExitTest, ThreadBlockedUnblocked) {
   ASSERT_EQ(worker_pool_->GetWorkerCapacityForTesting(),
             kNumWorkersInWorkerPool);
 
-  SaturateWithBlockingTasks();
+  SaturateWithBlockingTasks(GetParam());
+  if (GetParam() == BlockingType::MAY_BLOCK)
+    ExpectWorkerCapacityAfterDelay(2 * kNumWorkersInWorkerPool);
   // A range of possible number of workers is accepted because of
   // crbug.com/757897.
   EXPECT_GE(worker_pool_->NumberOfWorkersForTesting(),
@@ -800,7 +863,7 @@
 
 // Verify that tasks posted in a saturated pool before a ScopedBlockingCall will
 // execute after ScopedBlockingCall is instantiated.
-TEST_F(TaskSchedulerWorkerPoolBlockingEnterExitTest, PostBeforeBlocking) {
+TEST_P(TaskSchedulerWorkerPoolBlockingEnterExitTest, PostBeforeBlocking) {
   WaitableEvent thread_running(WaitableEvent::ResetPolicy::AUTOMATIC,
                                WaitableEvent::InitialState::NOT_SIGNALED);
   WaitableEvent thread_can_block(WaitableEvent::ResetPolicy::MANUAL,
@@ -812,15 +875,16 @@
     task_runner_->PostTask(
         FROM_HERE,
         BindOnce(
-            [](WaitableEvent* thread_running, WaitableEvent* thread_can_block,
+            [](BlockingType blocking_type, WaitableEvent* thread_running,
+               WaitableEvent* thread_can_block,
                WaitableEvent* thread_continue) {
               thread_running->Signal();
               thread_can_block->Wait();
-              ScopedBlockingCall scoped_blocking_call(BlockingType::WILL_BLOCK);
+              ScopedBlockingCall scoped_blocking_call(blocking_type);
               thread_continue->Wait();
             },
-            Unretained(&thread_running), Unretained(&thread_can_block),
-            Unretained(&thread_continue)));
+            GetParam(), Unretained(&thread_running),
+            Unretained(&thread_can_block), Unretained(&thread_continue)));
     thread_running.Wait();
   }
 
@@ -853,6 +917,8 @@
   // Allow tasks to enter ScopedBlockingCall. Workers should be created for the
   // tasks we just posted.
   thread_can_block.Signal();
+  if (GetParam() == BlockingType::MAY_BLOCK)
+    ExpectWorkerCapacityAfterDelay(2 * kNumWorkersInWorkerPool);
 
   // Should not block forever.
   extra_thread_running.Wait();
@@ -865,12 +931,14 @@
 }
 // Verify that workers become idle when the pool is over-capacity and that
 // those workers do no work.
-TEST_F(TaskSchedulerWorkerPoolBlockingEnterExitTest,
+TEST_P(TaskSchedulerWorkerPoolBlockingEnterExitTest,
        WorkersIdleWhenOverCapacity) {
   ASSERT_EQ(worker_pool_->GetWorkerCapacityForTesting(),
             kNumWorkersInWorkerPool);
 
-  SaturateWithBlockingTasks();
+  SaturateWithBlockingTasks(GetParam());
+  if (GetParam() == BlockingType::MAY_BLOCK)
+    ExpectWorkerCapacityAfterDelay(2 * kNumWorkersInWorkerPool);
   EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(),
             2 * kNumWorkersInWorkerPool);
   // A range of possible number of workers is accepted because of
@@ -944,6 +1012,36 @@
   task_tracker_.Flush();
 }
 
+INSTANTIATE_TEST_CASE_P(WILL_BLOCK,
+                        TaskSchedulerWorkerPoolBlockingEnterExitTest,
+                        ::testing::Values(BlockingType::WILL_BLOCK));
+INSTANTIATE_TEST_CASE_P(MAY_BLOCK,
+                        TaskSchedulerWorkerPoolBlockingEnterExitTest,
+                        ::testing::Values(BlockingType::MAY_BLOCK));
+
+// Verify that if a thread enters the scope of a ScopedMayBlock, but exits the
+// scope before the MayBlockThreshold() is reached, that the worker capacity
+// does not increase.
+TEST_F(TaskSchedulerWorkerPoolBlockingEnterExitTest,
+       ThreadBlockUnblockPremature) {
+  ASSERT_EQ(worker_pool_->GetWorkerCapacityForTesting(),
+            kNumWorkersInWorkerPool);
+
+  TimeDelta worker_capacity_change_sleep = GetWorkerCapacityChangeSleepTime();
+  worker_pool_->MaximizeMayBlockThresholdForTesting();
+
+  SaturateWithBlockingTasks(BlockingType::MAY_BLOCK);
+  PlatformThread::Sleep(worker_capacity_change_sleep);
+  EXPECT_EQ(worker_pool_->NumberOfWorkersForTesting(), kNumWorkersInWorkerPool);
+  EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(),
+            kNumWorkersInWorkerPool);
+
+  UnblockTasks();
+  task_tracker_.Flush();
+  EXPECT_EQ(worker_pool_->GetWorkerCapacityForTesting(),
+            kNumWorkersInWorkerPool);
+}
+
 // Verify that workers that become idle due to the pool being over capacity will
 // eventually cleanup.
 TEST(TaskSchedulerWorkerPoolOverWorkerCapacityTest, VerifyCleanup) {
@@ -951,12 +1049,15 @@
 
   TaskTracker task_tracker;
   DelayedTaskManager delayed_task_manager;
-  delayed_task_manager.Start(MakeRefCounted<TestSimpleTaskRunner>());
+  scoped_refptr<TaskRunner> service_thread_task_runner =
+      MakeRefCounted<TestSimpleTaskRunner>();
+  delayed_task_manager.Start(service_thread_task_runner);
   SchedulerWorkerPoolImpl worker_pool("OverWorkerCapacityTestWorkerPool",
                                       ThreadPriority::NORMAL, &task_tracker,
                                       &delayed_task_manager);
   worker_pool.Start(
-      SchedulerWorkerPoolParams(kWorkerCapacity, kReclaimTimeForCleanupTests));
+      SchedulerWorkerPoolParams(kWorkerCapacity, kReclaimTimeForCleanupTests),
+      service_thread_task_runner);
 
   scoped_refptr<TaskRunner> task_runner =
       worker_pool.CreateTaskRunnerWithTraits({WithBaseSyncPrimitives()});
diff --git a/base/task_scheduler/scheduler_worker_pool_unittest.cc b/base/task_scheduler/scheduler_worker_pool_unittest.cc
index f5d82c3..1ea3e4f 100644
--- a/base/task_scheduler/scheduler_worker_pool_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_pool_unittest.cc
@@ -129,8 +129,10 @@
       case PoolType::GENERIC: {
         SchedulerWorkerPoolImpl* scheduler_worker_pool_impl =
             static_cast<SchedulerWorkerPoolImpl*>(worker_pool_.get());
-        scheduler_worker_pool_impl->Start(SchedulerWorkerPoolParams(
-            kNumWorkersInWorkerPool, TimeDelta::Max()));
+        scheduler_worker_pool_impl->Start(
+            SchedulerWorkerPoolParams(kNumWorkersInWorkerPool,
+                                      TimeDelta::Max()),
+            service_thread_.task_runner());
         break;
       }
 #if defined(OS_WIN)
diff --git a/base/task_scheduler/task_scheduler_impl.cc b/base/task_scheduler/task_scheduler_impl.cc
index 6db8cdb..2bd793f 100644
--- a/base/task_scheduler/task_scheduler_impl.cc
+++ b/base/task_scheduler/task_scheduler_impl.cc
@@ -80,16 +80,22 @@
 #endif  // defined(OS_POSIX) && !defined(OS_NACL_SFI)
 
   // Needs to happen after starting the service thread to get its task_runner().
-  delayed_task_manager_.Start(service_thread_.task_runner());
+  scoped_refptr<TaskRunner> service_thread_task_runner =
+      service_thread_.task_runner();
+  delayed_task_manager_.Start(service_thread_task_runner);
 
   single_thread_task_runner_manager_.Start();
 
-  worker_pools_[BACKGROUND]->Start(init_params.background_worker_pool_params);
+  worker_pools_[BACKGROUND]->Start(init_params.background_worker_pool_params,
+                                   service_thread_task_runner);
   worker_pools_[BACKGROUND_BLOCKING]->Start(
-      init_params.background_blocking_worker_pool_params);
-  worker_pools_[FOREGROUND]->Start(init_params.foreground_worker_pool_params);
+      init_params.background_blocking_worker_pool_params,
+      service_thread_task_runner);
+  worker_pools_[FOREGROUND]->Start(init_params.foreground_worker_pool_params,
+                                   service_thread_task_runner);
   worker_pools_[FOREGROUND_BLOCKING]->Start(
-      init_params.foreground_blocking_worker_pool_params);
+      init_params.foreground_blocking_worker_pool_params,
+      service_thread_task_runner);
 }
 
 void TaskSchedulerImpl::PostDelayedTaskWithTraits(
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
index d6b66e8..b6f34c3 100644
--- a/base/threading/thread_local_storage.h
+++ b/base/threading/thread_local_storage.h
@@ -97,9 +97,7 @@
   typedef void (*TLSDestructorFunc)(void* value);
 
   // StaticSlot uses its own struct initializer-list style static
-  // initialization, as base's LINKER_INITIALIZED requires a constructor and on
-  // some compilers (notably gcc 4.4) this still ends up needing runtime
-  // initialization.
+  // initialization, which does not require a constructor.
   #define TLS_INITIALIZER {0}
 
   // A key representing one value stored in TLS.
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index cc0dac90..24f4921 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -402,7 +402,10 @@
     if (options.is_fast_polling_supported)
       MemoryPeakDetector::GetInstance()->NotifyMemoryDumpProvidersChanged();
 
-    heap_profiling_enabled = IsHeapProfilingModeEnabled(heap_profiling_mode_);
+    heap_profiling_enabled =
+        (heap_profiling_mode_ == kHeapProfilingModePseudo) ||
+        (heap_profiling_mode_ == kHeapProfilingModeNative) ||
+        (heap_profiling_mode_ == kHeapProfilingModeNoStack);
   }
 
   if (heap_profiling_enabled)
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 3f3dab8..e892c2ac 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -838,15 +838,24 @@
 TEST_F(MemoryDumpManagerTest, EnableHeapProfilingPseudoStack) {
   InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
   MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
   RegisterDumpProvider(&mdp1, nullptr);
-  testing::InSequence sequence;
-  EXPECT_CALL(mdp1, OnHeapProfilingEnabled(true)).Times(1);
-  EXPECT_CALL(mdp1, OnHeapProfilingEnabled(false)).Times(1);
+  {
+    testing::InSequence sequence;
+    EXPECT_CALL(mdp1, OnHeapProfilingEnabled(true)).Times(1);
+    EXPECT_CALL(mdp1, OnHeapProfilingEnabled(false)).Times(1);
+  }
+  {
+    testing::InSequence sequence;
+    EXPECT_CALL(mdp2, OnHeapProfilingEnabled(true)).Times(1);
+    EXPECT_CALL(mdp2, OnHeapProfilingEnabled(false)).Times(1);
+  }
 
   EXPECT_TRUE(mdm_->EnableHeapProfiling(kHeapProfilingModePseudo));
   ASSERT_EQ(AllocationContextTracker::CaptureMode::PSEUDO_STACK,
             AllocationContextTracker::capture_mode());
   EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModePseudo);
+  RegisterDumpProvider(&mdp2, nullptr);
   // Disable will permanently disable heap profiling.
   EXPECT_TRUE(mdm_->EnableHeapProfiling(kHeapProfilingModeDisabled));
   EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeInvalid);
@@ -893,15 +902,16 @@
 TEST_F(MemoryDumpManagerTest, EnableHeapProfilingTask) {
   InitializeMemoryDumpManagerForInProcessTesting(true /* is_coordinator */);
   MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
   RegisterDumpProvider(&mdp1, nullptr);
-  testing::InSequence sequence;
-  EXPECT_CALL(mdp1, OnHeapProfilingEnabled(true)).Times(0);
-  EXPECT_CALL(mdp1, OnHeapProfilingEnabled(false)).Times(0);
+  EXPECT_CALL(mdp1, OnHeapProfilingEnabled(_)).Times(0);
+  EXPECT_CALL(mdp2, OnHeapProfilingEnabled(_)).Times(0);
 
   ASSERT_FALSE(base::debug::ThreadHeapUsageTracker::IsHeapTrackingEnabled());
   EXPECT_TRUE(mdm_->EnableHeapProfiling(kHeapProfilingModeTaskProfiler));
   ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
             AllocationContextTracker::capture_mode());
+  RegisterDumpProvider(&mdp2, nullptr);
   EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeTaskProfiler);
   ASSERT_TRUE(debug::ThreadHeapUsageTracker::IsHeapTrackingEnabled());
   TestingThreadHeapUsageTracker::DisableHeapTrackingForTesting();
diff --git a/base/trace_event/sharded_allocation_register.cc b/base/trace_event/sharded_allocation_register.cc
index f1e2d3c..d03a7ef 100644
--- a/base/trace_event/sharded_allocation_register.cc
+++ b/base/trace_event/sharded_allocation_register.cc
@@ -14,12 +14,12 @@
 // "base/trace_event/heap_profiler_allocation_register.h".
 #if defined(OS_ANDROID) || defined(OS_IOS)
 const size_t ShardCount = 1;
-#elif defined(OS_WIN)
+#elif defined(OS_MACOSX)
+const size_t ShardCount = 64;
+#else
 // Using ShardCount = 64 adds about 1.6GB of committed memory, which triggers
 // the sandbox's committed memory limit.
 const size_t ShardCount = 16;
-#else
-const size_t ShardCount = 64;
 #endif
 
 ShardedAllocationRegister::ShardedAllocationRegister() : enabled_(false) {}
diff --git a/build/android/gradle/android.jinja b/build/android/gradle/android.jinja
index 32befa88..ff7b403 100644
--- a/build/android/gradle/android.jinja
+++ b/build/android/gradle/android.jinja
@@ -97,6 +97,9 @@
         return (it.name.equals('generateDebugSources')  // causes unwanted AndroidManifest.java
                 || it.name.equals('generateReleaseSources')
                 || it.name.endsWith('BuildConfig')  // causes unwanted BuildConfig.java
+{% if canary %}
+                || it.name.equals('preDebugAndroidTestBuild')
+{% endif %}
 {% if not use_gradle_process_resources %}
                 || it.name.endsWith('Assets')
                 || it.name.endsWith('Resources')
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index a5e29ee..d357f73 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -834,7 +834,7 @@
 
   logging.warning('Project created!')
   logging.warning('Generated projects work with %s',
-                  'Android Studio 3.0 Canary 9' if args.canary
+                  'Android Studio 3.0 Beta 2' if args.canary
                       else 'Android Studio 2.3')
   logging.warning('For more tips: https://chromium.googlesource.com/chromium'
                   '/src.git/+/master/docs/android_studio.md')
diff --git a/build/android/gradle/root.jinja b/build/android/gradle/root.jinja
index 9cd23f1..077ca6b 100644
--- a/build/android/gradle/root.jinja
+++ b/build/android/gradle/root.jinja
@@ -14,7 +14,7 @@
     }
     dependencies {
 {% if canary %}
-        classpath "com.android.tools.build:gradle:3.0.0-beta1"
+        classpath "com.android.tools.build:gradle:3.0.0-beta2"
 {% else %}
         classpath "com.android.tools.build:gradle:2.3.3"
 {% endif %}
diff --git a/build/android/gyp/assert_static_initializers.py b/build/android/gyp/assert_static_initializers.py
new file mode 100755
index 0000000..e9bfebd
--- /dev/null
+++ b/build/android/gyp/assert_static_initializers.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# 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.
+
+"""Checks the number of static initializers in an APK's library."""
+
+import argparse
+import os
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import resource_sizes
+
+from util import build_utils
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument('--touch', help='File to touch upon success')
+  parser.add_argument('--tool-prefix', required=True,
+                      help='Prefix for nm and friends')
+  parser.add_argument('--expected-count', required=True, type=int,
+                      help='Fail if number of static initializers is not '
+                           'equal to this value.')
+  parser.add_argument('apk', help='APK file path.')
+  args = parser.parse_args()
+
+  si_count = resource_sizes.AnalyzeStaticInitializers(
+      args.apk, args.tool_prefix, False, '.')
+  if si_count != args.expected_count:
+    print 'Expected {} static initializers, but found {}.'.format(
+        args.expected_count, si_count)
+    if args.expected_count > si_count:
+      print 'You have removed one or more static initializers. Thanks!'
+      print 'To fix the build, update the expectation in:'
+      print '    //chrome/android/static_initializers.gni'
+    else:
+      print 'Dumping static initializers via dump-static-initializers.py:'
+      sys.stdout.flush()
+      resource_sizes.AnalyzeStaticInitializers(
+          args.apk, args.tool_prefix, True, '.')
+      print
+      print 'If the above list is not useful, consider listing them with:'
+      print '    //tools/binary_size/diagnose_bloat.py'
+      print
+      print 'For more information:'
+      print ('    https://chromium.googlesource.com/chromium/src/+/master/docs/'
+             'static_initializers.md')
+    sys.exit(1)
+
+  if args.depfile:
+    build_utils.WriteDepfile(args.depfile, args.touch)
+  if args.touch:
+    open(args.touch, 'w')
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index a15e518..e5f9f08b 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -31,6 +31,11 @@
   parser.add_option('--output-path', help='Path to the generated .jar file.')
   parser.add_option('--proguard-configs', action='append',
                     help='Paths to proguard configuration files.')
+  parser.add_option('--proguard-config-exclusions',
+                    default='',
+                    help='GN list of paths to proguard configuration files '
+                         'included by --proguard-configs, but that should '
+                         'not actually be included.')
   parser.add_option('--mapping', help='Path to proguard mapping to apply.')
   parser.add_option('--is-test', action='store_true',
       help='If true, extra proguard options for instrumentation tests will be '
@@ -56,6 +61,8 @@
   for arg in options.proguard_configs:
     configs += build_utils.ParseGnList(arg)
   options.proguard_configs = configs
+  options.proguard_config_exclusions = (
+      build_utils.ParseGnList(options.proguard_config_exclusions))
 
   options.input_paths = build_utils.ParseGnList(options.input_paths)
 
@@ -81,6 +88,7 @@
   proguard = proguard_util.ProguardCmdBuilder(options.proguard_path)
   proguard.injars(options.input_paths)
   proguard.configs(options.proguard_configs)
+  proguard.config_exclusions(options.proguard_config_exclusions)
   proguard.outjar(options.output_path)
 
   if options.mapping:
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py
index dd1f06c..31a69051 100644
--- a/build/android/gyp/util/proguard_util.py
+++ b/build/android/gyp/util/proguard_util.py
@@ -52,6 +52,7 @@
     self._libraries = None
     self._injars = None
     self._configs = None
+    self._config_exclusions = None
     self._outjar = None
     self._cmd = None
     self._verbose = False
@@ -90,9 +91,14 @@
   def configs(self, paths):
     assert self._cmd is None
     assert self._configs is None
-    for p in paths:
-      assert os.path.exists(p), p
     self._configs = paths
+    for p in self._configs:
+      assert os.path.exists(p), p
+
+  def config_exclusions(self, paths):
+    assert self._cmd is None
+    assert self._config_exclusions is None
+    self._config_exclusions = paths
 
   def verbose(self, verbose):
     assert self._cmd is None
@@ -116,6 +122,9 @@
       tested_apk_info = build_utils.ReadJson(self._tested_apk_info_path)
       self._configs += tested_apk_info['configs']
 
+    for path in self._config_exclusions:
+      self._configs.remove(path)
+
     if self._mapping:
       cmd += [
         '-applymapping', self._mapping,
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index 367aa2f..caeba76 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -17,6 +17,7 @@
 from pylib.constants import host_paths
 from pylib.instrumentation import test_result
 from pylib.instrumentation import instrumentation_parser
+from pylib.symbols import deobfuscator
 from pylib.symbols import stack_symbolizer
 from pylib.utils import dexdump
 from pylib.utils import instrumentation_tracing
@@ -497,8 +498,8 @@
 
     self._store_tombstones = False
     self._symbolizer = None
-    self._initializeTombstonesAttributes(args)
-
+    self._enable_java_deobfuscation = False
+    self._deobfuscator = None
     self._gs_results_bucket = None
     self._should_save_logcat = None
     self._initializeLogAttributes(args)
@@ -678,13 +679,13 @@
   def _initializeTestCoverageAttributes(self, args):
     self._coverage_directory = args.coverage_dir
 
-  def _initializeTombstonesAttributes(self, args):
+  def _initializeLogAttributes(self, args):
+    self._enable_java_deobfuscation = args.enable_java_deobfuscation
     self._store_tombstones = args.store_tombstones
     self._symbolizer = stack_symbolizer.Symbolizer(
         self.apk_under_test.path if self.apk_under_test else None,
         args.enable_relocation_packing)
 
-  def _initializeLogAttributes(self, args):
     self._gs_results_bucket = args.gs_results_bucket
     self._should_save_logcat = bool(args.json_results_file)
 
@@ -827,6 +828,9 @@
   def SetUp(self):
     self._data_deps.extend(
         self._data_deps_delegate(self._runtime_deps_path))
+    if self._enable_java_deobfuscation:
+      self._deobfuscator = deobfuscator.DeobfuscatorPool(
+          self.test_apk.path + '.mapping')
 
   def GetDataDependencies(self):
     return self._data_deps
@@ -838,6 +842,11 @@
       raw_tests = GetAllTestsFromApk(self.test_apk.path)
     return self.ProcessRawTests(raw_tests)
 
+  def MaybeDeobfuscateLines(self, lines):
+    if not self._deobfuscator:
+      return lines
+    return self._deobfuscator.TransformLines(lines)
+
   def ProcessRawTests(self, raw_tests):
     inflated_tests = self._ParameterizeTestsWithFlags(
         self._InflateTests(raw_tests))
@@ -915,3 +924,6 @@
   #override
   def TearDown(self):
     self.symbolizer.CleanUp()
+    if self._deobfuscator:
+      self._deobfuscator.Close()
+      self._deobfuscator = None
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index 0d802d8..01c11156 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -459,17 +459,21 @@
     logcat_url = logmon.GetLogcatURL()
     duration_ms = time_ms() - start_ms
 
+    with contextlib_ext.Optional(
+        trace_event.trace('ProcessResults'),
+        self._env.trace_output):
+      output = self._test_instance.MaybeDeobfuscateLines(output)
+      # TODO(jbudorick): Make instrumentation tests output a JSON so this
+      # doesn't have to parse the output.
+      result_code, result_bundle, statuses = (
+          self._test_instance.ParseAmInstrumentRawOutput(output))
+      results = self._test_instance.GenerateTestResults(
+          result_code, result_bundle, statuses, start_ms, duration_ms,
+          device.product_cpu_abi, self._test_instance.symbolizer)
+
     if self._env.trace_output:
       self._SaveTraceData(trace_device_file, device, test['class'])
 
-    # TODO(jbudorick): Make instrumentation tests output a JSON so this
-    # doesn't have to parse the output.
-    result_code, result_bundle, statuses = (
-        self._test_instance.ParseAmInstrumentRawOutput(output))
-    results = self._test_instance.GenerateTestResults(
-        result_code, result_bundle, statuses, start_ms, duration_ms,
-        device.product_cpu_abi, self._test_instance.symbolizer)
-
     def restore_flags():
       if flags_to_add:
         self._flag_changers[str(device)].Restore()
diff --git a/build/android/pylib/symbols/deobfuscator.py b/build/android/pylib/symbols/deobfuscator.py
new file mode 100644
index 0000000..f85b86b
--- /dev/null
+++ b/build/android/pylib/symbols/deobfuscator.py
@@ -0,0 +1,133 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import subprocess
+import uuid
+
+from devil.utils import reraiser_thread
+from pylib import constants
+
+
+_MINIUMUM_TIMEOUT = 5.0  # Large enough to account for process start-up.
+_PER_LINE_TIMEOUT = .002  # Should be able to process 500 lines per second.
+
+
+class Deobfuscator(object):
+  def __init__(self, mapping_path):
+    self._reader_thread = None
+    script_path = os.path.join(
+        constants.GetOutDirectory(), 'bin', 'java_deobfuscate')
+    cmd = [script_path, mapping_path]
+    # Start process eagerly to hide start-up latency.
+    self._proc = subprocess.Popen(
+        cmd, bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+        close_fds=True)
+    self._logged_error = False
+
+  def IsClosed(self):
+    return self._proc.returncode is not None
+
+  def IsBusy(self):
+    return bool(self._reader_thread)
+
+  def IsReady(self):
+    return not self.IsClosed() and not self.IsBusy()
+
+  def TransformLines(self, lines):
+    """Deobfuscates obfuscated names found in the given lines.
+
+    If anything goes wrong (process crashes, timeout, etc), returns |lines|.
+
+    Args:
+      lines: A list of strings without trailing newlines.
+
+    Returns:
+      A list of strings without trailing newlines.
+    """
+    if not lines:
+      return []
+
+    # Allow only one thread to communicate with the subprocess at a time.
+    if self._reader_thread:
+      logging.warning('Having to wait for Java deobfuscation.')
+      self._reader_thread.join()
+
+    if self._proc.returncode is not None:
+      if not self._logged_error:
+        logging.warning('java_deobfuscate process exited with code=%d.',
+                        self._proc.returncode)
+        self._logged_error = True
+      return lines
+
+    out_lines = []
+    eof_line = uuid.uuid4().hex
+
+    def deobfuscate_reader():
+      while True:
+        line = self._proc.stdout.readline()[:-1]
+        # Due to inlining, deobfuscated stacks may contain more frames than
+        # obfuscated ones. To account for the variable number of lines, keep
+        # reading until eof_line.
+        if line == eof_line:
+          break
+        out_lines.append(line)
+
+    # TODO(agrieve): Can probably speed this up by only sending lines through
+    #     that might contain an obfuscated name.
+    self._reader_thread = reraiser_thread.ReraiserThread(deobfuscate_reader)
+    self._reader_thread.start()
+    try:
+      self._proc.stdin.write('\n'.join(lines))
+      self._proc.stdin.write('\n{}\n'.format(eof_line))
+      self._proc.stdin.flush()
+      timeout = max(_MINIUMUM_TIMEOUT, len(lines) * _PER_LINE_TIMEOUT)
+      self._reader_thread.join(timeout)
+      if self._reader_thread.is_alive():
+        logging.error('java_deobfuscate timed out.')
+        self.Close()
+      self._reader_thread = None
+      return out_lines
+    except IOError:
+      logging.exception('Exception during java_deobfuscate')
+      self.Close()
+      return lines
+
+  def Close(self):
+    if not self.IsClosed():
+      self._proc.stdin.close()
+      self._proc.kill()
+      self._proc.wait()
+    self._reader_thread = None
+
+  def __del__(self):
+    if not self.IsClosed():
+      logging.error('Forgot to Close() deobfuscator')
+
+
+class DeobfuscatorPool(object):
+  def __init__(self, mapping_path, pool_size=4):
+    self._mapping_path = mapping_path
+    self._pool = [Deobfuscator(mapping_path) for _ in xrange(pool_size)]
+
+  def TransformLines(self, lines):
+    target_instance = next((x for x in self._pool if x.IsReady()), None)
+
+    # Restart any closed ones.
+    for i, d in enumerate(self._pool):
+      if d.IsClosed():
+        logging.warning('Restarting closed Deobfuscator instance.')
+        self._pool[i] = Deobfuscator(self._mapping_path)
+
+    if not target_instance:
+      # No idle ones. Use the first one and cycle so as to not choose it again.
+      target_instance = self._pool[0]
+      self._pool.append(self._pool.pop(0))
+
+    return target_instance.TransformLines(lines)
+
+  def Close(self):
+    for d in self._pool:
+      d.Close()
diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
index e4fca7b..2e0500e 100755
--- a/build/android/resource_sizes.py
+++ b/build/android/resource_sizes.py
@@ -656,8 +656,8 @@
   return id_name_map, id_header_map
 
 
-def _PrintStaticInitializerAnalysis(apk_filename, tool_prefix, dump_sis,
-                                    out_dir, chartjson=None):
+# This method also used by //build/android/gyp/assert_static_initializers.py
+def AnalyzeStaticInitializers(apk_filename, tool_prefix, dump_sis, out_dir):
   # Static initializer counting mostly copies logic in
   # infra/scripts/legacy/scripts/slave/chromium/sizes.py.
   with zipfile.ZipFile(apk_filename) as z:
@@ -674,13 +674,12 @@
   for f in files_to_check:
     with Unzip(apk_filename, filename=f.filename) as unzipped_so:
       si_count += CountStaticInitializers(unzipped_so, tool_prefix)
-      if dump_sis and out_dir:
+      if dump_sis:
         # Print count and list of SIs reported by dump-static-initializers.py.
         # Doesn't work well on all archs (particularly arm), which is why
         # the readelf method is used for tracking SI counts.
         _PrintDumpSIsCount(f.filename, unzipped_so, out_dir, tool_prefix)
-  ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', si_count,
-                   'count')
+  return si_count
 
 
 def _PrintDumpSIsCount(apk_so_name, unzipped_so, out_dir, tool_prefix):
@@ -772,7 +771,7 @@
 
 def _ConfigOutDirAndToolsPrefix(out_dir):
   if out_dir:
-    constants.SetOutputDirectory(out_dir)
+    constants.SetOutputDirectory(os.path.abspath(out_dir))
   else:
     try:
       out_dir = constants.GetOutDirectory()
@@ -781,8 +780,7 @@
       pass
   if out_dir:
     build_vars = build_utils.ReadBuildVars()
-    tool_prefix = os.path.join(out_dir,
-                                build_vars['android_tool_prefix'])
+    tool_prefix = os.path.join(out_dir, build_vars['android_tool_prefix'])
   else:
     tool_prefix = ''
   return out_dir, tool_prefix
@@ -807,7 +805,7 @@
                          action='store_true',
                          dest='dump_sis',
                          help='Run dump-static-initializers.py to get the list'
-                         'of static initializers (slow).')
+                              'of static initializers (slow).')
   argparser.add_argument('-d', '--device',
                          help='Dummy option for perf runner.')
   argparser.add_argument('--estimate-patch-size',
@@ -827,10 +825,18 @@
 
   chartjson = _BASE_CHART.copy() if args.chartjson else None
   out_dir, tool_prefix = _ConfigOutDirAndToolsPrefix(args.out_dir)
+  if args.dump_sis and not out_dir:
+    argparser.error(
+        '--dump-static-initializers requires --chromium-output-directory')
+
   PrintApkAnalysis(args.apk, tool_prefix, chartjson=chartjson)
   _PrintDexAnalysis(args.apk, chartjson=chartjson)
-  _PrintStaticInitializerAnalysis(args.apk, tool_prefix, args.dump_sis,
-                                  out_dir, chartjson=chartjson)
+
+  si_count = AnalyzeStaticInitializers(
+      args.apk, tool_prefix, args.dump_sis, out_dir)
+  ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', si_count,
+                   'count')
+
   if args.estimate_patch_size:
     _PrintPatchSizeEstimate(args.apk, args.reference_apk_builder,
                             args.reference_apk_bucket, chartjson=chartjson)
diff --git a/build/android/stacktrace/README.md b/build/android/stacktrace/README.md
index fb4c035c..01062be4 100644
--- a/build/android/stacktrace/README.md
+++ b/build/android/stacktrace/README.md
@@ -7,7 +7,7 @@
 
 The second point here is what allows you to run:
 
-    adb logcat | out/Default/bin/java_deobfuscate
+    adb logcat | out/Default/bin/java_deobfuscate out/Default/apks/ChromePublic.apk.mapping
 
 And have it actually show output without logcat terminating.
 
diff --git a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
index 1402511..a828cb8 100644
--- a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
+++ b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
@@ -24,16 +24,20 @@
     // http://proguard.sourceforge.net/manual/retrace/usage.html.
     // But with the "at" part changed to "(?::|\bat)", to account for lines like:
     //     06-22 13:58:02.895  4674  4674 E THREAD_STATE:     bLA.a(PG:173)
+    // And .*=%c\s* added as the second subpattern to account for lines like:
+    //     INSTRUMENTATION_STATUS: class=bNs
     // Normal stack trace lines look like:
     // java.lang.RuntimeException: Intentional Java Crash
     //     at org.chromium.chrome.browser.tab.Tab.handleJavaCrash(Tab.java:682)
     //     at org.chromium.chrome.browser.tab.Tab.loadUrl(Tab.java:644)
     private static final String LINE_PARSE_REGEX =
-            "(?:.*?(?::|\\bat)\\s+%c\\.%m\\s*\\(%s(?::%l)?\\)\\s*)|(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)";
+            "(?:.*?(?::|\\bat)\\s+%c\\.%m\\s*\\(%s(?::%l)?\\)\\s*)|"
+            + "(?:.*=%c\\s*)|"
+            + "(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)";
 
     public static void main(String[] args) {
         if (args.length != 1) {
-            System.err.println("Usage: retrace Foo.apk.map < foo.log > bar.log");
+            System.err.println("Usage: java_deobfuscate Foo.apk.map < foo.log > bar.log");
             System.exit(1);
         }
 
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 01a0ec53..9060e825 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -332,7 +332,7 @@
   parser.add_argument(
       '--test-apk-incremental-install-json',
       type=os.path.realpath,
-      help='Path to install script for the test apk.')
+      help='Path to install json for the test apk.')
 
   filter_group = parser.add_mutually_exclusive_group()
   filter_group.add_argument(
@@ -383,6 +383,10 @@
       dest='set_asserts', action='store_false', default=True,
       help='Removes the dalvik.vm.enableassertions property')
   parser.add_argument(
+      '--enable-java-deobfuscation',
+      action='store_true',
+      help='Deobfuscate java stack traces in test output and logcat.')
+  parser.add_argument(
       '-E', '--exclude-annotation',
       dest='exclude_annotation_str',
       help='Comma-separated list of annotations. Exclude tests with these '
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps
index 573577e..cd1f494 100644
--- a/build/android/test_runner.pydeps
+++ b/build/android/test_runner.pydeps
@@ -174,6 +174,7 @@
 pylib/results/json_results.py
 pylib/results/report_results.py
 pylib/symbols/__init__.py
+pylib/symbols/deobfuscator.py
 pylib/symbols/stack_symbolizer.py
 pylib/utils/__init__.py
 pylib/utils/decorators.py
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 5b8e8458..2db4273 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -572,6 +572,9 @@
           "@FileArg($_rebased_apk_under_test_build_config:deps_info:enable_relocation_packing)",
         ]
       }
+      if (defined(invoker.proguard_enabled) && invoker.proguard_enabled) {
+        test_runner_args += [ "--enable-java-deobfuscation" ]
+      }
       if (emma_coverage) {
         # Set a default coverage output directory (can be overridden by user
         # passing the same flag).
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index ba5473f7..708f6e7 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1638,11 +1638,10 @@
     }
     final_dex_target_name = "${_template_name}__final_dex"
 
-    _final_apk_path = ""
     if (defined(invoker.final_apk_path)) {
       _final_apk_path = invoker.final_apk_path
-    } else if (defined(invoker.apk_name)) {
-      _final_apk_path = "$root_build_dir/apks/" + invoker.apk_name + ".apk"
+    } else {
+      _final_apk_path = "$root_build_dir/apks/${invoker.apk_name}.apk"
     }
     _final_apk_path_no_ext_list =
         process_file_template([ _final_apk_path ],
@@ -2138,6 +2137,12 @@
           "--input-paths=@FileArg($_rebased_build_config:proguard:input_paths)",
           "--classpath=@FileArg($_rebased_build_config:proguard:lib_paths)",
         ]
+        if (defined(invoker.proguard_config_exclusions)) {
+          _rebased_proguard_config_exclusions =
+              rebase_path(invoker.proguard_config_exclusions, root_build_dir)
+          args += [ "--proguard-config-exclusions=$_rebased_proguard_config_exclusions" ]
+        }
+
         if (defined(invoker.apk_under_test)) {
           deps += [
             "${invoker.apk_under_test}__build_config",
@@ -2630,6 +2635,7 @@
                                  "data_deps",
                                  "deps",
                                  "ignore_all_data_deps",
+                                 "proguard_enabled",
                                  "public_deps",
                                ])
         test_name = invoker.target_name
@@ -2680,6 +2686,15 @@
           proguard_configs = []
         }
         proguard_configs += [ "//testing/android/proguard_for_test.flags" ]
+        data_deps += [ "//build/android/stacktrace:java_deobfuscate" ]
+        if (defined(final_apk_path)) {
+          _final_apk_path = final_apk_path
+        } else {
+          _final_apk_path = "$root_build_dir/apks/${apk_name}.apk"
+        }
+        data = [
+          "$_final_apk_path.mapping",
+        ]
       }
 
       dist_ijar_path = _dist_ijar_path
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 9cba67e..4ab7826 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -276,6 +276,8 @@
     # and build system rebuild things when their commandline changes). Nothing
     # should ever read this define.
     defines += [ "CR_CLANG_REVISION=\"$clang_revision\"" ]
+
+    configs += [ "//build/config/coverage" ]
   }
 
   # Non-Mac Posix compiler flags setup.
diff --git a/build/config/coverage/BUILD.gn b/build/config/coverage/BUILD.gn
new file mode 100644
index 0000000..0bf1e96
--- /dev/null
+++ b/build/config/coverage/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/toolchain/toolchain.gni")
+
+declare_args() {
+  # Enable Clang's source-based code coverage.
+  use_clang_coverage = false
+}
+
+config("coverage") {
+  if (use_clang_coverage) {
+    cflags = [
+      "-fprofile-instr-generate",
+      "-fcoverage-mapping",
+      "-fno-use-cxa-atexit",
+    ]
+    ldflags = [ "-fprofile-instr-generate" ]
+  }
+}
diff --git a/build/config/dcheck_always_on.gni b/build/config/dcheck_always_on.gni
index b5eb503..60672cdf 100644
--- a/build/config/dcheck_always_on.gni
+++ b/build/config/dcheck_always_on.gni
@@ -2,10 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/sanitizers/sanitizers.gni")
-
 declare_args() {
   # Set to true to enable dcheck in Release builds.
-  # is_syzyasan defaults to logging/non-fatal DCHECKs - see crbug.com/596231.
-  dcheck_always_on = is_syzyasan
+  dcheck_always_on = false
 }
diff --git a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
index b95acd1..703aa550 100644
--- a/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -76,6 +76,8 @@
     "minidump/process_snapshot_minidump.cc",
     "minidump/process_snapshot_minidump.h",
     "module_snapshot.h",
+    "posix/timezone.cc",
+    "posix/timezone.h",
     "process_snapshot.h",
     "system_snapshot.h",
     "thread_snapshot.h",
@@ -110,6 +112,13 @@
     "win/thread_snapshot_win.cc",
     "win/thread_snapshot_win.h",
   ]
+
+  if (target_cpu == "x86" || target_cpu == "x64") {
+    sources += [
+      "x86/cpuid_reader.cc",
+      "x86/cpuid_reader.h",
+    ]
+  }
 }
 
 if (is_win) {
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 93a04ceb..c53c0285 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -183,12 +183,14 @@
     if verbose:
       print 'Copying %s to %s...' % (source, target)
     if os.path.exists(target):
-      # Make the file writable so that we can delete it now.
-      os.chmod(target, stat.S_IWRITE)
+      # Make the file writable so that we can delete it now, and keep it
+      # readable.
+      os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
       os.unlink(target)
     shutil.copy2(source, target)
-    # Make the file writable so that we can overwrite or delete it later.
-    os.chmod(target, stat.S_IWRITE)
+    # Make the file writable so that we can overwrite or delete it later,
+    # keep it readable.
+    os.chmod(target, stat.S_IWRITE | stat.S_IREAD)
 
 
 def _CopyUCRTRuntime(target_dir, source_dir, target_cpu, dll_pattern, suffix):
diff --git a/build/win/message_compiler.py b/build/win/message_compiler.py
index 7edfe6e2..3ee77c6 100644
--- a/build/win/message_compiler.py
+++ b/build/win/message_compiler.py
@@ -2,11 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
-# GN build, which can only run Python and not native binaries.
+# Runs the Microsoft Message Compiler (mc.exe).
 #
 # Usage: message_compiler.py <environment_file> [<args to mc.exe>*]
 
+import difflib
 import distutils.dir_util
 import filecmp
 import os
@@ -80,15 +80,27 @@
     # it generates an ANSI header, and includes broken versions of the message
     # text in the comment before the value. To work around this, for any invalid
     # // comment lines, we simply drop the line in the header after building it.
+    # Also, mc.exe apparently doesn't always write #define lines in
+    # deterministic order, so manually sort each block of #defines.
     if header_dir:
       header_file = os.path.join(
           header_dir, os.path.splitext(os.path.basename(input_file))[0] + '.h')
       header_contents = []
       with open(header_file, 'rb') as f:
+        define_block = []  # The current contiguous block of #defines.
         for line in f.readlines():
           if line.startswith('//') and '?' in line:
             continue
+          if line.startswith('#define '):
+            define_block.append(line)
+            continue
+          # On the first non-#define line, emit the sorted preceding #define
+          # block.
+          header_contents += sorted(define_block, key=lambda s: s.split()[-1])
+          define_block = []
           header_contents.append(line)
+        # If the .h file ends with a #define block, flush the final block.
+        header_contents += sorted(define_block, key=lambda s: s.split()[-1])
       with open(header_file, 'wb') as f:
         f.write(''.join(header_contents))
 
@@ -96,8 +108,16 @@
     # in tmp_dir to the checked-in outputs.
     diff = filecmp.dircmp(tmp_dir, source)
     if diff.diff_files or set(diff.left_list) != set(diff.right_list):
-      print >>sys.stderr, 'mc.exe output different from files in %s, see %s' % (
-          source, tmp_dir)
+      print 'mc.exe output different from files in %s, see %s' % (source,
+                                                                  tmp_dir)
+      diff.report()
+      for f in diff.diff_files:
+        if f.endswith('.bin'): continue
+        fromfile = os.path.join(source, f)
+        tofile = os.path.join(tmp_dir, f)
+        print ''.join(difflib.unified_diff(open(fromfile, 'U').readlines(),
+                                           open(tofile, 'U').readlines(),
+                                           fromfile, tofile))
       delete_tmp_dir = False
       sys.exit(1)
   except subprocess.CalledProcessError as e:
diff --git a/build/win/reorder-imports.py b/build/win/reorder-imports.py
index 00a69d75d..c4b294d 100755
--- a/build/win/reorder-imports.py
+++ b/build/win/reorder-imports.py
@@ -10,28 +10,67 @@
 import subprocess
 import sys
 
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..',
+                                'third_party', 'pefile'))
+import pefile
+
 def reorder_imports(input_dir, output_dir, architecture):
-  """Run swapimports.exe on the initial chrome.exe, and write to the output
-  directory. Also copy over any related files that might be needed
+  """Swap chrome_elf.dll to be the first import of chrome.exe.
+  Also copy over any related files that might be needed
   (pdbs, manifests etc.).
   """
+  # TODO(thakis): See if there is a reliable way to write the
+  # correct executable in the first place, so that this script
+  # only needs to verify that and not write a whole new exe.
 
   input_image = os.path.join(input_dir, 'chrome.exe')
   output_image = os.path.join(output_dir, 'chrome.exe')
 
-  swap_exe = os.path.join(
-    __file__,
-    '..\\..\\..\\third_party\\syzygy\\binaries\\exe\\swapimport.exe')
-
-  args = [swap_exe, '--input-image=%s' % input_image,
-      '--output-image=%s' % output_image, '--overwrite', '--no-logo']
-
+  # pefile mmap()s the whole executable, and then parses parts of
+  # it into python data structures for ease of processing.
+  # To write the file again, only the mmap'd data is written back,
+  # so modifying the parsed python objects generally has no effect.
+  # However, parsed raw data ends up in pe.Structure instances,
+  # and these all get serialized back when the file gets written.
+  # So things that are in a Structure must have their data set
+  # through the Structure, while other data must bet set through
+  # the set_bytes_*() methods.
+  pe = pefile.PE(input_image, fast_load=True)
   if architecture == 'x64':
-    args.append('--x64');
+    assert pe.PE_TYPE == pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS
+  else:
+    assert pe.PE_TYPE == pefile.OPTIONAL_HEADER_MAGIC_PE
 
-  args.append('chrome_elf.dll');
+  pe.parse_data_directories(directories=[
+      pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_IMPORT']])
 
-  subprocess.check_call(args)
+  found_elf = False
+  for i, peimport in enumerate(pe.DIRECTORY_ENTRY_IMPORT):
+    if peimport.dll.lower() == 'chrome_elf.dll':
+      assert not found_elf, 'only one chrome_elf.dll import expected'
+      found_elf = True
+      if i > 0:
+        swap = pe.DIRECTORY_ENTRY_IMPORT[0]
+
+        # Morally we want to swap peimport.struct and swap.struct here,
+        # but the pe module doesn't expose a public method on Structure
+        # to get all data of a Structure without explicitly listing all
+        # field names.
+        # NB: OriginalFirstThunk and Characteristics are an union both at
+        # offset 0, handling just one of them is enough.
+        peimport.struct.OriginalFirstThunk, swap.struct.OriginalFirstThunk = \
+            swap.struct.OriginalFirstThunk, peimport.struct.OriginalFirstThunk
+        peimport.struct.TimeDateStamp, swap.struct.TimeDateStamp = \
+            swap.struct.TimeDateStamp, peimport.struct.TimeDateStamp
+        peimport.struct.ForwarderChain, swap.struct.ForwarderChain = \
+            swap.struct.ForwarderChain, peimport.struct.ForwarderChain
+        peimport.struct.Name, swap.struct.Name = \
+            swap.struct.Name, peimport.struct.Name
+        peimport.struct.FirstThunk, swap.struct.FirstThunk = \
+            swap.struct.FirstThunk, peimport.struct.FirstThunk
+  assert found_elf, 'chrome_elf.dll import not found'
+
+  pe.write(filename=output_image)
 
   for fname in glob.iglob(os.path.join(input_dir, 'chrome.exe.*')):
     shutil.copy(fname, os.path.join(output_dir, os.path.basename(fname)))
diff --git a/cc/ipc/BUILD.gn b/cc/ipc/BUILD.gn
index fa26b2c..999264d 100644
--- a/cc/ipc/BUILD.gn
+++ b/cc/ipc/BUILD.gn
@@ -40,7 +40,6 @@
 mojom("interfaces") {
   sources = [
     "copy_output_result.mojom",
-    "frame_sink_id.mojom",
     "local_surface_id.mojom",
     "texture_mailbox.mojom",
     "texture_mailbox_releaser.mojom",
diff --git a/cc/ipc/cc_param_traits_unittest.cc b/cc/ipc/cc_param_traits_unittest.cc
index 05c3f5d..e686df07 100644
--- a/cc/ipc/cc_param_traits_unittest.cc
+++ b/cc/ipc/cc_param_traits_unittest.cc
@@ -318,8 +318,9 @@
 
   SharedQuadState* shared_state1_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_rect1, arbitrary_rect1,
-                           arbitrary_rect2, arbitrary_bool1, arbitrary_float1,
-                           arbitrary_blend_mode1, arbitrary_context_id1);
+                           arbitrary_rect2, arbitrary_bool1, arbitrary_bool2,
+                           arbitrary_float1, arbitrary_blend_mode1,
+                           arbitrary_context_id1);
 
   std::unique_ptr<RenderPass> pass_cmp = RenderPass::Create();
   pass_cmp->SetAll(root_id, arbitrary_rect1, arbitrary_rect2, arbitrary_matrix1,
@@ -340,8 +341,9 @@
 
   SharedQuadState* shared_state2_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state2_in->SetAll(arbitrary_matrix2, arbitrary_rect2, arbitrary_rect2,
-                           arbitrary_rect3, arbitrary_bool1, arbitrary_float2,
-                           arbitrary_blend_mode2, arbitrary_context_id2);
+                           arbitrary_rect3, arbitrary_bool1, arbitrary_bool1,
+                           arbitrary_float2, arbitrary_blend_mode2,
+                           arbitrary_context_id2);
   SharedQuadState* shared_state2_cmp =
       pass_cmp->CreateAndAppendSharedQuadState();
   *shared_state2_cmp = *shared_state2_in;
@@ -358,8 +360,9 @@
 
   SharedQuadState* shared_state3_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state3_in->SetAll(arbitrary_matrix1, arbitrary_rect3, arbitrary_rect3,
-                           arbitrary_rect1, arbitrary_bool1, arbitrary_float3,
-                           arbitrary_blend_mode3, arbitrary_context_id3);
+                           arbitrary_rect1, arbitrary_bool1, arbitrary_bool2,
+                           arbitrary_float3, arbitrary_blend_mode3,
+                           arbitrary_context_id3);
   SharedQuadState* shared_state3_cmp =
       pass_cmp->CreateAndAppendSharedQuadState();
   *shared_state3_cmp = *shared_state3_in;
@@ -501,7 +504,8 @@
   // The first SharedQuadState is used.
   SharedQuadState* shared_state1_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state1_in->SetAll(gfx::Transform(), gfx::Rect(1, 1), gfx::Rect(),
-                           gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
+                           gfx::Rect(), false, true, 1.f, SkBlendMode::kSrcOver,
+                           0);
 
   SolidColorDrawQuad* quad1 =
       pass_in->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -511,16 +515,19 @@
   // The second and third SharedQuadStates are not used.
   SharedQuadState* shared_state2_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state2_in->SetAll(gfx::Transform(), gfx::Rect(2, 2), gfx::Rect(),
-                           gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
+                           gfx::Rect(), false, true, 1.f, SkBlendMode::kSrcOver,
+                           0);
 
   SharedQuadState* shared_state3_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state3_in->SetAll(gfx::Transform(), gfx::Rect(3, 3), gfx::Rect(),
-                           gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
+                           gfx::Rect(), false, true, 1.f, SkBlendMode::kSrcOver,
+                           0);
 
   // The fourth SharedQuadState is used.
   SharedQuadState* shared_state4_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state4_in->SetAll(gfx::Transform(), gfx::Rect(4, 4), gfx::Rect(),
-                           gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
+                           gfx::Rect(), false, true, 1.f, SkBlendMode::kSrcOver,
+                           0);
 
   SolidColorDrawQuad* quad2 =
       pass_in->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -530,7 +537,8 @@
   // The fifth is not used again.
   SharedQuadState* shared_state5_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state5_in->SetAll(gfx::Transform(), gfx::Rect(5, 5), gfx::Rect(),
-                           gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
+                           gfx::Rect(), false, true, 1.f, SkBlendMode::kSrcOver,
+                           0);
 
   // 5 SharedQuadStates go in.
   ASSERT_EQ(5u, pass_in->shared_quad_state_list.size());
diff --git a/cc/ipc/cc_serialization_perftest.cc b/cc/ipc/cc_serialization_perftest.cc
index 9a92b59..ed66495 100644
--- a/cc/ipc/cc_serialization_perftest.cc
+++ b/cc/ipc/cc_serialization_perftest.cc
@@ -311,10 +311,10 @@
     for (uint32_t i = 0; i < 10; ++i) {
       viz::SharedQuadState* shared_state1_in =
           pass_in->CreateAndAppendSharedQuadState();
-      shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_rect1,
-                               arbitrary_rect1, arbitrary_rect2,
-                               arbitrary_bool1, arbitrary_float1,
-                               arbitrary_blend_mode1, arbitrary_context_id1);
+      shared_state1_in->SetAll(
+          arbitrary_matrix1, arbitrary_rect1, arbitrary_rect1, arbitrary_rect2,
+          arbitrary_bool1, arbitrary_bool1, arbitrary_float1,
+          arbitrary_blend_mode1, arbitrary_context_id1);
 
       TextureDrawQuad* texture_in =
           pass_in->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -357,10 +357,10 @@
     for (uint32_t i = 0; i < 10; ++i) {
       viz::SharedQuadState* shared_state2_in =
           pass_in->CreateAndAppendSharedQuadState();
-      shared_state2_in->SetAll(arbitrary_matrix2, arbitrary_rect2,
-                               arbitrary_rect2, arbitrary_rect3,
-                               arbitrary_bool1, arbitrary_float2,
-                               arbitrary_blend_mode2, arbitrary_context_id2);
+      shared_state2_in->SetAll(
+          arbitrary_matrix2, arbitrary_rect2, arbitrary_rect2, arbitrary_rect3,
+          arbitrary_bool1, arbitrary_bool1, arbitrary_float2,
+          arbitrary_blend_mode2, arbitrary_context_id2);
       for (uint32_t j = 0; j < 6; ++j) {
         TileDrawQuad* tile_in =
             pass_in->CreateAndAppendDrawQuad<TileDrawQuad>();
@@ -375,10 +375,10 @@
     for (uint32_t i = 0; i < 5; ++i) {
       viz::SharedQuadState* shared_state3_in =
           pass_in->CreateAndAppendSharedQuadState();
-      shared_state3_in->SetAll(arbitrary_matrix1, arbitrary_rect3,
-                               arbitrary_rect3, arbitrary_rect1,
-                               arbitrary_bool1, arbitrary_float3,
-                               arbitrary_blend_mode3, arbitrary_context_id3);
+      shared_state3_in->SetAll(
+          arbitrary_matrix1, arbitrary_rect3, arbitrary_rect3, arbitrary_rect1,
+          arbitrary_bool1, arbitrary_bool1, arbitrary_float3,
+          arbitrary_blend_mode3, arbitrary_context_id3);
       for (uint32_t j = 0; j < 5; ++j) {
         SolidColorDrawQuad* solidcolor_in =
             pass_in->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
diff --git a/cc/ipc/frame_sink_id.mojom b/cc/ipc/frame_sink_id.mojom
deleted file mode 100644
index b8fb286f..0000000
--- a/cc/ipc/frame_sink_id.mojom
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module cc.mojom;
-
-struct FrameSinkId {
-  uint32 client_id;
-  uint32 sink_id;
-};
diff --git a/cc/ipc/frame_sink_id.typemap b/cc/ipc/frame_sink_id.typemap
deleted file mode 100644
index c7e3c5d..0000000
--- a/cc/ipc/frame_sink_id.typemap
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//cc/ipc/frame_sink_id.mojom"
-public_headers = [ "//components/viz/common/surfaces/frame_sink_id.h" ]
-deps = [
-  "//components/viz/common",
-]
-traits_headers = [ "//cc/ipc/frame_sink_id_struct_traits.h" ]
-type_mappings = [ "cc.mojom.FrameSinkId=viz::FrameSinkId" ]
diff --git a/cc/ipc/frame_sink_id_struct_traits.h b/cc/ipc/frame_sink_id_struct_traits.h
deleted file mode 100644
index 1acacf03..0000000
--- a/cc/ipc/frame_sink_id_struct_traits.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_IPC_FRAME_SINK_ID_STRUCT_TRAITS_H_
-#define CC_IPC_FRAME_SINK_ID_STRUCT_TRAITS_H_
-
-#include "cc/ipc/frame_sink_id.mojom-shared.h"
-#include "components/viz/common/surfaces/frame_sink_id.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<cc::mojom::FrameSinkIdDataView, viz::FrameSinkId> {
-  static uint32_t client_id(const viz::FrameSinkId& frame_sink_id) {
-    return frame_sink_id.client_id();
-  }
-
-  static uint32_t sink_id(const viz::FrameSinkId& frame_sink_id) {
-    return frame_sink_id.sink_id();
-  }
-
-  static bool Read(cc::mojom::FrameSinkIdDataView data, viz::FrameSinkId* out) {
-    *out = viz::FrameSinkId(data.client_id(), data.sink_id());
-    return true;
-  }
-};
-
-}  // namespace mojo
-
-#endif  // CC_IPC_FRAME_SINK_ID_STRUCT_TRAITS_H_
diff --git a/cc/ipc/typemaps.gni b/cc/ipc/typemaps.gni
index 7833d25..97b37738 100644
--- a/cc/ipc/typemaps.gni
+++ b/cc/ipc/typemaps.gni
@@ -4,7 +4,6 @@
 
 typemaps = [
   "//cc/ipc/copy_output_result.typemap",
-  "//cc/ipc/frame_sink_id.typemap",
   "//cc/ipc/local_surface_id.typemap",
   "//cc/ipc/texture_mailbox.typemap",
 ]
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 6a37870..4cbe2d2 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -137,7 +137,7 @@
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
   PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_,
-                                internal_contents_scale_);
+                                internal_contents_scale_, contents_opaque());
 
   gfx::Rect quad_rect(internal_content_bounds_);
   bool needs_blending = contents_opaque() ? false : true;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index c3d251a..07094470c 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -142,17 +142,19 @@
   scroll_tree_index_ = index;
 }
 
-void LayerImpl::PopulateSharedQuadState(viz::SharedQuadState* state) const {
+void LayerImpl::PopulateSharedQuadState(viz::SharedQuadState* state,
+                                        bool contents_opaque) const {
   state->SetAll(draw_properties_.target_space_transform, gfx::Rect(bounds()),
                 draw_properties_.visible_layer_rect, draw_properties_.clip_rect,
-                draw_properties_.is_clipped, draw_properties_.opacity,
-                SkBlendMode::kSrcOver, GetSortingContextId());
+                draw_properties_.is_clipped, contents_opaque,
+                draw_properties_.opacity, SkBlendMode::kSrcOver,
+                GetSortingContextId());
 }
 
-void LayerImpl::PopulateScaledSharedQuadState(
-    viz::SharedQuadState* state,
-    float layer_to_content_scale_x,
-    float layer_to_content_scale_y) const {
+void LayerImpl::PopulateScaledSharedQuadState(viz::SharedQuadState* state,
+                                              float layer_to_content_scale_x,
+                                              float layer_to_content_scale_y,
+                                              bool contents_opaque) const {
   gfx::Transform scaled_draw_transform =
       draw_properties_.target_space_transform;
   scaled_draw_transform.Scale(SK_MScalar1 / layer_to_content_scale_x,
@@ -165,8 +167,9 @@
 
   state->SetAll(scaled_draw_transform, gfx::Rect(scaled_bounds),
                 scaled_visible_layer_rect, draw_properties().clip_rect,
-                draw_properties().is_clipped, draw_properties().opacity,
-                SkBlendMode::kSrcOver, GetSortingContextId());
+                draw_properties().is_clipped, contents_opaque,
+                draw_properties().opacity, SkBlendMode::kSrcOver,
+                GetSortingContextId());
 }
 
 bool LayerImpl::WillDraw(DrawMode draw_mode,
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 5e207c6..860bbdb 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -125,10 +125,12 @@
 
   LayerTreeImpl* layer_tree_impl() const { return layer_tree_impl_; }
 
-  void PopulateSharedQuadState(viz::SharedQuadState* state) const;
+  void PopulateSharedQuadState(viz::SharedQuadState* state,
+                               bool contents_opaque) const;
   void PopulateScaledSharedQuadState(viz::SharedQuadState* state,
                                      float layer_to_content_scale_x,
-                                     float layer_to_content_scale_y) const;
+                                     float layer_to_content_scale_y,
+                                     bool contents_opaque) const;
   // WillDraw must be called before AppendQuads. If WillDraw returns false,
   // AppendQuads and DidDraw will not be called. If WillDraw returns true,
   // DidDraw is guaranteed to be called before another WillDraw or before
diff --git a/cc/layers/nine_patch_layer_impl.cc b/cc/layers/nine_patch_layer_impl.cc
index dca9aeb..adab312 100644
--- a/cc/layers/nine_patch_layer_impl.cc
+++ b/cc/layers/nine_patch_layer_impl.cc
@@ -55,7 +55,10 @@
   quad_generator_.CheckGeometryLimitations();
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  bool are_contents_opaque =
+      contents_opaque() ||
+      layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_);
+  PopulateSharedQuadState(shared_quad_state, are_contents_opaque);
 
   AppendDebugBorderQuad(render_pass, bounds(), shared_quad_state,
                         append_quads_data);
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc
index 7d6636bd..8deed66c 100644
--- a/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -83,6 +83,8 @@
 
     EXPECT_TRUE(visible_layer_rect.Contains(quad_rect)) << iter.index();
     EXPECT_TRUE(layer_remaining.Contains(quad_rect)) << iter.index();
+    EXPECT_EQ(iter->needs_blending,
+              !iter->shared_quad_state->are_contents_opaque);
     layer_remaining.Subtract(Region(quad_rect));
   }
 
@@ -191,6 +193,8 @@
 
     EXPECT_TRUE(visible_layer_rect.Contains(quad_rect)) << iter.index();
     EXPECT_TRUE(layer_remaining.Contains(quad_rect)) << iter.index();
+    EXPECT_EQ(iter->needs_blending,
+              !iter->shared_quad_state->are_contents_opaque);
     layer_remaining.Subtract(Region(quad_rect));
   }
 
diff --git a/cc/layers/painted_overlay_scrollbar_layer_impl.cc b/cc/layers/painted_overlay_scrollbar_layer_impl.cc
index e525a30..95e793e3 100644
--- a/cc/layers/painted_overlay_scrollbar_layer_impl.cc
+++ b/cc/layers/painted_overlay_scrollbar_layer_impl.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "cc/layers/painted_overlay_scrollbar_layer_impl.h"
+#include "cc/trees/layer_tree_impl.h"
 
 namespace cc {
 
@@ -91,7 +92,10 @@
 
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  bool are_contents_opaque =
+      contents_opaque() ||
+      layer_tree_impl()->IsUIResourceOpaque(thumb_ui_resource_id_);
+  PopulateSharedQuadState(shared_quad_state, are_contents_opaque);
 
   AppendDebugBorderQuad(render_pass, bounds(), shared_quad_state,
                         append_quads_data);
diff --git a/cc/layers/painted_scrollbar_layer_impl.cc b/cc/layers/painted_scrollbar_layer_impl.cc
index 73dbaf3..81f8cf9 100644
--- a/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/cc/layers/painted_scrollbar_layer_impl.cc
@@ -95,7 +95,7 @@
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
   PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_,
-                                internal_contents_scale_);
+                                internal_contents_scale_, contents_opaque());
 
   AppendDebugBorderQuad(render_pass, internal_content_bounds_,
                         shared_quad_state, append_quads_data);
diff --git a/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
index e3af2a87..f033bf96 100644
--- a/cc/layers/painted_scrollbar_layer_impl_unittest.cc
+++ b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -91,6 +91,8 @@
     gfx::Rect scaled_thumb_rect = gfx::ScaleToEnclosingRect(thumb_rect, scale);
     EXPECT_EQ(track_quad->rect.ToString(),
               gfx::Rect(scaled_layer_size).ToString());
+    EXPECT_EQ(scrollbar_layer_impl->contents_opaque(),
+              track_quad->shared_quad_state->are_contents_opaque);
     EXPECT_EQ(track_quad->visible_rect.ToString(),
               gfx::Rect(scaled_layer_size).ToString());
     EXPECT_FALSE(track_quad->needs_blending);
@@ -98,6 +100,8 @@
     EXPECT_EQ(thumb_quad->visible_rect.ToString(),
               scaled_thumb_rect.ToString());
     EXPECT_TRUE(thumb_quad->needs_blending);
+    EXPECT_EQ(scrollbar_layer_impl->contents_opaque(),
+              thumb_quad->shared_quad_state->are_contents_opaque);
     for (size_t i = 0; i < 4; ++i) {
       EXPECT_EQ(thumb_opacity, thumb_quad->vertex_opacity[i]);
       EXPECT_EQ(1.f, track_quad->vertex_opacity[i]);
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 53f01877..5e96ae20 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -207,7 +207,7 @@
       render_pass->CreateAndAppendSharedQuadState();
 
   if (raster_source_->IsSolidColor()) {
-    PopulateSharedQuadState(shared_quad_state);
+    PopulateSharedQuadState(shared_quad_state, contents_opaque());
 
     AppendDebugBorderQuad(
         render_pass, bounds(), shared_quad_state, append_quads_data);
@@ -223,7 +223,7 @@
       layer_tree_impl() ? layer_tree_impl()->device_scale_factor() : 1;
   float max_contents_scale = MaximumTilingContentsScale();
   PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale,
-                                max_contents_scale);
+                                max_contents_scale, contents_opaque());
   Occlusion scaled_occlusion;
   if (mask_type_ == Layer::LayerMaskType::NOT_MASK) {
     scaled_occlusion =
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index cc8e860..f8d81187 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -738,8 +738,9 @@
   active_layer()->draw_properties().visible_layer_rect =
       gfx::Rect(layer_bounds);
   viz::SharedQuadState state;
-  active_layer()->PopulateScaledSharedQuadState(&state, adjusted_scale,
-                                                adjusted_scale);
+  active_layer()->PopulateScaledSharedQuadState(
+      &state, adjusted_scale, adjusted_scale,
+      active_layer()->contents_opaque());
 }
 
 TEST_F(PictureLayerImplTest, PinchGestureTilings) {
@@ -1528,6 +1529,8 @@
             render_pass->quad_list.front()->material);
   EXPECT_EQ(render_pass->quad_list.front()->rect, layer_rect);
   EXPECT_FALSE(render_pass->quad_list.front()->needs_blending);
+  EXPECT_TRUE(
+      render_pass->quad_list.front()->shared_quad_state->are_contents_opaque);
   EXPECT_EQ(render_pass->quad_list.front()->visible_rect, layer_rect);
 }
 
@@ -1564,6 +1567,7 @@
             render_pass->quad_list.front()->material);
   const DrawQuad* quad = render_pass->quad_list.front();
   EXPECT_EQ(quad_visible, quad->rect);
+  EXPECT_TRUE(quad->shared_quad_state->are_contents_opaque);
   EXPECT_EQ(quad_visible, quad->visible_rect);
   EXPECT_FALSE(quad->needs_blending);
 }
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 1929681..192366d 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -383,11 +383,12 @@
   int sorting_context_id =
       property_trees->transform_tree.Node(TransformTreeIndex())
           ->sorting_context_id;
+  bool contents_opaque = false;
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(
       draw_transform(), content_rect(), content_rect(),
-      draw_properties_.clip_rect, draw_properties_.is_clipped,
+      draw_properties_.clip_rect, draw_properties_.is_clipped, contents_opaque,
       draw_properties_.draw_opacity, BlendMode(), sorting_context_id);
 
   if (layer_tree_impl_->debug_state().show_debug_borders.test(
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc
index 0bfef29..c4ffd4a3 100644
--- a/cc/layers/render_surface_unittest.cc
+++ b/cc/layers/render_surface_unittest.cc
@@ -63,7 +63,7 @@
         render_pass->CreateAndAppendSharedQuadState();
     float max_contents_scale = 1.f;
     PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale,
-                                  max_contents_scale);
+                                  max_contents_scale, contents_opaque());
     bool needs_blending = false;
     for (const auto& rect : quad_rects_) {
       TileDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
diff --git a/cc/layers/solid_color_layer_impl.cc b/cc/layers/solid_color_layer_impl.cc
index b6f8811..9558d75 100644
--- a/cc/layers/solid_color_layer_impl.cc
+++ b/cc/layers/solid_color_layer_impl.cc
@@ -72,7 +72,7 @@
     AppendQuadsData* append_quads_data) {
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  PopulateSharedQuadState(shared_quad_state, contents_opaque());
 
   AppendDebugBorderQuad(render_pass, bounds(), shared_quad_state,
                         append_quads_data);
diff --git a/cc/layers/solid_color_layer_impl_unittest.cc b/cc/layers/solid_color_layer_impl_unittest.cc
index 7535ce2..5776f65 100644
--- a/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/cc/layers/solid_color_layer_impl_unittest.cc
@@ -209,6 +209,8 @@
 
     ASSERT_EQ(render_pass->quad_list.size(), 1U);
     EXPECT_FALSE(render_pass->quad_list.front()->needs_blending);
+    EXPECT_TRUE(
+        render_pass->quad_list.front()->shared_quad_state->are_contents_opaque);
   }
 
   EXPECT_TRUE(layer->contents_opaque());
@@ -234,6 +236,8 @@
 
     ASSERT_EQ(render_pass->quad_list.size(), 1U);
     EXPECT_TRUE(render_pass->quad_list.front()->needs_blending);
+    EXPECT_FALSE(
+        render_pass->quad_list.front()->shared_quad_state->are_contents_opaque);
   }
 }
 
diff --git a/cc/layers/solid_color_scrollbar_layer_impl.cc b/cc/layers/solid_color_scrollbar_layer_impl.cc
index 3ff4e32..a0265fd 100644
--- a/cc/layers/solid_color_scrollbar_layer_impl.cc
+++ b/cc/layers/solid_color_scrollbar_layer_impl.cc
@@ -96,7 +96,7 @@
     AppendQuadsData* append_quads_data) {
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  PopulateSharedQuadState(shared_quad_state, contents_opaque());
 
   AppendDebugBorderQuad(render_pass, bounds(), shared_quad_state,
                         append_quads_data);
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index 315fdf6..fac891f 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -133,7 +133,7 @@
   if (!shared_quad_state) {
     shared_quad_state = render_pass->CreateAndAppendSharedQuadState();
     PopulateScaledSharedQuadState(shared_quad_state, layer_to_content_scale_x,
-                                  layer_to_content_scale_y);
+                                  layer_to_content_scale_y, contents_opaque());
   }
   if (common_shared_quad_state)
     *common_shared_quad_state = shared_quad_state;
@@ -159,7 +159,7 @@
 
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  PopulateSharedQuadState(shared_quad_state, contents_opaque());
 
   SkColor color;
   float border_width;
diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc
index 15d999ed..5da8480 100644
--- a/cc/layers/texture_layer_impl.cc
+++ b/cc/layers/texture_layer_impl.cc
@@ -63,7 +63,6 @@
 
 void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
   LayerImpl::PushPropertiesTo(layer);
-
   TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
   texture_layer->SetFlipped(flipped_);
   texture_layer->SetUVTopLeft(uv_top_left_);
@@ -148,22 +147,23 @@
                                    AppendQuadsData* append_quads_data) {
   DCHECK(external_texture_resource_ || valid_texture_copy_);
 
+  SkColor bg_color =
+      blend_background_color_ ? background_color() : SK_ColorTRANSPARENT;
+  bool are_contents_opaque =
+      contents_opaque() || (SkColorGetA(bg_color) == 0xFF);
+
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  PopulateSharedQuadState(shared_quad_state, are_contents_opaque);
 
   AppendDebugBorderQuad(render_pass, bounds(), shared_quad_state,
                         append_quads_data);
 
-  SkColor bg_color = blend_background_color_ ?
-      background_color() : SK_ColorTRANSPARENT;
-  bool opaque = contents_opaque() || (SkColorGetA(bg_color) == 0xFF);
-
   gfx::Rect quad_rect(bounds());
   gfx::Rect visible_quad_rect =
       draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
           quad_rect);
-  bool needs_blending = !opaque;
+  bool needs_blending = !are_contents_opaque;
   if (visible_quad_rect.IsEmpty())
     return;
 
diff --git a/cc/layers/ui_resource_layer_impl.cc b/cc/layers/ui_resource_layer_impl.cc
index 33ed81d..4790ec3 100644
--- a/cc/layers/ui_resource_layer_impl.cc
+++ b/cc/layers/ui_resource_layer_impl.cc
@@ -96,7 +96,10 @@
     AppendQuadsData* append_quads_data) {
   viz::SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  bool are_contents_opaque =
+      layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_) ||
+      contents_opaque();
+  PopulateSharedQuadState(shared_quad_state, are_contents_opaque);
 
   AppendDebugBorderQuad(render_pass, bounds(), shared_quad_state,
                         append_quads_data);
@@ -116,11 +119,8 @@
 
   DCHECK(!bounds().IsEmpty());
 
-  bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_) ||
-                contents_opaque();
-
   gfx::Rect quad_rect(bounds());
-  bool needs_blending = opaque ? false : true;
+  bool needs_blending = are_contents_opaque ? false : true;
   gfx::Rect visible_quad_rect =
       draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
           quad_rect);
diff --git a/cc/layers/ui_resource_layer_impl_unittest.cc b/cc/layers/ui_resource_layer_impl_unittest.cc
index cb702946..9b302eef 100644
--- a/cc/layers/ui_resource_layer_impl_unittest.cc
+++ b/cc/layers/ui_resource_layer_impl_unittest.cc
@@ -110,6 +110,8 @@
   const QuadList& quads = render_pass->quad_list;
   EXPECT_GE(quads.size(), (size_t)0);
   EXPECT_EQ(needs_blending, quads.front()->needs_blending);
+  EXPECT_EQ(quads.front()->needs_blending,
+            !quads.front()->shared_quad_state->are_contents_opaque);
 
   host_impl->active_tree()->DetachLayers();
 }
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index ce3a483c..bc151eb 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -171,8 +171,8 @@
       render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(transform, gfx::Rect(rotated_size),
                             visible_layer_rect(), clip_rect(), is_clipped(),
-                            draw_opacity(), SkBlendMode::kSrcOver,
-                            GetSortingContextId());
+                            contents_opaque(), draw_opacity(),
+                            SkBlendMode::kSrcOver, GetSortingContextId());
 
   AppendDebugBorderQuad(
       render_pass, rotated_size, shared_quad_state, append_quads_data);
diff --git a/cc/output/dc_layer_overlay.cc b/cc/output/dc_layer_overlay.cc
index 51f120d1..e1602f19 100644
--- a/cc/output/dc_layer_overlay.cc
+++ b/cc/output/dc_layer_overlay.cc
@@ -200,7 +200,7 @@
         punch_through.opacity * original_shared_quad_state->opacity;
     new_shared_quad_state->SetAll(new_transform, punch_through.rect,
                                   punch_through.rect, punch_through.rect, false,
-                                  new_opacity, SkBlendMode::kDstOut, 0);
+                                  true, new_opacity, SkBlendMode::kDstOut, 0);
     SolidColorDrawQuad* solid_quad = static_cast<SolidColorDrawQuad*>(*it);
     solid_quad->SetAll(new_shared_quad_state, punch_through.rect,
                        punch_through.rect, false, 0xff000000, true);
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index 994dfab..dcc66777 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -68,13 +68,14 @@
   const gfx::Rect visible_layer_rect = rect;
   const gfx::Rect clip_rect = rect;
   const bool is_clipped = false;
+  const bool are_contents_opaque = false;
   const float opacity = 1.0f;
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   int sorting_context_id = 0;
   SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                       clip_rect, is_clipped, opacity, blend_mode,
-                       sorting_context_id);
+                       clip_rect, is_clipped, are_contents_opaque, opacity,
+                       blend_mode, sorting_context_id);
   return shared_state;
 }
 
@@ -86,13 +87,14 @@
   const gfx::Rect layer_rect = rect;
   const gfx::Rect visible_layer_rect = clip_rect;
   const bool is_clipped = true;
+  const bool are_contents_opaque = false;
   const float opacity = 1.0f;
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   int sorting_context_id = 0;
   SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                       clip_rect, is_clipped, opacity, blend_mode,
-                       sorting_context_id);
+                       clip_rect, is_clipped, are_contents_opaque, opacity,
+                       blend_mode, sorting_context_id);
   return shared_state;
 }
 
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index 066b186..d643d82 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -105,7 +105,8 @@
   viz::SharedQuadState* shared_quad_state =
       root_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
-                            outer_rect, false, 1.0, SkBlendMode::kSrcOver, 0);
+                            outer_rect, false, true, 1.0, SkBlendMode::kSrcOver,
+                            0);
   SolidColorDrawQuad* inner_quad =
       root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
   inner_quad->SetNew(
@@ -172,7 +173,8 @@
   viz::SharedQuadState* shared_quad_state =
       root_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
-                            outer_rect, false, 1.0, SkBlendMode::kSrcOver, 0);
+                            outer_rect, false, true, 1.0, SkBlendMode::kSrcOver,
+                            0);
   TileDrawQuad* inner_quad =
       root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
   inner_quad->SetNew(shared_quad_state, inner_rect, inner_rect, needs_blending,
@@ -233,7 +235,7 @@
   viz::SharedQuadState* shared_quad_state =
       root_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), tile_rect, tile_rect, tile_rect,
-                            false, 1.0, SkBlendMode::kSrcOver, 0);
+                            false, true, 1.0, SkBlendMode::kSrcOver, 0);
   TileDrawQuad* quad =
       root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
   quad->SetNew(shared_quad_state, tile_rect, tile_rect, needs_blending,
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn
index a3ef3d0..387800c5 100644
--- a/cc/paint/BUILD.gn
+++ b/cc/paint/BUILD.gn
@@ -16,6 +16,7 @@
     "display_item_list.h",
     "draw_image.cc",
     "draw_image.h",
+    "image_animation_count.h",
     "image_id.h",
     "image_provider.cc",
     "image_provider.h",
diff --git a/cc/paint/image_animation_count.h b/cc/paint/image_animation_count.h
new file mode 100644
index 0000000..be39f0a
--- /dev/null
+++ b/cc/paint/image_animation_count.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_IMAGE_ANIMATION_COUNT_H_
+#define CC_PAINT_IMAGE_ANIMATION_COUNT_H_
+
+namespace cc {
+
+// GIF and WebP support animation. The explanation below is in terms of GIF,
+// but the same constants are used for WebP, too.
+// GIFs have an optional 16-bit unsigned loop count that describes how an
+// animated GIF should be cycled.  If the loop count is absent, the animation
+// cycles once; if it is 0, the animation cycles infinitely; otherwise the
+// animation plays n + 1 cycles (where n is the specified loop count).  If the
+// GIF decoder defaults to kAnimationLoopOnce in the absence of any loop count
+// and translates an explicit "0" loop count to kAnimationLoopInfinite, then we
+// get a couple of nice side effects:
+//   * By making kAnimationLoopOnce be 0, we allow the animation cycling code in
+//     BitmapImage.cpp to avoid special-casing it, and simply treat all
+//     non-negative loop counts identically.
+//   * By making the other two constants negative, we avoid conflicts with any
+//     real loop count values.
+const int kAnimationLoopOnce = 0;
+const int kAnimationLoopInfinite = -1;
+const int kAnimationNone = -2;
+
+}  // namespace cc
+
+#endif  // CC_PAINT_IMAGE_ANIMATION_COUNT_H_
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h
index 8586e68..db1856f 100644
--- a/cc/paint/paint_image.h
+++ b/cc/paint/paint_image.h
@@ -10,6 +10,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
 #include "cc/paint/frame_metadata.h"
+#include "cc/paint/image_animation_count.h"
 #include "cc/paint/paint_export.h"
 #include "cc/paint/skia_paint_image_generator.h"
 #include "third_party/skia/include/core/SkImage.h"
@@ -161,6 +162,7 @@
   Id id_ = 0;
   AnimationType animation_type_ = AnimationType::STATIC;
   CompletionState completion_state_ = CompletionState::DONE;
+  int repetition_count_ = kAnimationNone;
 
   // If non-empty, holds the subset of this image relative to the original image
   // at the origin.
diff --git a/cc/paint/paint_image_builder.h b/cc/paint/paint_image_builder.h
index 6585b79..467e0a9 100644
--- a/cc/paint/paint_image_builder.h
+++ b/cc/paint/paint_image_builder.h
@@ -69,6 +69,10 @@
     paint_image_.frame_index_ = frame_index;
     return *this;
   }
+  PaintImageBuilder& set_repetition_count(int count) {
+    paint_image_.repetition_count_ = count;
+    return *this;
+  }
 
   PaintImageBuilder& set_sk_image_id(uint32_t sk_image_id) {
     paint_image_.sk_image_id_ = sk_image_id;
diff --git a/cc/quads/draw_quad_perftest.cc b/cc/quads/draw_quad_perftest.cc
index b10b75e..d0c8540 100644
--- a/cc/quads/draw_quad_perftest.cc
+++ b/cc/quads/draw_quad_perftest.cc
@@ -26,13 +26,15 @@
   gfx::Rect visible_layer_rect(10, 12, 14, 16);
   gfx::Rect clip_rect(19, 21, 23, 25);
   bool is_clipped = false;
+  bool are_contents_opaque = false;
   float opacity = 1.f;
   int sorting_context_id = 65536;
   SkBlendMode blend_mode = SkBlendMode::kSrcOver;
 
   viz::SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
   state->SetAll(quad_transform, content_rect, visible_layer_rect, clip_rect,
-                is_clipped, opacity, blend_mode, sorting_context_id);
+                is_clipped, are_contents_opaque, opacity, blend_mode,
+                sorting_context_id);
   return state;
 }
 
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index dbc820d..000396a 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -40,13 +40,15 @@
   gfx::Rect visible_layer_rect(10, 12, 14, 16);
   gfx::Rect clip_rect(19, 21, 23, 25);
   bool is_clipped = true;
+  bool are_contents_opaque = true;
   float opacity = 0.25f;
   SkBlendMode blend_mode = SkBlendMode::kMultiply;
   int sorting_context_id = 65536;
 
   auto state = std::make_unique<viz::SharedQuadState>();
   state->SetAll(quad_transform, layer_rect, visible_layer_rect, clip_rect,
-                is_clipped, opacity, blend_mode, sorting_context_id);
+                is_clipped, are_contents_opaque, opacity, blend_mode,
+                sorting_context_id);
 
   auto copy = std::make_unique<viz::SharedQuadState>(*state);
   EXPECT_EQ(quad_transform, copy->quad_to_target_transform);
@@ -54,6 +56,7 @@
   EXPECT_EQ(opacity, copy->opacity);
   EXPECT_EQ(clip_rect, copy->clip_rect);
   EXPECT_EQ(is_clipped, copy->is_clipped);
+  EXPECT_EQ(are_contents_opaque, copy->are_contents_opaque);
   EXPECT_EQ(blend_mode, copy->blend_mode);
 }
 
@@ -63,13 +66,15 @@
   gfx::Rect visible_layer_rect(10, 12, 14, 16);
   gfx::Rect clip_rect(19, 21, 23, 25);
   bool is_clipped = false;
+  bool are_contents_opaque = true;
   float opacity = 1.f;
   int sorting_context_id = 65536;
   SkBlendMode blend_mode = SkBlendMode::kSrcOver;
 
   viz::SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
   state->SetAll(quad_transform, layer_rect, visible_layer_rect, clip_rect,
-                is_clipped, opacity, blend_mode, sorting_context_id);
+                is_clipped, are_contents_opaque, opacity, blend_mode,
+                sorting_context_id);
   return state;
 }
 
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc
index a73eabf..6c82df50 100644
--- a/cc/quads/render_pass_unittest.cc
+++ b/cc/quads/render_pass_unittest.cc
@@ -92,7 +92,7 @@
   // Stick a quad in the pass, this should not get copied.
   viz::SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(), gfx::Rect(), gfx::Rect(),
-                       false, 1, SkBlendMode::kSrcOver, 0);
+                       false, false, 1, SkBlendMode::kSrcOver, 0);
 
   SolidColorDrawQuad* color_quad =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -143,7 +143,7 @@
   // Two quads using one shared state.
   viz::SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
   shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
-                        gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
+                        gfx::Rect(), false, false, 1, SkBlendMode::kSrcOver, 0);
 
   SolidColorDrawQuad* color_quad1 =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -160,7 +160,7 @@
   // And two quads using another shared state.
   viz::SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
   shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
+                        gfx::Rect(), false, false, 1, SkBlendMode::kSrcOver, 0);
 
   SolidColorDrawQuad* color_quad3 =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -199,7 +199,7 @@
   viz::SharedQuadState* contrib_shared_state =
       contrib->CreateAndAppendSharedQuadState();
   contrib_shared_state->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2),
-                               gfx::Rect(), gfx::Rect(), false, 1,
+                               gfx::Rect(), gfx::Rect(), false, false, 1,
                                SkBlendMode::kSrcOver, 0);
 
   SolidColorDrawQuad* contrib_quad =
@@ -250,7 +250,7 @@
   // A shared state with a quad.
   viz::SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
   shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
-                        gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
+                        gfx::Rect(), false, false, 1, SkBlendMode::kSrcOver, 0);
 
   SolidColorDrawQuad* color_quad1 =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -261,17 +261,17 @@
   // A shared state with no quads, they were culled.
   viz::SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
   shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
+                        gfx::Rect(), false, false, 1, SkBlendMode::kSrcOver, 0);
 
   // A second shared state with no quads.
   viz::SharedQuadState* shared_state3 = pass->CreateAndAppendSharedQuadState();
   shared_state3->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
+                        gfx::Rect(), false, false, 1, SkBlendMode::kSrcOver, 0);
 
   // A last shared state with a quad again.
   viz::SharedQuadState* shared_state4 = pass->CreateAndAppendSharedQuadState();
   shared_state4->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
-                        gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
+                        gfx::Rect(), false, false, 1, SkBlendMode::kSrcOver, 0);
 
   SolidColorDrawQuad* color_quad2 =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
diff --git a/cc/resources/layer_tree_resource_provider.cc b/cc/resources/layer_tree_resource_provider.cc
index 45a8703..c37f56a 100644
--- a/cc/resources/layer_tree_resource_provider.cc
+++ b/cc/resources/layer_tree_resource_provider.cc
@@ -85,6 +85,9 @@
     unverified_sync_tokens.push_back(new_sync_token.GetData());
   }
 
+  if (compositor_context_provider_)
+    compositor_context_provider_->ContextSupport()->FlushPendingWork();
+
   if (!unverified_sync_tokens.empty()) {
     DCHECK(settings_.delegated_sync_points_required);
     DCHECK(gl);
diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc
index 587fbdc94..e355b3a 100644
--- a/cc/test/render_pass_test_utils.cc
+++ b/cc/test/render_pass_test_utils.cc
@@ -39,7 +39,7 @@
                             const gfx::Rect& rect,
                             SkColor color) {
   viz::SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1,
+  shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, false, 1,
                        SkBlendMode::kSrcOver, 0);
   SolidColorDrawQuad* quad =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -51,7 +51,7 @@
                                    const gfx::Rect& rect,
                                    SkColor color) {
   viz::SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, rect, true, 1,
+  shared_state->SetAll(gfx::Transform(), rect, rect, rect, true, false, 1,
                        SkBlendMode::kSrcOver, 0);
   SolidColorDrawQuad* quad =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -64,7 +64,8 @@
                                        SkColor color,
                                        const gfx::Transform& transform) {
   viz::SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(transform, rect, rect, rect, false, 1,
+  shared_state->SetAll(transform, rect, rect, rect, false, false, 1,
+
                        SkBlendMode::kSrcOver, 0);
   SolidColorDrawQuad* quad =
       pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -77,7 +78,7 @@
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), output_rect, output_rect, output_rect,
-                       false, 1, SkBlendMode::kSrcOver, 0);
+                       false, false, 1, SkBlendMode::kSrcOver, 0);
   RenderPassDrawQuad* quad =
       to_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
   quad->SetNew(shared_state, output_rect, output_rect, contributing_pass->id, 0,
@@ -94,7 +95,7 @@
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(transform, output_rect, output_rect, output_rect, false,
-                       1, blend_mode, 0);
+                       false, 1, blend_mode, 0);
   RenderPassDrawQuad* quad =
       to_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
   gfx::Size arbitrary_nonzero_size(1, 1);
@@ -166,7 +167,7 @@
 
   viz::SharedQuadState* shared_state =
       to_pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1,
+  shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, false, 1,
                        SkBlendMode::kSrcOver, 0);
 
   DebugBorderDrawQuad* debug_border_quad =
@@ -226,7 +227,7 @@
 
   viz::SharedQuadState* shared_state2 =
       to_pass->CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1,
+  shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, false, 1,
                        SkBlendMode::kSrcOver, 0);
 
   TileDrawQuad* tile_quad = to_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 168c634..a66ffdf 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -29,12 +29,12 @@
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/GrTexture.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gl/trace_util.h"
 
 namespace cc {
 namespace {
-
 // The number or entries to keep in the cache, depending on the memory state of
 // the system. This limit can be breached by in-use cache items, which cannot
 // be deleted.
@@ -42,14 +42,21 @@
 static const int kThrottledMaxItemsInCache = 100;
 static const int kSuspendedMaxItemsInCache = 0;
 
-// The factor by which to reduce the GPU memory size of the cache when in the
-// THROTTLED memory state.
-static const int kThrottledCacheSizeReductionFactor = 2;
-
-// The maximum size in bytes of GPU memory in the cache while SUSPENDED or not
-// visible. This limit can be breached by in-use cache items, which cannot be
-// deleted.
-static const int kSuspendedOrInvisibleMaxGpuImageBytes = 0;
+// lock_count │ used  │ result state
+// ═══════════╪═══════╪══════════════════
+//  1         │ false │ WASTED_ONCE
+//  1         │ true  │ USED_ONCE
+//  >1        │ false │ WASTED_RELOCKED
+//  >1        │ true  │ USED_RELOCKED
+// Note that it's important not to reorder the following enum, since the
+// numerical values are used in the histogram code.
+enum ImageUsageState : int {
+  IMAGE_USAGE_STATE_WASTED_ONCE,
+  IMAGE_USAGE_STATE_USED_ONCE,
+  IMAGE_USAGE_STATE_WASTED_RELOCKED,
+  IMAGE_USAGE_STATE_USED_RELOCKED,
+  IMAGE_USAGE_STATE_COUNT
+};
 
 // Returns true if an image would not be drawn and should therefore be
 // skipped rather than decoded.
@@ -148,6 +155,14 @@
   return decode_pixmap.readPixels(*target_pixmap);
 }
 
+// Returns the GL texture ID backing the given SkImage.
+GrGLuint GlIdFromSkImage(SkImage* image) {
+  DCHECK(image->isTextureBacked());
+  const GrGLTextureInfo* info = skia::GrBackendObjectToGrGLTextureInfo(
+      image->getTextureHandle(true /* flushPendingGrContextIO */));
+  return info->fID;
+}
+
 }  // namespace
 
 // static
@@ -276,78 +291,87 @@
   DISALLOW_COPY_AND_ASSIGN(ImageUploadTaskImpl);
 };
 
+GpuImageDecodeCache::ImageDataBase::ImageDataBase() = default;
+GpuImageDecodeCache::ImageDataBase::~ImageDataBase() = default;
+
+void GpuImageDecodeCache::ImageDataBase::OnSetLockedData(bool out_of_raster) {
+  DCHECK_EQ(usage_stats_.lock_count, 1);
+  DCHECK(!is_locked_);
+  usage_stats_.first_lock_out_of_raster = out_of_raster;
+  is_locked_ = true;
+}
+
+void GpuImageDecodeCache::ImageDataBase::OnResetData() {
+  is_locked_ = false;
+  usage_stats_ = UsageStats();
+}
+
+void GpuImageDecodeCache::ImageDataBase::OnLock() {
+  DCHECK(!is_locked_);
+  is_locked_ = true;
+  ++usage_stats_.lock_count;
+}
+
+void GpuImageDecodeCache::ImageDataBase::OnUnlock() {
+  DCHECK(is_locked_);
+  is_locked_ = false;
+  if (usage_stats_.lock_count == 1)
+    usage_stats_.first_lock_wasted = !usage_stats_.used;
+}
+
+int GpuImageDecodeCache::ImageDataBase::UsageState() const {
+  ImageUsageState state = IMAGE_USAGE_STATE_WASTED_ONCE;
+  if (usage_stats_.lock_count == 1) {
+    if (usage_stats_.used)
+      state = IMAGE_USAGE_STATE_USED_ONCE;
+    else
+      state = IMAGE_USAGE_STATE_WASTED_ONCE;
+  } else {
+    if (usage_stats_.used)
+      state = IMAGE_USAGE_STATE_USED_RELOCKED;
+    else
+      state = IMAGE_USAGE_STATE_WASTED_RELOCKED;
+  }
+
+  return state;
+}
+
 GpuImageDecodeCache::DecodedImageData::DecodedImageData() = default;
 GpuImageDecodeCache::DecodedImageData::~DecodedImageData() {
   ResetData();
 }
 
 bool GpuImageDecodeCache::DecodedImageData::Lock() {
-  DCHECK(!is_locked_);
-  is_locked_ = data_->Lock();
-  if (is_locked_)
-    ++usage_stats_.lock_count;
+  if (data_->Lock())
+    OnLock();
   return is_locked_;
 }
 
 void GpuImageDecodeCache::DecodedImageData::Unlock() {
-  DCHECK(is_locked_);
   data_->Unlock();
-  if (usage_stats_.lock_count == 1)
-    usage_stats_.first_lock_wasted = !usage_stats_.used;
-  is_locked_ = false;
+  OnUnlock();
 }
 
 void GpuImageDecodeCache::DecodedImageData::SetLockedData(
     std::unique_ptr<base::DiscardableMemory> data,
     bool out_of_raster) {
-  DCHECK(!is_locked_);
   DCHECK(data);
   DCHECK(!data_);
-  DCHECK_EQ(usage_stats_.lock_count, 1);
   data_ = std::move(data);
-  is_locked_ = true;
-  usage_stats_.first_lock_out_of_raster = out_of_raster;
+  OnSetLockedData(out_of_raster);
 }
 
 void GpuImageDecodeCache::DecodedImageData::ResetData() {
-  DCHECK(!is_locked_);
   if (data_)
     ReportUsageStats();
   data_ = nullptr;
-  usage_stats_ = UsageStats();
+  OnResetData();
 }
 
 void GpuImageDecodeCache::DecodedImageData::ReportUsageStats() const {
-  // lock_count │ used  │ result state
-  // ═══════════╪═══════╪══════════════════
-  //  1         │ false │ WASTED_ONCE
-  //  1         │ true  │ USED_ONCE
-  //  >1        │ false │ WASTED_RELOCKED
-  //  >1        │ true  │ USED_RELOCKED
-  // Note that it's important not to reorder the following enums, since the
-  // numerical values are used in the histogram code.
-  enum State : int {
-    DECODED_IMAGE_STATE_WASTED_ONCE,
-    DECODED_IMAGE_STATE_USED_ONCE,
-    DECODED_IMAGE_STATE_WASTED_RELOCKED,
-    DECODED_IMAGE_STATE_USED_RELOCKED,
-    DECODED_IMAGE_STATE_COUNT
-  } state = DECODED_IMAGE_STATE_WASTED_ONCE;
-
-  if (usage_stats_.lock_count == 1) {
-    if (usage_stats_.used)
-      state = DECODED_IMAGE_STATE_USED_ONCE;
-    else
-      state = DECODED_IMAGE_STATE_WASTED_ONCE;
-  } else {
-    if (usage_stats_.used)
-      state = DECODED_IMAGE_STATE_USED_RELOCKED;
-    else
-      state = DECODED_IMAGE_STATE_WASTED_RELOCKED;
-  }
-
-  UMA_HISTOGRAM_ENUMERATION("Renderer4.GpuImageDecodeState", state,
-                            DECODED_IMAGE_STATE_COUNT);
+  UMA_HISTOGRAM_ENUMERATION("Renderer4.GpuImageDecodeState",
+                            static_cast<ImageUsageState>(UsageState()),
+                            IMAGE_USAGE_STATE_COUNT);
   UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageDecodeState.FirstLockWasted",
                         usage_stats_.first_lock_wasted);
   if (usage_stats_.first_lock_out_of_raster)
@@ -358,23 +382,33 @@
 
 GpuImageDecodeCache::UploadedImageData::UploadedImageData() = default;
 GpuImageDecodeCache::UploadedImageData::~UploadedImageData() {
-  SetImage(nullptr);
+  DCHECK(!image());
 }
 
 void GpuImageDecodeCache::UploadedImageData::SetImage(sk_sp<SkImage> image) {
-  DCHECK(!image_ || !image);
-  if (image_) {
-    ReportUsageStats();
-    usage_stats_ = UsageStats();
-  }
+  DCHECK(!image_);
+  DCHECK(image);
   image_ = std::move(image);
+  if (image_->isTextureBacked())
+    gl_id_ = GlIdFromSkImage(image_.get());
+  OnSetLockedData(false /* out_of_raster */);
+}
+
+void GpuImageDecodeCache::UploadedImageData::ResetImage() {
+  if (image_)
+    ReportUsageStats();
+
+  image_ = nullptr;
+  gl_id_ = 0;
+  OnResetData();
 }
 
 void GpuImageDecodeCache::UploadedImageData::ReportUsageStats() const {
-  UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageUploadState.Used",
-                        usage_stats_.used);
-  UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageUploadState.FirstRefWasted",
-                        usage_stats_.first_ref_wasted);
+  UMA_HISTOGRAM_ENUMERATION("Renderer4.GpuImageUploadState",
+                            static_cast<ImageUsageState>(UsageState()),
+                            IMAGE_USAGE_STATE_COUNT);
+  UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageUploadState.FirstLockWasted",
+                        usage_stats_.first_lock_wasted);
 }
 
 GpuImageDecodeCache::ImageData::ImageData(
@@ -400,21 +434,17 @@
 
 GpuImageDecodeCache::GpuImageDecodeCache(viz::ContextProvider* context,
                                          SkColorType color_type,
-                                         size_t max_working_set_bytes,
-                                         size_t max_cache_bytes)
+                                         size_t max_working_set_bytes)
     : color_type_(color_type),
       context_(context),
       persistent_cache_(PersistentCache::NO_AUTO_EVICT),
-      max_working_set_bytes_(max_working_set_bytes),
-      normal_max_cache_bytes_(max_cache_bytes) {
-  DCHECK_GE(max_working_set_bytes_, normal_max_cache_bytes_);
-
+      max_working_set_bytes_(max_working_set_bytes) {
   // Acquire the context_lock so that we can safely retrieve the
   // GrContextThreadSafeProxy. This proxy can then be used with no lock held.
   {
     viz::ContextProvider::ScopedContextLock context_lock(context_);
     context_threadsafe_proxy_ = sk_sp<GrContextThreadSafeProxy>(
-        context->GrContext()->threadSafeProxy());
+        context_->GrContext()->threadSafeProxy());
   }
 
   // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
@@ -486,11 +516,6 @@
     // We have already tried and failed to decode this image, so just return.
     *task = nullptr;
     return false;
-  } else if (image_data->upload.image()) {
-    // The image is already uploaded, ref and return.
-    RefImage(draw_image);
-    *task = nullptr;
-    return true;
   } else if (task_type == DecodeTaskType::PART_OF_UPLOAD_TASK &&
              image_data->upload.task) {
     // We had an existing upload task, ref the image and return the task.
@@ -521,6 +546,14 @@
   // it is their responsibility to release it by calling UnrefImage.
   RefImage(draw_image);
 
+  // If we already have an image and it is locked (or lock-able), just return
+  // that.
+  if (image_data->upload.image() &&
+      TryLockImage(HaveContextLock::kNo, draw_image, image_data)) {
+    *task = nullptr;
+    return true;
+  }
+
   if (task_type == DecodeTaskType::PART_OF_UPLOAD_TASK) {
     // Ref image and create a upload and decode tasks. We will release this ref
     // in UploadTaskCompleted.
@@ -584,7 +617,8 @@
   UnrefImageDecode(draw_image);
 
   sk_sp<SkImage> image = image_data->upload.image();
-  image_data->upload.mark_used();
+  if (image)
+    image_data->upload.mark_used();
   DCHECK(image || image_data->decode.decode_failure);
 
   SkSize scale_factor = CalculateScaleFactorForMipLevel(
@@ -614,7 +648,7 @@
   // We are mid-draw and holding the context lock, ensure we clean up any
   // textures (especially at-raster), which may have just been marked for
   // deletion by UnrefImage.
-  DeletePendingImages();
+  RunPendingContextThreadOperations();
 }
 
 void GpuImageDecodeCache::ReduceCacheUsage() {
@@ -622,6 +656,14 @@
                "GpuImageDecodeCache::ReduceCacheUsage");
   base::AutoLock lock(lock_);
   EnsureCapacity(0);
+
+  // This is typically called when no tasks are running (between scheduling
+  // tasks). Try to lock and run pending operations if possible, but don't
+  // block on it.
+  if (context_->GetLock()->Try()) {
+    RunPendingContextThreadOperations();
+    context_->GetLock()->Release();
+  }
 }
 
 void GpuImageDecodeCache::SetShouldAggressivelyFreeResources(
@@ -632,17 +674,15 @@
   if (aggressively_free_resources) {
     viz::ContextProvider::ScopedContextLock context_lock(context_);
     base::AutoLock lock(lock_);
-    // We want to keep as little in our cache as possible. Set our memory limit
-    // to zero and EnsureCapacity to clean up memory.
-    cached_bytes_limit_ = kSuspendedOrInvisibleMaxGpuImageBytes;
+    aggressively_freeing_resources_ = aggressively_free_resources;
     EnsureCapacity(0);
 
     // We are holding the context lock, so finish cleaning up deleted images
     // now.
-    DeletePendingImages();
+    RunPendingContextThreadOperations();
   } else {
     base::AutoLock lock(lock_);
-    cached_bytes_limit_ = normal_max_cache_bytes_;
+    aggressively_freeing_resources_ = aggressively_free_resources;
   }
 }
 
@@ -654,17 +694,14 @@
       // Orphan the entry so it will be deleted once no longer in use.
       entry.second->is_orphaned = true;
     } else if (entry.second->upload.image()) {
-      bytes_used_ -= entry.second->size;
-      images_pending_deletion_.push_back(entry.second->upload.image());
-      entry.second->upload.SetImage(nullptr);
-      entry.second->upload.budgeted = false;
+      DeleteImage(entry.second.get());
     }
   }
   persistent_cache_.Clear();
 }
 
 size_t GpuImageDecodeCache::GetMaximumMemoryLimitBytes() const {
-  return normal_max_cache_bytes_;
+  return max_working_set_bytes_;
 }
 
 void GpuImageDecodeCache::NotifyImageUnused(
@@ -675,11 +712,7 @@
         it->second->upload.ref_count != 0) {
       it->second->is_orphaned = true;
     } else if (it->second->upload.image()) {
-      DCHECK(!it->second->decode.is_locked());
-      bytes_used_ -= it->second->size;
-      images_pending_deletion_.push_back(it->second->upload.image());
-      it->second->upload.SetImage(nullptr);
-      it->second->upload.budgeted = false;
+      DeleteImage(it->second.get());
     }
     persistent_cache_.Erase(it);
   }
@@ -700,7 +733,7 @@
         "cc/image_memory/cache_0x%" PRIXPTR, reinterpret_cast<uintptr_t>(this));
     MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_name);
     dump->AddScalar(MemoryAllocatorDump::kNameSize,
-                    MemoryAllocatorDump::kUnitsBytes, bytes_used_);
+                    MemoryAllocatorDump::kUnitsBytes, working_set_bytes_);
 
     // Early out, no need for more detail in a BACKGROUND dump.
     return true;
@@ -728,8 +761,7 @@
     }
 
     // If we have an uploaded image (that is actually on the GPU, not just a
-    // CPU
-    // wrapper), upload it here.
+    // CPU wrapper), upload it here.
     if (image_data->upload.image() &&
         image_data->mode == DecodedDataMode::GPU) {
       std::string gpu_dump_name = base::StringPrintf(
@@ -739,15 +771,17 @@
       dump->AddScalar(MemoryAllocatorDump::kNameSize,
                       MemoryAllocatorDump::kUnitsBytes, image_data->size);
 
+      // Dump the "locked_size" as an additional column.
+      size_t locked_size =
+          image_data->upload.is_locked() ? image_data->size : 0u;
+      dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes,
+                      locked_size);
+
       // Create a global shred GUID to associate this data with its GPU
-      // process
-      // counterpart.
-      GLuint gl_id = skia::GrBackendObjectToGrGLTextureInfo(
-                         image_data->upload.image()->getTextureHandle(
-                             false /* flushPendingGrContextIO */))
-                         ->fID;
+      // process counterpart.
       MemoryAllocatorDumpGuid guid = gl::GetGLTextureClientGUIDForTracing(
-          context_->ContextSupport()->ShareGroupTracingGUID(), gl_id);
+          context_->ContextSupport()->ShareGroupTracingGUID(),
+          image_data->upload.gl_id());
 
       // kImportance is somewhat arbitrary - we chose 3 to be higher than the
       // value used in the GPU process (1), and Skia (2), causing us to appear
@@ -949,68 +983,61 @@
       persistent_cache_.Erase(found_persistent);
   }
 
+  // If we have no refs on an uploaded image, it should be unlocked. Do this
+  // before any attempts to delete the image.
+  if (image_data->mode == DecodedDataMode::GPU &&
+      image_data->upload.ref_count == 0 && image_data->upload.is_locked()) {
+    UnlockImage(image_data);
+  }
+
   // Don't keep around orphaned images.
   if (image_data->is_orphaned && !has_any_refs) {
-    images_pending_deletion_.push_back(std::move(image_data->upload.image()));
-    image_data->upload.SetImage(nullptr);
+    DeleteImage(image_data);
   }
 
   // Don't keep CPU images if they are unused, these images can be recreated by
   // re-locking discardable (rather than requiring a full upload like GPU
   // images).
   if (image_data->mode == DecodedDataMode::CPU && !has_any_refs) {
-    images_pending_deletion_.push_back(image_data->upload.image());
-    image_data->upload.SetImage(nullptr);
+    DeleteImage(image_data);
   }
 
   if (image_data->is_at_raster && !has_any_refs) {
-    // We have an at-raster image which has reached zero refs. If it won't fit
-    // in our cache, delete the image to allow it to fit.
-    if (image_data->upload.image() && !CanFitInCache(image_data->size)) {
-      images_pending_deletion_.push_back(image_data->upload.image());
-      image_data->upload.SetImage(nullptr);
-    }
-
-    // We now have an at-raster image which will fit in our cache. Convert it
-    // to not-at-raster.
+    // We have an at-raster image with no refs. Convert it to not-at-raster and
+    // cache it unlocked.
     image_data->is_at_raster = false;
-    if (image_data->upload.image()) {
-      bytes_used_ += image_data->size;
-      image_data->upload.budgeted = true;
-    }
+    DCHECK(!image_data->upload.budgeted);
   }
 
-  // If we have image refs on a non-at-raster image, it must be budgeted, as it
-  // is either uploaded or pending upload.
+  // If we have image that should be budgeted, but isn't, budget it now.
   if (image_data->upload.ref_count > 0 && !image_data->upload.budgeted &&
       !image_data->is_at_raster) {
     // We should only be taking non-at-raster refs on images that fit in cache.
     DCHECK(CanFitInWorkingSet(image_data->size));
 
-    bytes_used_ += image_data->size;
+    working_set_bytes_ += image_data->size;
     image_data->upload.budgeted = true;
   }
 
   // If we have no image refs on an image, it should only be budgeted if it has
   // an uploaded image. If no image exists (upload was cancelled), we should
   // un-budget the image.
-  if (image_data->upload.ref_count == 0 && image_data->upload.budgeted &&
-      !image_data->upload.image()) {
-    DCHECK_GE(bytes_used_, image_data->size);
-    bytes_used_ -= image_data->size;
+  if (image_data->upload.ref_count == 0 && image_data->upload.budgeted) {
+    DCHECK_GE(working_set_bytes_, image_data->size);
+    working_set_bytes_ -= image_data->size;
     image_data->upload.budgeted = false;
   }
 
-  // We should unlock the discardable memory for the image in two cases:
+  // We should unlock the decoded image memory for the image in two cases:
   // 1) The image is no longer being used (no decode or upload refs).
   // 2) This is a GPU backed image that has already been uploaded (no decode
   //    refs, and we actually already have an image).
-  bool should_unlock_discardable =
+  bool should_unlock_decode =
       !has_any_refs ||
       (image_data->mode == DecodedDataMode::GPU &&
        !image_data->decode.ref_count && image_data->upload.image());
 
-  if (should_unlock_discardable && image_data->decode.is_locked()) {
+  if (should_unlock_decode && image_data->decode.is_locked()) {
     DCHECK(image_data->decode.data());
     image_data->decode.Unlock();
   }
@@ -1021,7 +1048,8 @@
 #if DCHECK_IS_ON()
   // Sanity check the above logic.
   if (image_data->upload.image()) {
-    DCHECK(image_data->is_at_raster || image_data->upload.budgeted);
+    DCHECK(image_data->is_at_raster || image_data->upload.budgeted ||
+           !image_data->upload.is_locked());
     if (image_data->mode == DecodedDataMode::CPU)
       DCHECK(image_data->decode.is_locked());
   } else {
@@ -1038,18 +1066,11 @@
                "GpuImageDecodeCache::EnsureCapacity");
   lock_.AssertAcquired();
 
-  // While we only care whether |required_size| fits in our working set, we
-  // also want to keep our cache under-budget if possible. Working set size
-  // will always match or exceed cache size, so keeping the cache under budget
-  // may be impossible.
-  if (CanFitInCache(required_size) && !ExceedsPreferredCount())
+  if (CanFitInWorkingSet(required_size) && !ExceedsPreferredCount())
     return true;
 
   // While we are over memory or preferred item capacity, we iterate through
-  // our set of cached image data in LRU order. For each image, we can do two
-  // things: 1) We can free the uploaded image, reducing the memory usage of
-  // the cache and 2) we can remove the entry entirely, reducing the count of
-  // elements in the cache.
+  // our set of cached image data in LRU order, removing unreferenced images.
   for (auto it = persistent_cache_.rbegin(); it != persistent_cache_.rend();) {
     if (it->second->decode.ref_count != 0 ||
         it->second->upload.ref_count != 0) {
@@ -1064,52 +1085,23 @@
     // upload.
     DCHECK(!it->second->upload.budgeted || it->second->upload.image());
 
-    // Free the uploaded image if possible.
-    if (it->second->upload.image()) {
-      DCHECK(it->second->upload.budgeted);
-      DCHECK_GE(bytes_used_, it->second->size);
-      bytes_used_ -= it->second->size;
-      images_pending_deletion_.push_back(it->second->upload.image());
-      it->second->upload.SetImage(nullptr);
-      it->second->upload.budgeted = false;
-    }
+    // Free the uploaded image if it exists.
+    if (it->second->upload.image())
+      DeleteImage(it->second.get());
 
-    // Free the entire entry if necessary.
-    if (ExceedsPreferredCount()) {
-      it = persistent_cache_.Erase(it);
-    } else {
-      ++it;
-    }
+    it = persistent_cache_.Erase(it);
 
-    if (CanFitInCache(required_size) && !ExceedsPreferredCount())
+    if (CanFitInWorkingSet(required_size) && !ExceedsPreferredCount())
       return true;
   }
 
-  return CanFitInWorkingSet(required_size);
-}
-
-bool GpuImageDecodeCache::CanFitInCache(size_t size) const {
-  lock_.AssertAcquired();
-
-  size_t bytes_limit;
-  if (memory_state_ == base::MemoryState::NORMAL) {
-    bytes_limit = cached_bytes_limit_;
-  } else if (memory_state_ == base::MemoryState::THROTTLED) {
-    bytes_limit = cached_bytes_limit_ / kThrottledCacheSizeReductionFactor;
-  } else {
-    DCHECK_EQ(base::MemoryState::SUSPENDED, memory_state_);
-    bytes_limit = kSuspendedOrInvisibleMaxGpuImageBytes;
-  }
-
-  base::CheckedNumeric<uint32_t> new_size(bytes_used_);
-  new_size += size;
-  return new_size.IsValid() && new_size.ValueOrDie() <= bytes_limit;
+  return false;
 }
 
 bool GpuImageDecodeCache::CanFitInWorkingSet(size_t size) const {
   lock_.AssertAcquired();
 
-  base::CheckedNumeric<uint32_t> new_size(bytes_used_);
+  base::CheckedNumeric<uint32_t> new_size(working_set_bytes_);
   new_size += size;
   return new_size.IsValid() && new_size.ValueOrDie() <= max_working_set_bytes_;
 }
@@ -1118,7 +1110,9 @@
   lock_.AssertAcquired();
 
   size_t items_limit;
-  if (memory_state_ == base::MemoryState::NORMAL) {
+  if (aggressively_freeing_resources_) {
+    items_limit = kSuspendedMaxItemsInCache;
+  } else if (memory_state_ == base::MemoryState::NORMAL) {
     items_limit = kNormalMaxItemsInCache;
   } else if (memory_state_ == base::MemoryState::THROTTLED) {
     items_limit = kThrottledMaxItemsInCache;
@@ -1142,7 +1136,8 @@
     return;
   }
 
-  if (image_data->upload.image()) {
+  if (image_data->upload.image() &&
+      TryLockImage(HaveContextLock::kNo, draw_image, image_data)) {
     // We already have an uploaded image, no reason to decode.
     return;
   }
@@ -1220,12 +1215,18 @@
   context_->GetLock()->AssertAcquired();
   lock_.AssertAcquired();
 
+  // We are about to upload a new image and are holding the context lock.
+  // Ensure that any images which have been marked for deletion are actually
+  // cleaned up so we don't exceed our memory limit during this upload.
+  RunPendingContextThreadOperations();
+
   if (image_data->decode.decode_failure) {
     // We were unnable to decode this image. Don't try to upload.
     return;
   }
 
-  if (image_data->upload.image()) {
+  if (image_data->upload.image() &&
+      TryLockImage(HaveContextLock::kYes, draw_image, image_data)) {
     // Someone has uploaded this image before us (at raster).
     return;
   }
@@ -1235,11 +1236,6 @@
   DCHECK_GT(image_data->decode.ref_count, 0u);
   DCHECK_GT(image_data->upload.ref_count, 0u);
 
-  // We are about to upload a new image and are holding the context lock.
-  // Ensure that any images which have been marked for deletion are actually
-  // cleaned up so we don't exceed our memory limit during this upload.
-  DeletePendingImages();
-
   sk_sp<SkImage> uploaded_image;
   {
     base::AutoUnlock unlock(lock_);
@@ -1265,8 +1261,10 @@
 
   // TODO(crbug.com/740737): uploaded_image is sometimes null for reasons that
   // need investigation.
+  if (!uploaded_image)
+    return;
 
-  if (uploaded_image && draw_image.target_color_space().IsValid()) {
+  if (draw_image.target_color_space().IsValid()) {
     TRACE_EVENT0("cc", "GpuImageDecodeCache::UploadImage - color conversion");
     uploaded_image = uploaded_image->makeColorSpace(
         draw_image.target_color_space().ToSkColorSpace(),
@@ -1275,8 +1273,18 @@
 
   // At-raster may have decoded this while we were unlocked. If so, ignore our
   // result.
-  if (!image_data->upload.image())
+  if (!image_data->upload.image()) {
     image_data->upload.SetImage(std::move(uploaded_image));
+
+    // If we have a new GPU-backed image, initialize it for use in the GPU
+    // discardable system.
+    if (image_data->mode == DecodedDataMode::GPU) {
+      // Notify the discardable system of this image so it will count against
+      // budgets.
+      context_->ContextGL()->InitializeDiscardableTextureCHROMIUM(
+          image_data->upload.gl_id());
+    }
+  }
 }
 
 scoped_refptr<GpuImageDecodeCache::ImageData>
@@ -1310,9 +1318,53 @@
       new ImageData(mode, data_size, draw_image.target_color_space(), params));
 }
 
-void GpuImageDecodeCache::DeletePendingImages() {
+void GpuImageDecodeCache::DeleteImage(ImageData* image_data) {
+  if (image_data->mode == DecodedDataMode::GPU && image_data->upload.image()) {
+    DCHECK(!image_data->upload.is_locked());
+    images_pending_deletion_.push_back(image_data->upload.image());
+  }
+  image_data->upload.ResetImage();
+}
+
+void GpuImageDecodeCache::UnlockImage(ImageData* image_data) {
+  DCHECK_EQ(DecodedDataMode::GPU, image_data->mode);
+  images_pending_unlock_.push_back(image_data->upload.image().get());
+  image_data->upload.OnUnlock();
+}
+
+// We always run pending operations in the following order:
+//   Lock > Unlock > Delete
+// This ensures that:
+//   a) We never fully unlock an image that's pending lock (lock before unlock)
+//   b) We never delete an image that has pending locks/unlocks.
+// As this can be run at-raster, to unlock/delete an image that was just used,
+// we need to call GlIdFromSkImage, which flushes pending IO on the image,
+// rather than just using a cached GL ID.
+void GpuImageDecodeCache::RunPendingContextThreadOperations() {
   context_->GetLock()->AssertAcquired();
   lock_.AssertAcquired();
+
+  for (auto* image : images_pending_complete_lock_) {
+    context_->ContextSupport()->CompleteLockDiscardableTexureOnContextThread(
+        GlIdFromSkImage(image));
+  }
+  images_pending_complete_lock_.clear();
+
+  for (auto* image : images_pending_unlock_) {
+    context_->ContextGL()->UnlockDiscardableTextureCHROMIUM(
+        GlIdFromSkImage(image));
+  }
+  images_pending_unlock_.clear();
+
+  for (auto& image : images_pending_deletion_) {
+    // We *always* abandon images, to prevent Skia from caching/re-using them.
+    // TODO(ericrk): Handle this in a better way. crbug.com/735736
+    uint32_t texture_id = GlIdFromSkImage(image.get());
+    if (context_->ContextGL()->LockDiscardableTextureCHROMIUM(texture_id)) {
+      context_->ContextGL()->DeleteTextures(1, &texture_id);
+    }
+    image->getTexture()->abandon();
+  }
   images_pending_deletion_.clear();
 }
 
@@ -1326,6 +1378,39 @@
                            draw_image.target_color_space().ToSkColorSpace());
 }
 
+bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
+                                       const DrawImage& draw_image,
+                                       ImageData* data) {
+  if (data->upload.is_locked())
+    return true;
+
+  if (have_context_lock == HaveContextLock::kYes &&
+      context_->ContextGL()->LockDiscardableTextureCHROMIUM(
+          data->upload.gl_id())) {
+    // If |have_context_lock|, we can immediately lock the image and send
+    // the lock command to the GPU process.
+    data->upload.OnLock();
+    return true;
+  } else if (context_->ContextSupport()
+                 ->ThreadSafeShallowLockDiscardableTexture(
+                     data->upload.gl_id())) {
+    // If !|have_context_lock|, we use ThreadsafeShallowLockDiscardableTexture.
+    // This takes a reference to the image, ensuring that it can't be deleted
+    // by the service, but delays sending a lock command over the command
+    // buffer. This command must be sent before the image is used, but is now
+    // guaranteed to succeed. We will send this command via
+    // CompleteLockDiscardableTextureOnContextThread in UploadImageIfNecessary,
+    // which is guaranteed to run before the texture is used.
+    data->upload.OnLock();
+    images_pending_complete_lock_.push_back(data->upload.image().get());
+    return true;
+  }
+
+  // Couldn't lock, abandon the image.
+  DeleteImage(data);
+  return false;
+}
+
 // Tries to find an ImageData that can be used to draw the provided
 // |draw_image|. First looks for an exact entry in our |in_use_cache_|. If one
 // cannot be found, it looks for a compatible entry in our |persistent_cache_|.
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h
index 4a84583..c2cb8da 100644
--- a/cc/tiles/gpu_image_decode_cache.h
+++ b/cc/tiles/gpu_image_decode_cache.h
@@ -17,6 +17,7 @@
 #include "cc/cc_export.h"
 #include "cc/tiles/image_decode_cache.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
 
 namespace viz {
 class ContextProvider;
@@ -39,14 +40,13 @@
 //
 // Decoded and Uploaded image data share a single cache entry. Depending on how
 // far we've progressed, this cache entry may contain CPU-side decoded data,
-// GPU-side uploaded data, or both. Because CPU-side decoded data is stored in
-// discardable memory, and is only locked for short periods of time (until the
-// upload completes), this memory is not counted against our sized cache
-// limits. Uploaded GPU memory, being non-discardable, always counts against
-// our limits.
+// GPU-side uploaded data, or both. CPU-side decoded data is stored in software
+// discardable memory and is only locked for short periods of time (until the
+// upload completes). Uploaded GPU data is stored in GPU discardable memory and
+// remains locked for the duration of the raster tasks which depend on it.
 //
-// In cases where the number of images needed exceeds our cache limits, we
-// operate in an "at-raster" mode. In this mode, there are no decode/upload
+// In cases where the size of locked GPU images exceeds our working set limits,
+// we operate in an "at-raster" mode. In this mode, there are no decode/upload
 // tasks, and images are decoded/uploaded as needed, immediately before being
 // used in raster. Cache entries for at-raster tasks are marked as such, which
 // prevents future tasks from taking a dependency on them and extending their
@@ -104,8 +104,7 @@
 
   explicit GpuImageDecodeCache(viz::ContextProvider* context,
                                SkColorType color_type,
-                               size_t max_working_set_bytes,
-                               size_t max_cache_bytes);
+                               size_t max_working_set_bytes);
   ~GpuImageDecodeCache() override;
 
   // ImageDecodeCache overrides.
@@ -147,14 +146,14 @@
   void OnImageUploadTaskCompleted(const DrawImage& image);
 
   // For testing only.
-  void SetAllByteLimitsForTesting(size_t limit) {
-    cached_bytes_limit_ = limit;
+  void SetWorkingSetLimitForTesting(size_t limit) {
     max_working_set_bytes_ = limit;
   }
-  size_t GetBytesUsedForTesting() const { return bytes_used_; }
+  size_t GetWorkingSetBytesForTesting() const { return working_set_bytes_; }
   size_t GetNumCacheEntriesForTesting() const {
     return persistent_cache_.size();
   }
+  size_t GetInUseCacheEntriesForTesting() const { return in_use_cache_.size(); }
   size_t GetDrawImageSizeForTesting(const DrawImage& image);
   void SetImageDecodingFailedForTesting(const DrawImage& image);
   bool DiscardableIsLockedForTesting(const DrawImage& image);
@@ -163,30 +162,26 @@
  private:
   enum class DecodedDataMode { GPU, CPU };
 
-  // Stores the CPU-side decoded bits of an image and supporting fields.
-  struct DecodedImageData {
-    DecodedImageData();
-    ~DecodedImageData();
+  // Stores stats tracked by both DecodedImageData and UploadedImageData.
+  struct ImageDataBase {
+    ImageDataBase();
+    ~ImageDataBase();
 
     bool is_locked() const { return is_locked_; }
-    bool Lock();
-    void Unlock();
-    void SetLockedData(std::unique_ptr<base::DiscardableMemory> data,
-                       bool out_of_raster);
-    void ResetData();
-    base::DiscardableMemory* data() const { return data_.get(); }
-    void mark_used() { usage_stats_.used = true; }
+    void OnSetLockedData(bool out_of_raster);
+    void OnResetData();
+    void OnLock();
+    void OnUnlock();
+    void mark_used() {
+      DCHECK(is_locked_);
+      usage_stats_.used = true;
+    }
 
     uint32_t ref_count = 0;
-    // Set to true if the image was corrupt and could not be decoded.
-    bool decode_failure = false;
-    // If non-null, this is the pending decode task for this image.
+    // If non-null, this is the pending task to populate this data.
     scoped_refptr<TileTask> task;
-    // Similar to above, but only is generated if there is no associated upload
-    // generated for this task (ie, this is an out-of-raster request for decode.
-    scoped_refptr<TileTask> stand_alone_task;
 
-   private:
+   protected:
     struct UsageStats {
       int lock_count = 1;
       bool used = false;
@@ -194,45 +189,56 @@
       bool first_lock_wasted = false;
     };
 
-    void ReportUsageStats() const;
+    // Returns the usage state (see cc file) for histogram logging.
+    int UsageState() const;
 
-    std::unique_ptr<base::DiscardableMemory> data_;
     bool is_locked_ = false;
     UsageStats usage_stats_;
   };
 
+  // Stores the CPU-side decoded bits of an image and supporting fields.
+  struct DecodedImageData : public ImageDataBase {
+    DecodedImageData();
+    ~DecodedImageData();
+
+    bool Lock();
+    void Unlock();
+
+    void SetLockedData(std::unique_ptr<base::DiscardableMemory> data,
+                       bool out_of_raster);
+    void ResetData();
+    base::DiscardableMemory* data() const { return data_.get(); }
+
+    bool decode_failure = false;
+    // Similar to |task|, but only is generated if there is no associated upload
+    // generated for this task (ie, this is an out-of-raster request for decode.
+    scoped_refptr<TileTask> stand_alone_task;
+
+   private:
+    void ReportUsageStats() const;
+
+    std::unique_ptr<base::DiscardableMemory> data_;
+  };
+
   // Stores the GPU-side image and supporting fields.
-  struct UploadedImageData {
+  struct UploadedImageData : public ImageDataBase {
     UploadedImageData();
     ~UploadedImageData();
 
     void SetImage(sk_sp<SkImage> image);
+    void ResetImage();
     const sk_sp<SkImage>& image() const { return image_; }
+    GrGLuint gl_id() const { return gl_id_; }
 
-    void mark_used() { usage_stats_.used = true; }
-    void notify_ref_reached_zero() {
-      if (++usage_stats_.ref_reached_zero_count == 1)
-        usage_stats_.first_ref_wasted = !usage_stats_.used;
-    }
-
-    // True if the image is counting against our memory limits.
+    // True if the image is counting against our working set limits.
     bool budgeted = false;
-    uint32_t ref_count = 0;
-    // If non-null, this is the pending upload task for this image.
-    scoped_refptr<TileTask> task;
 
    private:
-    struct UsageStats {
-      bool used = false;
-      bool first_ref_wasted = false;
-      int ref_reached_zero_count = 0;
-    };
-
     void ReportUsageStats() const;
 
     // May be null if image not yet uploaded / prepared.
     sk_sp<SkImage> image_;
-    UsageStats usage_stats_;
+    GrGLuint gl_id_ = 0;
   };
 
   struct ImageData : public base::RefCountedThreadSafe<ImageData> {
@@ -322,7 +328,6 @@
   // freeing unreferenced cache entries to make room.
   bool EnsureCapacity(size_t required_size);
   bool CanFitInWorkingSet(size_t size) const;
-  bool CanFitInCache(size_t size) const;
   bool ExceedsPreferredCount() const;
 
   void DecodeImageIfNecessary(const DrawImage& draw_image,
@@ -343,10 +348,31 @@
   bool IsCompatible(const ImageData* image_data,
                     const DrawImage& draw_image) const;
 
-  // The following two functions also require the |context_| lock to be held.
+  // Helper to delete an image and remove it from the cache. Ensures that
+  // the image is unlocked and Skia cleanup is handled on the right thread.
+  void DeleteImage(ImageData* image_data);
+
+  // Helper to unlock an image, indicating that it is no longer actively
+  // being used. An image must be locked via TryLockImage below before it
+  // can be used again.
+  void UnlockImage(ImageData* image_data);
+
+  // Attempts to lock an image for use. If locking fails (the image is deleted
+  // on the service side), this function will delete the local reference to the
+  // image and return false.
+  enum class HaveContextLock { kYes, kNo };
+  bool TryLockImage(HaveContextLock have_context_lock,
+                    const DrawImage& draw_image,
+                    ImageData* data);
+
+  // Requires that the |context_| lock be held when calling.
   void UploadImageIfNecessary(const DrawImage& draw_image,
                               ImageData* image_data);
-  void DeletePendingImages();
+
+  // Runs pending operations that required the |context_| lock to be held, but
+  // were queued up during a time when the |context_| lock was unavailable.
+  // These including deleting, unlocking, and locking textures.
+  void RunPendingContextThreadOperations();
 
   const SkColorType color_type_;
   viz::ContextProvider* context_;
@@ -370,15 +396,15 @@
       std::unordered_map<InUseCacheKey, InUseCacheEntry, InUseCacheKeyHash>;
   InUseCache in_use_cache_;
 
-  size_t max_working_set_bytes_;
-  const size_t normal_max_cache_bytes_;
-  size_t cached_bytes_limit_ = normal_max_cache_bytes_;
-  size_t bytes_used_ = 0;
+  size_t max_working_set_bytes_ = 0;
+  size_t working_set_bytes_ = 0;
   base::MemoryState memory_state_ = base::MemoryState::NORMAL;
+  bool aggressively_freeing_resources_ = false;
 
-  // We can't release GPU backed SkImages without holding the context lock,
-  // so we add them to this list and defer deletion until the next time the lock
-  // is held.
+  // We can't modify GPU backed SkImages without holding the context lock, so
+  // we queue up operations to run the next time the lock is held.
+  std::vector<SkImage*> images_pending_complete_lock_;
+  std::vector<SkImage*> images_pending_unlock_;
   std::vector<sk_sp<SkImage>> images_pending_deletion_;
 };
 
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index e8ad345..511d80c 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -4,11 +4,14 @@
 
 #include "cc/tiles/gpu_image_decode_cache.h"
 
+#include "base/memory/ptr_util.h"
 #include "cc/paint/draw_image.h"
 #include "cc/paint/paint_image_builder.h"
 #include "cc/test/skia_common.h"
 #include "cc/test/test_context_provider.h"
+#include "cc/test/test_gles2_interface.h"
 #include "cc/test/test_tile_task_runner.h"
+#include "cc/test/test_web_graphics_context_3d.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkImageGenerator.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
@@ -16,19 +19,173 @@
 namespace cc {
 namespace {
 
+class FakeDiscardableManager {
+ public:
+  void Initialize(GLuint texture_id) {
+    EXPECT_EQ(textures_.end(), textures_.find(texture_id));
+    textures_[texture_id] = kHandleLockedStart;
+    live_textures_count_++;
+  }
+  void Unlock(GLuint texture_id) {
+    EXPECT_NE(textures_.end(), textures_.find(texture_id));
+    EXPECT_GE(textures_[texture_id], kHandleLockedStart);
+    textures_[texture_id]--;
+  }
+  bool Lock(GLuint texture_id) {
+    EnforceLimit();
+
+    EXPECT_NE(textures_.end(), textures_.find(texture_id));
+    if (textures_[texture_id] >= kHandleUnlocked) {
+      textures_[texture_id]++;
+      return true;
+    }
+    return false;
+  }
+
+  void DeleteImage(GLuint texture_id) {
+    EXPECT_NE(textures_.end(), textures_.find(texture_id));
+    EXPECT_EQ(textures_[texture_id], kHandleUnlocked);
+    textures_[texture_id] = kHandleDeleted;
+    live_textures_count_--;
+  }
+
+  void set_cached_textures_limit(size_t limit) {
+    cached_textures_limit_ = limit;
+  }
+
+ private:
+  void EnforceLimit() {
+    for (auto it = textures_.begin(); it != textures_.end(); ++it) {
+      if (live_textures_count_ <= cached_textures_limit_)
+        return;
+      if (it->second != kHandleUnlocked)
+        continue;
+
+      it->second = kHandleDeleted;
+      live_textures_count_--;
+    }
+  }
+
+  const int32_t kHandleDeleted = 0;
+  const int32_t kHandleUnlocked = 1;
+  const int32_t kHandleLockedStart = 2;
+
+  std::map<GLuint, int32_t> textures_;
+  size_t live_textures_count_ = 0;
+  size_t cached_textures_limit_ = std::numeric_limits<size_t>::max();
+};
+
+class FakeDiscardableGLES2Interface : public TestGLES2Interface,
+                                      public TestContextSupport {
+ public:
+  explicit FakeDiscardableGLES2Interface(
+      FakeDiscardableManager* discardable_manager)
+      : extension_string_("GL_EXT_texture_format_BGRA8888 GL_OES_rgb8_rgba8"),
+        discardable_manager_(discardable_manager) {}
+
+  void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override {
+    discardable_manager_->Initialize(texture_id);
+  }
+  void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) override {
+    discardable_manager_->Unlock(texture_id);
+  }
+  bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override {
+    return discardable_manager_->Lock(texture_id);
+  }
+
+  void DeleteTextures(GLsizei n, const GLuint* textures) override {}
+
+  bool ThreadSafeShallowLockDiscardableTexture(uint32_t texture_id) override {
+    return discardable_manager_->Lock(texture_id);
+  }
+  void CompleteLockDiscardableTexureOnContextThread(
+      uint32_t texture_id) override {}
+
+  // TestGLES2Interface:
+  const GLubyte* GetString(GLenum name) override {
+    switch (name) {
+      case GL_EXTENSIONS:
+        return reinterpret_cast<const GLubyte*>(extension_string_.c_str());
+      case GL_VERSION:
+        return reinterpret_cast<const GLubyte*>("4.0 Null GL");
+      case GL_SHADING_LANGUAGE_VERSION:
+        return reinterpret_cast<const GLubyte*>("4.20.8 Null GLSL");
+      case GL_VENDOR:
+        return reinterpret_cast<const GLubyte*>("Null Vendor");
+      case GL_RENDERER:
+        return reinterpret_cast<const GLubyte*>("The Null (Non-)Renderer");
+    }
+    return nullptr;
+  }
+  void GetIntegerv(GLenum name, GLint* params) override {
+    switch (name) {
+      case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *params = 8;
+        return;
+      case GL_MAX_RENDERBUFFER_SIZE:
+        *params = 2048;
+        return;
+      default:
+        break;
+    }
+    TestGLES2Interface::GetIntegerv(name, params);
+  }
+
+ private:
+  const std::string extension_string_;
+  FakeDiscardableManager* discardable_manager_;
+};
+
+class DiscardableTextureMockContextProvider : public TestContextProvider {
+ public:
+  static scoped_refptr<DiscardableTextureMockContextProvider> Create(
+      FakeDiscardableManager* discardable_manager) {
+    return new DiscardableTextureMockContextProvider(
+        base::MakeUnique<FakeDiscardableGLES2Interface>(discardable_manager),
+        base::MakeUnique<FakeDiscardableGLES2Interface>(discardable_manager),
+        TestWebGraphicsContext3D::Create());
+  }
+
+ private:
+  ~DiscardableTextureMockContextProvider() override {}
+  DiscardableTextureMockContextProvider(
+      std::unique_ptr<TestContextSupport> support,
+      std::unique_ptr<TestGLES2Interface> gl,
+      std::unique_ptr<TestWebGraphicsContext3D> context)
+      : TestContextProvider(std::move(support),
+                            std::move(gl),
+                            std::move(context)) {}
+};
+
 gfx::ColorSpace DefaultColorSpace() {
   return gfx::ColorSpace::CreateSRGB();
 }
 
 size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024;
-class TestGpuImageDecodeCache : public GpuImageDecodeCache {
+
+class GpuImageDecodeCacheTest : public ::testing::TestWithParam<SkColorType> {
  public:
-  explicit TestGpuImageDecodeCache(viz::ContextProvider* context,
-                                   SkColorType color_type)
-      : GpuImageDecodeCache(context,
-                            color_type,
-                            kGpuMemoryLimitBytes,
-                            kGpuMemoryLimitBytes) {}
+  void SetUp() override {
+    context_provider_ =
+        DiscardableTextureMockContextProvider::Create(&discardable_manager_);
+    context_provider_->BindToCurrentThread();
+  }
+  std::unique_ptr<GpuImageDecodeCache> CreateCache() {
+    return base::WrapUnique(new GpuImageDecodeCache(
+        context_provider_.get(), GetParam(), kGpuMemoryLimitBytes));
+  }
+
+  DiscardableTextureMockContextProvider* context_provider() {
+    return context_provider_.get();
+  }
+
+  void SetDiscardableTexturesLimit(size_t limit) {
+    discardable_manager_.set_cached_textures_limit(limit);
+  }
+
+ private:
+  FakeDiscardableManager discardable_manager_;
+  scoped_refptr<DiscardableTextureMockContextProvider> context_provider_;
 };
 
 SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
@@ -43,12 +200,8 @@
   return matrix;
 }
 
-using GpuImageDecodeCacheTest = ::testing::TestWithParam<SkColorType>;
-
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
@@ -58,7 +211,7 @@
                        CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -68,7 +221,7 @@
       CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       another_draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task.get() == another_task.get());
@@ -76,14 +229,12 @@
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task.get());
 
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
@@ -93,7 +244,7 @@
                        CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -103,7 +254,7 @@
       CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       another_draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task.get() == another_task.get());
@@ -111,14 +262,12 @@
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task.get());
 
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(another_draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(another_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
@@ -126,7 +275,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kHigh_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -135,7 +284,7 @@
       image, SkIRect::MakeWH(image.width(), image.height()),
       kLow_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       another_draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task.get() == another_task.get());
@@ -143,14 +292,12 @@
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task.get());
 
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(another_draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(another_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -160,7 +307,7 @@
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> first_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(first_task);
@@ -172,7 +319,7 @@
       CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> second_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(second_task);
@@ -183,14 +330,12 @@
   TestTileTaskRunner::ProcessTask(second_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(second_task.get());
 
-  cache.UnrefImage(first_draw_image);
-  cache.UnrefImage(second_draw_image);
+  cache->UnrefImage(first_draw_image);
+  cache->UnrefImage(second_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -200,7 +345,7 @@
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> first_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(first_task);
@@ -208,14 +353,14 @@
   TestTileTaskRunner::ProcessTask(first_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(first_task.get());
 
-  cache.UnrefImage(first_draw_image);
+  cache->UnrefImage(first_draw_image);
 
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> second_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(second_task);
@@ -226,7 +371,7 @@
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> third_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       third_draw_image, ImageDecodeCache::TracingInfo(), &third_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(third_task.get() == second_task.get());
@@ -234,14 +379,12 @@
   TestTileTaskRunner::ProcessTask(second_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(second_task.get());
 
-  cache.UnrefImage(second_draw_image);
-  cache.UnrefImage(third_draw_image);
+  cache->UnrefImage(second_draw_image);
+  cache->UnrefImage(third_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -251,7 +394,7 @@
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> first_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(first_task);
@@ -261,7 +404,7 @@
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> second_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(second_task);
@@ -272,7 +415,7 @@
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> third_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       third_draw_image, ImageDecodeCache::TracingInfo(), &third_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(third_task.get() == first_task.get());
@@ -282,15 +425,13 @@
   TestTileTaskRunner::ProcessTask(second_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(second_task.get());
 
-  cache.UnrefImage(first_draw_image);
-  cache.UnrefImage(second_draw_image);
-  cache.UnrefImage(third_draw_image);
+  cache->UnrefImage(first_draw_image);
+  cache->UnrefImage(second_draw_image);
+  cache->UnrefImage(third_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
 
@@ -299,7 +440,7 @@
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       kLow_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> first_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(first_task);
@@ -307,13 +448,13 @@
   TestTileTaskRunner::ProcessTask(first_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(first_task.get());
 
-  cache.UnrefImage(first_draw_image);
+  cache->UnrefImage(first_draw_image);
 
   DrawImage second_draw_image(
       first_image, SkIRect::MakeWH(first_image.width(), first_image.height()),
       kHigh_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> second_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(second_task);
@@ -322,13 +463,11 @@
   TestTileTaskRunner::ProcessTask(second_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(second_task.get());
 
-  cache.UnrefImage(second_draw_image);
+  cache->UnrefImage(second_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -338,7 +477,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -356,7 +495,7 @@
   // Get the image again - we should have an upload task, but no dependent
   // decode task, as the decode was already locked.
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(another_task);
@@ -367,14 +506,12 @@
   // Finally, complete the original decode task.
   TestTileTaskRunner::CompleteTask(task->dependencies()[0].get());
 
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -384,7 +521,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -399,12 +536,12 @@
   TestTileTaskRunner::CompleteTask(task.get());
 
   // Unref the image.
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 
   // Get the image again - we should have an upload task and a dependent decode
   // task - this dependent task will typically just re-lock the image.
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(another_task);
@@ -414,13 +551,11 @@
   TestTileTaskRunner::ProcessTask(another_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(another_task.get());
 
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -430,7 +565,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -440,23 +575,20 @@
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ScheduleTask(task.get());
   TestTileTaskRunner::RunTask(task.get());
+  TestTileTaskRunner::CompleteTask(task.get());
 
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_FALSE(another_task);
 
-  TestTileTaskRunner::CompleteTask(task.get());
-
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -466,7 +598,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -474,7 +606,7 @@
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
 
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(another_task.get() == task.get());
@@ -484,12 +616,12 @@
   TestTileTaskRunner::CompleteTask(task.get());
 
   // Fully cancel everything (so the raster would unref things).
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 
   // Here a new task is created.
   scoped_refptr<TileTask> third_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &third_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(third_task);
@@ -498,13 +630,11 @@
   TestTileTaskRunner::ProcessTask(third_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(third_task.get());
 
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -514,7 +644,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -523,7 +653,7 @@
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
 
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(another_task.get() == task.get());
@@ -533,13 +663,13 @@
   TestTileTaskRunner::CompleteTask(task.get());
 
   // 2 Unrefs, so that the decode is unlocked as well.
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 
   // Note that here, everything is reffed, but a new task is created. This is
   // possible with repeated schedule/cancel operations.
   scoped_refptr<TileTask> third_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &third_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(third_task);
@@ -550,13 +680,11 @@
   TestTileTaskRunner::ProcessTask(third_task.get());
 
   // Unref!
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -566,7 +694,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -576,21 +704,19 @@
   TestTileTaskRunner::CancelTask(task.get());
   TestTileTaskRunner::CompleteTask(task.get());
 
-  cache.SetImageDecodingFailedForTesting(draw_image);
+  cache->SetImageDecodingFailedForTesting(draw_image);
 
   scoped_refptr<TileTask> another_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_FALSE(need_unref);
   EXPECT_EQ(another_task.get(), nullptr);
 
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -600,7 +726,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -610,23 +736,20 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  cache.UnrefImage(draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -636,7 +759,7 @@
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -646,28 +769,25 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_TRUE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_TRUE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  cache.UnrefImage(draw_image);
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->UnrefImage(draw_image);
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  cache.SetAllByteLimitsForTesting(0);
+  cache->SetWorkingSetLimitForTesting(0);
 
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
@@ -676,29 +796,26 @@
                        DefaultColorSpace());
 
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_FALSE(need_unref);
   EXPECT_FALSE(task);
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_TRUE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -708,7 +825,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -721,7 +838,7 @@
       CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> larger_task;
-  bool larger_need_unref = cache.GetTaskForImageAndRef(
+  bool larger_need_unref = cache->GetTaskForImageAndRef(
       larger_draw_image, ImageDecodeCache::TracingInfo(), &larger_task);
   EXPECT_TRUE(larger_need_unref);
   EXPECT_TRUE(larger_task);
@@ -731,37 +848,31 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  // |draw_image| had a low filter quality, so expect that to be respected.
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kLow_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
   DecodedDrawImage larger_decoded_draw_image =
-      cache.GetDecodedImageForDraw(larger_draw_image);
-  EXPECT_EQ(larger_decoded_draw_image.filter_quality(),
-            kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(larger_draw_image);
   EXPECT_TRUE(larger_decoded_draw_image.image());
   EXPECT_TRUE(larger_decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(larger_decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
   EXPECT_FALSE(decoded_draw_image.image() == larger_decoded_draw_image.image());
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  cache.UnrefImage(draw_image);
-  cache.DrawWithImageFinished(larger_draw_image, larger_decoded_draw_image);
-  cache.UnrefImage(larger_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->UnrefImage(draw_image);
+  cache->DrawWithImageFinished(larger_draw_image, larger_decoded_draw_image);
+  cache->UnrefImage(larger_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable);
 
@@ -769,7 +880,7 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kLow_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -781,7 +892,7 @@
       image, SkIRect::MakeWH(image.width(), image.height()),
       kHigh_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> hq_task;
-  bool hq_needs_unref = cache.GetTaskForImageAndRef(
+  bool hq_needs_unref = cache->GetTaskForImageAndRef(
       higher_quality_draw_image, ImageDecodeCache::TracingInfo(), &hq_task);
   EXPECT_TRUE(hq_needs_unref);
   EXPECT_TRUE(hq_task);
@@ -791,37 +902,32 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kLow_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
   DecodedDrawImage larger_decoded_draw_image =
-      cache.GetDecodedImageForDraw(higher_quality_draw_image);
-  EXPECT_EQ(larger_decoded_draw_image.filter_quality(),
-            kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(higher_quality_draw_image);
   EXPECT_TRUE(larger_decoded_draw_image.image());
   EXPECT_TRUE(larger_decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(larger_decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
   EXPECT_FALSE(decoded_draw_image.image() == larger_decoded_draw_image.image());
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  cache.UnrefImage(draw_image);
-  cache.DrawWithImageFinished(higher_quality_draw_image,
-                              larger_decoded_draw_image);
-  cache.UnrefImage(higher_quality_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->UnrefImage(draw_image);
+  cache->DrawWithImageFinished(higher_quality_draw_image,
+                               larger_decoded_draw_image);
+  cache->UnrefImage(higher_quality_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -831,7 +937,7 @@
                        CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -841,25 +947,22 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_EQ(decoded_draw_image.image()->width(), 50);
   EXPECT_EQ(decoded_draw_image.image()->height(), 50);
   EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  cache.UnrefImage(draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -869,7 +972,7 @@
                        CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -879,9 +982,9 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   // The mip level scale should never go below 0 in any dimension.
   EXPECT_EQ(1, decoded_draw_image.image()->width());
@@ -889,21 +992,19 @@
   EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
   EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_TRUE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_TRUE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  cache.UnrefImage(draw_image);
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->UnrefImage(draw_image);
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 }
 
 TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  cache.SetAllByteLimitsForTesting(0);
+  cache->SetWorkingSetLimitForTesting(0);
 
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
@@ -912,45 +1013,42 @@
                        DefaultColorSpace());
 
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_FALSE(need_unref);
   EXPECT_FALSE(task);
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_TRUE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.SetAllByteLimitsForTesting(96 * 1024 * 1024);
+  cache->SetWorkingSetLimitForTesting(96 * 1024 * 1024);
 
   // Finish our draw after increasing the memory limit, image should be added to
   // cache.
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
 
   scoped_refptr<TileTask> another_task;
-  bool another_task_needs_unref = cache.GetTaskForImageAndRef(
-      draw_image, ImageDecodeCache::TracingInfo(), &task);
+  bool another_task_needs_unref = cache->GetTaskForImageAndRef(
+      draw_image, ImageDecodeCache::TracingInfo(), &another_task);
   EXPECT_TRUE(another_task_needs_unref);
   EXPECT_FALSE(another_task);
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest,
        GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
-  cache.SetAllByteLimitsForTesting(0);
+  cache->SetWorkingSetLimitForTesting(0);
 
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
@@ -960,29 +1058,26 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_TRUE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
   DecodedDrawImage another_decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_EQ(decoded_draw_image.image()->uniqueID(),
             another_decoded_draw_image.image()->uniqueID());
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  cache.DrawWithImageFinished(draw_image, another_decoded_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->DrawWithImageFinished(draw_image, another_decoded_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest,
        GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -994,35 +1089,30 @@
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(decoded_draw_image.filter_quality(), kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(decoded_draw_image.image());
   EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
   EXPECT_TRUE(decoded_draw_image.is_at_raster_decode());
-  EXPECT_TRUE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_TRUE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 
   DecodedDrawImage second_decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
-  EXPECT_EQ(second_decoded_draw_image.filter_quality(),
-            kMedium_SkFilterQuality);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_TRUE(second_decoded_draw_image.image());
   EXPECT_FALSE(second_decoded_draw_image.image()->isTextureBacked());
   EXPECT_TRUE(second_decoded_draw_image.is_at_raster_decode());
-  EXPECT_TRUE(cache.DiscardableIsLockedForTesting(draw_image));
+  EXPECT_TRUE(cache->DiscardableIsLockedForTesting(draw_image));
 
-  cache.DrawWithImageFinished(draw_image, second_decoded_draw_image);
-  EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
+  cache->DrawWithImageFinished(draw_image, second_decoded_draw_image);
+  EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
 }
 
 TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1033,25 +1123,23 @@
                        DefaultColorSpace());
 
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_FALSE(task);
   EXPECT_FALSE(need_unref);
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_FALSE(decoded_draw_image.image());
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1062,25 +1150,23 @@
       DefaultColorSpace());
 
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_FALSE(task);
   EXPECT_FALSE(need_unref);
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image);
+      cache->GetDecodedImageForDraw(draw_image);
   EXPECT_FALSE(decoded_draw_image.image());
 
-  cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1091,9 +1177,9 @@
       DefaultColorSpace());
 
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
-  EXPECT_NE(0u, cache.GetBytesUsedForTesting());
+  EXPECT_NE(0u, cache->GetWorkingSetBytesForTesting());
   EXPECT_TRUE(task);
   EXPECT_TRUE(need_unref);
 
@@ -1102,14 +1188,12 @@
   TestTileTaskRunner::CancelTask(task.get());
   TestTileTaskRunner::CompleteTask(task.get());
 
-  cache.UnrefImage(draw_image);
-  EXPECT_EQ(0u, cache.GetBytesUsedForTesting());
+  cache->UnrefImage(draw_image);
+  EXPECT_EQ(0u, cache->GetWorkingSetBytesForTesting());
 }
 
 TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1120,7 +1204,7 @@
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
   {
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
@@ -1129,51 +1213,49 @@
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task.get());
 
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 
-  // We should now have data image in our cache.
-  EXPECT_GT(cache.GetBytesUsedForTesting(), 0u);
+  // We should now have data image in our cache->
+  EXPECT_GT(cache->GetNumCacheEntriesForTesting(), 0u);
 
   // Tell our cache to aggressively free resources.
-  cache.SetShouldAggressivelyFreeResources(true);
-  EXPECT_EQ(0u, cache.GetBytesUsedForTesting());
+  cache->SetShouldAggressivelyFreeResources(true);
+  EXPECT_EQ(0u, cache->GetNumCacheEntriesForTesting());
 
   // Attempting to upload a new image should succeed, but the image should not
   // be cached past its use.
   {
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
 
     TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
     TestTileTaskRunner::ProcessTask(task.get());
-    cache.UnrefImage(draw_image);
+    cache->UnrefImage(draw_image);
 
-    EXPECT_EQ(cache.GetBytesUsedForTesting(), 0u);
+    EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
   }
 
   // We now tell the cache to not aggressively free resources. The image may
   // now be cached past its use.
-  cache.SetShouldAggressivelyFreeResources(false);
+  cache->SetShouldAggressivelyFreeResources(false);
   {
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
 
     TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
     TestTileTaskRunner::ProcessTask(task.get());
-    cache.UnrefImage(draw_image);
+    cache->UnrefImage(draw_image);
 
-    EXPECT_GT(cache.GetBytesUsedForTesting(), 0u);
+    EXPECT_GT(cache->GetNumCacheEntriesForTesting(), 0u);
   }
 }
 
 TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1184,14 +1266,14 @@
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> first_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(first_task);
 
   // The budget should account for exactly one image.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(),
-            cache.GetDrawImageSizeForTesting(first_draw_image));
+  EXPECT_EQ(cache->GetWorkingSetBytesForTesting(),
+            cache->GetDrawImageSizeForTesting(first_draw_image));
 
   // Create a larger version of |first_image|, this should immediately free the
   // memory used by |first_image| for the smaller scale.
@@ -1200,7 +1282,7 @@
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> second_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(second_task);
@@ -1209,28 +1291,21 @@
   TestTileTaskRunner::ProcessTask(second_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(second_task.get());
 
-  cache.UnrefImage(second_draw_image);
-
-  // The budget should account for both images one image.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(),
-            cache.GetDrawImageSizeForTesting(second_draw_image) +
-                cache.GetDrawImageSizeForTesting(first_draw_image));
+  cache->UnrefImage(second_draw_image);
 
   // Unref the first image, it was orphaned, so it should be immediately
   // deleted.
   TestTileTaskRunner::ProcessTask(first_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(first_task.get());
-  cache.UnrefImage(first_draw_image);
+  cache->UnrefImage(first_draw_image);
 
-  // The budget should account for exactly one image.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(),
-            cache.GetDrawImageSizeForTesting(second_draw_image));
+  // The cache should have exactly one image.
+  EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
+  EXPECT_EQ(0u, cache->GetInUseCacheEntriesForTesting());
 }
 
 TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1241,18 +1316,18 @@
       quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> first_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(first_task);
 
   TestTileTaskRunner::ProcessTask(first_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(first_task.get());
-  cache.UnrefImage(first_draw_image);
+  cache->UnrefImage(first_draw_image);
 
   // The budget should account for exactly one image.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(),
-            cache.GetDrawImageSizeForTesting(first_draw_image));
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
+  EXPECT_EQ(cache->GetInUseCacheEntriesForTesting(), 0u);
 
   // Create a larger version of |first_image|, this should immediately free the
   // memory used by |first_image| for the smaller scale.
@@ -1261,7 +1336,7 @@
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       DefaultColorSpace());
   scoped_refptr<TileTask> second_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(second_task);
@@ -1270,17 +1345,15 @@
   TestTileTaskRunner::ProcessTask(second_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(second_task.get());
 
-  cache.UnrefImage(second_draw_image);
+  cache->UnrefImage(second_draw_image);
 
   // The budget should account for exactly one image.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(),
-            cache.GetDrawImageSizeForTesting(second_draw_image));
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
+  EXPECT_EQ(cache->GetInUseCacheEntriesForTesting(), 0u);
 }
 
 TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
   bool is_decomposable = true;
   SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
@@ -1290,7 +1363,7 @@
                            SkIRect::MakeWH(image.width(), image.height()),
                            kLow_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> low_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       low_draw_image, ImageDecodeCache::TracingInfo(), &low_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(low_task);
@@ -1301,7 +1374,7 @@
       image, SkIRect::MakeWH(image.width(), image.height()),
       kMedium_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> medium_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       medium_draw_image, ImageDecodeCache::TracingInfo(), &medium_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(medium_task.get());
@@ -1312,7 +1385,7 @@
       image, SkIRect::MakeWH(image.width(), image.height()),
       kHigh_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> large_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       large_draw_image, ImageDecodeCache::TracingInfo(), &large_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(medium_task.get() == large_task.get());
@@ -1322,17 +1395,15 @@
   TestTileTaskRunner::ProcessTask(medium_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(medium_task.get());
 
-  cache.UnrefImage(low_draw_image);
-  cache.UnrefImage(medium_draw_image);
-  cache.UnrefImage(large_draw_image);
+  cache->UnrefImage(low_draw_image);
+  cache->UnrefImage(medium_draw_image);
+  cache->UnrefImage(large_draw_image);
 }
 
 // Ensure that switching to a mipped version of an image after the initial
 // cache entry creation doesn't cause a buffer overflow/crash.
 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1343,7 +1414,7 @@
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -1354,11 +1425,11 @@
   TestTileTaskRunner::CancelTask(task.get());
   TestTileTaskRunner::CompleteTask(task.get());
 
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 
   // Must hold context lock before calling GetDecodedImageForDraw /
   // DrawWithImageFinished.
-  viz::ContextProvider::ScopedContextLock context_lock(context_provider.get());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
 
   // Do an at-raster decode of the above image that *does* require mips.
   DrawImage draw_image_mips(
@@ -1366,14 +1437,12 @@
       CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
       DefaultColorSpace());
   DecodedDrawImage decoded_draw_image =
-      cache.GetDecodedImageForDraw(draw_image_mips);
-  cache.DrawWithImageFinished(draw_image_mips, decoded_draw_image);
+      cache->GetDecodedImageForDraw(draw_image_mips);
+  cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, MemoryStateSuspended) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
 
   // First Insert an image into our cache.
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(1, 1));
@@ -1382,68 +1451,58 @@
   DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
                        kLow_SkFilterQuality, matrix, DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
 
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task.get());
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 
   // The image should be cached.
-  EXPECT_GT(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 1u);
-
-  // Set us to the not visible state (prerequisite for SUSPENDED).
-  cache.SetShouldAggressivelyFreeResources(true);
-
-  // Image should be cached, but not using memory budget.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 1u);
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
 
   // Set us to the SUSPENDED state with purging.
-  cache.OnPurgeMemory();
-  cache.OnMemoryStateChange(base::MemoryState::SUSPENDED);
+  cache->OnPurgeMemory();
+  cache->OnMemoryStateChange(base::MemoryState::SUSPENDED);
 
   // Nothing should be cached.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 0u);
+  EXPECT_EQ(cache->GetWorkingSetBytesForTesting(), 0u);
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
 
   // Attempts to get a task for the image will still succeed, as SUSPENDED
   // doesn't impact working set size.
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
 
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task.get());
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 
   // Nothing should be cached.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 0u);
+  EXPECT_EQ(cache->GetWorkingSetBytesForTesting(), 0u);
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
 
   // Restore us to visible and NORMAL memory state.
-  cache.OnMemoryStateChange(base::MemoryState::NORMAL);
-  cache.SetShouldAggressivelyFreeResources(false);
+  cache->OnMemoryStateChange(base::MemoryState::NORMAL);
+  cache->SetShouldAggressivelyFreeResources(false);
 
   // We should now be able to create a task again (space available).
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
 
   TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task.get());
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
 
   PaintImage image = CreateDiscardablePaintImage(gfx::Size(1, 1));
   bool is_decomposable = true;
@@ -1453,25 +1512,22 @@
 
   scoped_refptr<TileTask> task;
   bool need_unref =
-      cache.GetOutOfRasterDecodeTaskForImageAndRef(draw_image, &task);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image, &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
-  EXPECT_TRUE(cache.IsInInUseCacheForTesting(draw_image));
+  EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
 
   // Run the decode task.
   TestTileTaskRunner::ProcessTask(task.get());
 
   // The image should remain in the cache till we unref it.
-  EXPECT_TRUE(cache.IsInInUseCacheForTesting(draw_image));
-  cache.UnrefImage(draw_image);
+  EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
-  // Setup - Image cache has a normal working set, but zero cache size.
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  GpuImageDecodeCache cache(context_provider.get(), kN32_SkColorType,
-                            kGpuMemoryLimitBytes, 0);
+  SetDiscardableTexturesLimit(0);
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1483,7 +1539,7 @@
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -1496,19 +1552,22 @@
 
   // Request the same image - it should be cached.
   scoped_refptr<TileTask> task2;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task2);
   EXPECT_TRUE(need_unref);
   EXPECT_FALSE(task2);
 
   // Unref both images.
-  cache.UnrefImage(draw_image);
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
+
+  // Ensure the unref is processed:
+  cache->ReduceCacheUsage();
 
   // Get the image again. As it was fully unreffed, it is no longer in the
   // working set and will be evicted due to 0 cache size.
   scoped_refptr<TileTask> task3;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task3);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task3);
@@ -1518,17 +1577,13 @@
   TestTileTaskRunner::ProcessTask(task3->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(task3.get());
 
-  cache.UnrefImage(draw_image);
+  cache->UnrefImage(draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
-  // Cache will fit one (but not two) 100x100 images.
-  size_t cache_size = 190 * 100 * 4;
-
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  GpuImageDecodeCache cache(context_provider.get(), kN32_SkColorType,
-                            kGpuMemoryLimitBytes, cache_size);
+  // Cache will fit one image.
+  SetDiscardableTexturesLimit(1);
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1547,7 +1602,7 @@
   // Add an image to the cache and un-ref it.
   {
     scoped_refptr<TileTask> task;
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
@@ -1557,23 +1612,23 @@
     // Run the task and unref the image.
     TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
     TestTileTaskRunner::ProcessTask(task.get());
-    cache.UnrefImage(draw_image);
+    cache->UnrefImage(draw_image);
   }
 
   // Request the same image - it should be cached.
   {
     scoped_refptr<TileTask> task;
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_FALSE(task);
-    cache.UnrefImage(draw_image);
+    cache->UnrefImage(draw_image);
   }
 
-  // Add a new image to the cache. It should push out the old one.
+  // Add a new image to the cache It should push out the old one.
   {
     scoped_refptr<TileTask> task;
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image2, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
@@ -1583,24 +1638,24 @@
     // Run the task and unref the image.
     TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
     TestTileTaskRunner::ProcessTask(task.get());
-    cache.UnrefImage(draw_image2);
+    cache->UnrefImage(draw_image2);
   }
 
   // Request the second image - it should be cached.
   {
     scoped_refptr<TileTask> task;
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image2, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_FALSE(task);
-    cache.UnrefImage(draw_image2);
+    cache->UnrefImage(draw_image2);
   }
 
   // Request the first image - it should have been evicted and return a new
   // task.
   {
     scoped_refptr<TileTask> task;
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
@@ -1610,14 +1665,12 @@
     // Run the task and unref the image.
     TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
     TestTileTaskRunner::ProcessTask(task.get());
-    cache.UnrefImage(draw_image);
+    cache->UnrefImage(draw_image);
   }
 }
 
 TEST_P(GpuImageDecodeCacheTest, ClearCache) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1628,31 +1681,27 @@
         CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
         DefaultColorSpace());
     scoped_refptr<TileTask> task;
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
     TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
     TestTileTaskRunner::ProcessTask(task.get());
-    cache.UnrefImage(draw_image);
+    cache->UnrefImage(draw_image);
   }
 
-  // We should now have data image in our cache.
-  EXPECT_GT(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 10u);
+  // We should now have images in our cache.
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 10u);
 
   // Tell our cache to clear resources.
-  cache.ClearCache();
+  cache->ClearCache();
 
   // We should now have nothing in our cache.
-  EXPECT_EQ(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 0u);
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
 }
 
 TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1663,7 +1712,7 @@
                        CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
                        DefaultColorSpace());
   scoped_refptr<TileTask> task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       draw_image, ImageDecodeCache::TracingInfo(), &task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(task);
@@ -1671,26 +1720,24 @@
   TestTileTaskRunner::ProcessTask(task.get());
 
   // We should now have data image in our cache.
-  EXPECT_GT(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 1u);
+  EXPECT_GT(cache->GetWorkingSetBytesForTesting(), 0u);
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
 
   // Tell our cache to clear resources.
-  cache.ClearCache();
+  cache->ClearCache();
   // We should still have data, as we can't clear the in-use entry.
-  EXPECT_GT(cache.GetBytesUsedForTesting(), 0u);
+  EXPECT_GT(cache->GetWorkingSetBytesForTesting(), 0u);
   // But the num (persistent) entries should be 0, as the entry is orphaned.
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 0u);
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
 
   // Unref the image, it should immidiately delete, leaving our cache empty.
-  cache.UnrefImage(draw_image);
-  EXPECT_EQ(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 0u);
+  cache->UnrefImage(draw_image);
+  EXPECT_EQ(cache->GetWorkingSetBytesForTesting(), 0u);
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
 }
 
 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
 
@@ -1703,7 +1750,7 @@
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       color_space_a);
   scoped_refptr<TileTask> first_task;
-  bool need_unref = cache.GetTaskForImageAndRef(
+  bool need_unref = cache->GetTaskForImageAndRef(
       first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(first_task);
@@ -1713,7 +1760,7 @@
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       color_space_b);
   scoped_refptr<TileTask> second_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(second_task);
@@ -1724,7 +1771,7 @@
       quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
       color_space_a);
   scoped_refptr<TileTask> third_task;
-  need_unref = cache.GetTaskForImageAndRef(
+  need_unref = cache->GetTaskForImageAndRef(
       third_draw_image, ImageDecodeCache::TracingInfo(), &third_task);
   EXPECT_TRUE(need_unref);
   EXPECT_TRUE(third_task.get() == first_task.get());
@@ -1734,15 +1781,13 @@
   TestTileTaskRunner::ProcessTask(second_task->dependencies()[0].get());
   TestTileTaskRunner::ProcessTask(second_task.get());
 
-  cache.UnrefImage(first_draw_image);
-  cache.UnrefImage(second_draw_image);
-  cache.UnrefImage(third_draw_image);
+  cache->UnrefImage(first_draw_image);
+  cache->UnrefImage(second_draw_image);
+  cache->UnrefImage(third_draw_image);
 }
 
 TEST_P(GpuImageDecodeCacheTest, RemoveUnusedImage) {
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentThread();
-  TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
+  auto cache = CreateCache();
   bool is_decomposable = true;
   SkFilterQuality quality = kHigh_SkFilterQuality;
   std::vector<PaintImage::FrameKey> frame_keys;
@@ -1755,23 +1800,22 @@
         DefaultColorSpace());
     frame_keys.push_back(draw_image.frame_key());
     scoped_refptr<TileTask> task;
-    bool need_unref = cache.GetTaskForImageAndRef(
+    bool need_unref = cache->GetTaskForImageAndRef(
         draw_image, ImageDecodeCache::TracingInfo(), &task);
     EXPECT_TRUE(need_unref);
     EXPECT_TRUE(task);
     TestTileTaskRunner::ProcessTask(task->dependencies()[0].get());
     TestTileTaskRunner::ProcessTask(task.get());
-    cache.UnrefImage(draw_image);
+    cache->UnrefImage(draw_image);
   }
 
-  // We should now have data image in our cache.
-  EXPECT_GT(cache.GetBytesUsedForTesting(), 0u);
-  EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 10u);
+  // We should now have images in our cache.
+  EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 10u);
 
   // Remove unused ids.
   for (uint32_t i = 0; i < 10; ++i) {
-    cache.NotifyImageUnused(frame_keys[i]);
-    EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), (10 - i - 1));
+    cache->NotifyImageUnused(frame_keys[i]);
+    EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), (10 - i - 1));
   }
 }
 
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 650c5cb..8b916de 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -546,7 +546,7 @@
   tile_task_manager_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
-  CheckPendingGpuWorkTiles(true /* issue_signals */);
+  CheckPendingGpuWorkTiles(true /* issue_signals */, false /* flush */);
 
   TRACE_EVENT_INSTANT1(
       "cc", "TileManager::CheckForCompletedTasksFinished",
@@ -1318,7 +1318,7 @@
   tile_task_manager_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
-  CheckPendingGpuWorkTiles(false /* issue_signals */);
+  CheckPendingGpuWorkTiles(false /* issue_signals */, true /* flush */);
 
   // Ready to activate.
   if (signals_.ready_to_activate && !signals_.did_notify_ready_to_activate) {
@@ -1401,8 +1401,6 @@
   resource_pool_->ReduceResourceUsage();
   image_controller_.ReduceMemoryUsage();
 
-  raster_buffer_provider_->Flush();
-
   // TODO(vmpstr): Temporary check to debug crbug.com/642927.
   CHECK(tile_task_manager_);
 
@@ -1506,12 +1504,15 @@
          raster_buffer_provider_->CanPartialRasterIntoProvidedResource();
 }
 
-void TileManager::CheckPendingGpuWorkTiles(bool issue_signals) {
+void TileManager::CheckPendingGpuWorkTiles(bool issue_signals, bool flush) {
   TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkTiles",
                "pending_gpu_work_tiles", pending_gpu_work_tiles_.size(),
                "tree_priority",
                TreePriorityToString(global_state_.tree_priority));
 
+  if (flush)
+    raster_buffer_provider_->Flush();
+
   ResourceProvider::ResourceIdArray required_for_activation_ids;
   ResourceProvider::ResourceIdArray required_for_draw_ids;
 
@@ -1550,7 +1551,7 @@
             required_for_activation_ids,
             base::Bind(&TileManager::CheckPendingGpuWorkTiles,
                        ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
-                       true /* issue_signals */),
+                       true /* issue_signals */, false /* flush */),
             pending_required_for_activation_callback_id_);
   }
 
@@ -1561,7 +1562,7 @@
             required_for_draw_ids,
             base::Bind(&TileManager::CheckPendingGpuWorkTiles,
                        ready_to_draw_callback_weak_ptr_factory_.GetWeakPtr(),
-                       true /* issue_signals */),
+                       true /* issue_signals */, false /* flush */),
             pending_required_for_draw_callback_id_);
   }
 
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index e48fa89d..d9a7cbf 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -372,7 +372,7 @@
 
   bool UsePartialRaster() const;
 
-  void CheckPendingGpuWorkTiles(bool issue_signals);
+  void CheckPendingGpuWorkTiles(bool issue_signals, bool flush);
 
   TileManagerClient* client_;
   base::SequencedTaskRunner* task_runner_;
diff --git a/cc/trees/clip_node.cc b/cc/trees/clip_node.cc
index aed3746..a949dcb9 100644
--- a/cc/trees/clip_node.cc
+++ b/cc/trees/clip_node.cc
@@ -18,51 +18,16 @@
       transform_id(TransformTree::kInvalidNodeId) {
 }
 
-ClipNode::ClipNode(const ClipNode& other)
-    : id(other.id),
-      parent_id(other.parent_id),
-      clip_type(other.clip_type),
-      clip(other.clip),
-      transform_id(other.transform_id) {
-  if (other.clip_expander) {
-    DCHECK_EQ(clip_type, ClipType::EXPANDS_CLIP);
-    clip_expander = std::make_unique<ClipExpander>(*other.clip_expander);
-  }
-  cached_clip_rects = other.cached_clip_rects;
-  cached_accumulated_rect_in_screen_space =
-      other.cached_accumulated_rect_in_screen_space;
-}
+ClipNode::ClipNode(const ClipNode& other) = default;
 
-ClipNode& ClipNode::operator=(const ClipNode& other) {
-  id = other.id;
-  parent_id = other.parent_id;
-  clip_type = other.clip_type;
-  clip = other.clip;
-  transform_id = other.transform_id;
-
-  if (other.clip_expander) {
-    DCHECK_EQ(clip_type, ClipType::EXPANDS_CLIP);
-    clip_expander = std::make_unique<ClipExpander>(*other.clip_expander);
-  } else {
-    clip_expander.reset();
-  }
-  cached_clip_rects = other.cached_clip_rects;
-  cached_accumulated_rect_in_screen_space =
-      other.cached_accumulated_rect_in_screen_space;
-  return *this;
-}
+ClipNode& ClipNode::operator=(const ClipNode& other) = default;
 
 ClipNode::~ClipNode() {}
 
 bool ClipNode::operator==(const ClipNode& other) const {
-  if (clip_expander && other.clip_expander &&
-      *clip_expander != *other.clip_expander)
-    return false;
-  if ((clip_expander && !other.clip_expander) ||
-      (!clip_expander && other.clip_expander))
-    return false;
   return id == other.id && parent_id == other.parent_id &&
          clip_type == other.clip_type && clip == other.clip &&
+         clip_expander == other.clip_expander &&
          transform_id == other.transform_id;
 }
 
diff --git a/cc/trees/clip_node.h b/cc/trees/clip_node.h
index 506b493..5620f9d 100644
--- a/cc/trees/clip_node.h
+++ b/cc/trees/clip_node.h
@@ -5,9 +5,8 @@
 #ifndef CC_TREES_CLIP_NODE_H_
 #define CC_TREES_CLIP_NODE_H_
 
-#include <memory>
-
 #include "base/containers/stack_container.h"
+#include "base/optional.h"
 #include "cc/cc_export.h"
 #include "cc/trees/clip_expander.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -66,7 +65,7 @@
   gfx::RectF cached_accumulated_rect_in_screen_space;
 
   // For nodes that expand, this represents the amount of expansion.
-  std::unique_ptr<ClipExpander> clip_expander;
+  base::Optional<ClipExpander> clip_expander;
 
   // The id of the transform node that defines the clip node's local space.
   int transform_id;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 8feb8a2..769010a 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -761,11 +761,13 @@
   gfx::Rect root_target_rect = root_render_surface->content_rect();
   float opacity = 1.f;
   int sorting_context_id = 0;
+  bool are_contents_opaque = SkColorGetA(screen_background_color) == 0xFF;
   viz::SharedQuadState* shared_quad_state =
       target_render_pass->CreateAndAppendSharedQuadState();
   shared_quad_state->SetAll(gfx::Transform(), root_target_rect,
-                            root_target_rect, root_target_rect, false, opacity,
-                            SkBlendMode::kSrcOver, sorting_context_id);
+                            root_target_rect, root_target_rect, false,
+                            are_contents_opaque, opacity, SkBlendMode::kSrcOver,
+                            sorting_context_id);
 
   for (Region::Iterator fill_rects(fill_region); fill_rects.has_rect();
        fill_rects.next()) {
@@ -2014,7 +2016,9 @@
   // Adjust the viewport layers by shrinking/expanding the container to account
   // for changes in the size (e.g. browser controls) since the last resize from
   // Blink.
-  gfx::Vector2dF amount_to_expand(0.f, delta_from_top_controls);
+  gfx::Vector2dF amount_to_expand(
+      0.f,
+      delta_from_top_controls * active_tree_->painted_device_scale_factor());
   inner_container->SetViewportBoundsDelta(amount_to_expand);
 
   if (outer_container && !outer_container->BoundsForScrolling().IsEmpty()) {
@@ -2323,8 +2327,7 @@
         layer_tree_frame_sink_->worker_context_provider(),
         viz::ResourceFormatToClosestSkColorType(
             settings_.preferred_tile_format),
-        settings_.decoded_image_working_set_budget_bytes,
-        settings_.decoded_image_cache_budget_bytes);
+        settings_.decoded_image_working_set_budget_bytes);
   } else {
     image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>(
         viz::ResourceFormatToClosestSkColorType(
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 9365423..ef0edc0 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -5094,6 +5094,40 @@
   ASSERT_EQ(0, host_impl_->active_tree()->CurrentBrowserControlsShownRatio());
 }
 
+TEST_F(LayerTreeHostImplBrowserControlsTest, ViewportBoundsUseZoomForDSF) {
+  SetupBrowserControlsAndScrollLayerWithVirtualViewport(
+      gfx::Size(50, 50), gfx::Size(100, 100), gfx::Size(100, 100));
+  DrawFrame();
+
+  LayerImpl* inner_container =
+      host_impl_->active_tree()->InnerViewportContainerLayer();
+
+  gfx::Vector2dF scroll_delta(0.f, 10.f);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+            host_impl_
+                ->ScrollBegin(BeginState(gfx::Point()).get(),
+                              InputHandler::TOUCHSCREEN)
+                .thread);
+  host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
+
+  gfx::Vector2dF bounds_delta = inner_container->ViewportBoundsDelta();
+  host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f);
+  host_impl_->ScrollEnd(EndState().get());
+
+  float device_scale = 3.5f;
+  host_impl_->active_tree()->set_painted_device_scale_factor(device_scale);
+
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+            host_impl_
+                ->ScrollBegin(BeginState(gfx::Point()).get(),
+                              InputHandler::TOUCHSCREEN)
+                .thread);
+  host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
+
+  bounds_delta.Scale(device_scale);
+  EXPECT_EQ(bounds_delta, inner_container->ViewportBoundsDelta());
+}
+
 // Test that if only the browser controls are scrolled, we shouldn't request a
 // commit.
 TEST_F(LayerTreeHostImplBrowserControlsTest, BrowserControlsDontTriggerCommit) {
@@ -7758,7 +7792,7 @@
 
     viz::SharedQuadState* shared_quad_state =
         render_pass->CreateAndAppendSharedQuadState();
-    PopulateSharedQuadState(shared_quad_state);
+    PopulateSharedQuadState(shared_quad_state, contents_opaque());
 
     TileDrawQuad* test_blending_draw_quad =
         render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
@@ -8553,7 +8587,7 @@
                    AppendQuadsData* append_quads_data) override {
     viz::SharedQuadState* shared_quad_state =
         render_pass->CreateAndAppendSharedQuadState();
-    PopulateSharedQuadState(shared_quad_state);
+    PopulateSharedQuadState(shared_quad_state, contents_opaque());
 
     SkColor gray = SkColorSetRGB(100, 100, 100);
     gfx::Rect quad_rect(bounds());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index ad27600..990877d6 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -7686,7 +7686,6 @@
 
     // Set to 0 to force at-raster GPU image decode.
     settings->decoded_image_working_set_budget_bytes = 0;
-    settings->decoded_image_cache_budget_bytes = 0;
   }
 
   void SetupTree() override {
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 70d89a01..a4b59ac2 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -2052,7 +2052,7 @@
   selection->start = ComputeViewportSelectionBound(
       selection_.start,
       selection_.start.layer_id ? LayerById(selection_.start.layer_id) : NULL,
-      device_scale_factor());
+      device_scale_factor() * painted_device_scale_factor());
   if (selection->start.type() == gfx::SelectionBound::CENTER ||
       selection->start.type() == gfx::SelectionBound::EMPTY) {
     selection->end = selection->start;
@@ -2060,7 +2060,7 @@
     selection->end = ComputeViewportSelectionBound(
         selection_.end,
         selection_.end.layer_id ? LayerById(selection_.end.layer_id) : NULL,
-        device_scale_factor());
+        device_scale_factor() * painted_device_scale_factor());
   }
 }
 
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index b68556a..04dd096 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -2119,6 +2119,77 @@
   EXPECT_TRUE(output.end.visible());
 }
 
+TEST_F(LayerTreeImplTest, SelectionBoundsForDSFEnabled) {
+  LayerImpl* root = root_layer();
+  root->SetDrawsContent(true);
+  root->SetBounds(gfx::Size(100, 100));
+
+  int root_layer_id = root->id();
+  int sub_layer_id = 2;
+
+  gfx::Vector2dF sub_layer_offset(10, 0);
+  {
+    std::unique_ptr<LayerImpl> sub_layer =
+        LayerImpl::Create(host_impl().active_tree(), sub_layer_id);
+    sub_layer->SetPosition(gfx::PointF() + sub_layer_offset);
+    sub_layer->SetBounds(gfx::Size(50, 50));
+    sub_layer->SetDrawsContent(true);
+    root->test_properties()->AddChild(std::move(sub_layer));
+  }
+
+  host_impl().active_tree()->BuildPropertyTreesForTesting();
+
+  float device_scale_factor = 3.f;
+  float painted_device_scale_factor = 5.f;
+
+  LayerTreeImpl::ViewportLayerIds viewport_ids;
+  viewport_ids.page_scale = root->id();
+  host_impl().active_tree()->SetViewportLayersFromIds(viewport_ids);
+  host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
+  host_impl().active_tree()->set_painted_device_scale_factor(
+      painted_device_scale_factor);
+
+  LayerSelection input;
+  input.start.type = gfx::SelectionBound::LEFT;
+  input.start.edge_top = gfx::Point(10, 10);
+  input.start.edge_bottom = gfx::Point(10, 30);
+  input.start.layer_id = root_layer_id;
+
+  input.end.type = gfx::SelectionBound::RIGHT;
+  input.end.edge_top = gfx::Point(0, 0);
+  input.end.edge_bottom = gfx::Point(0, 20);
+  input.end.layer_id = sub_layer_id;
+  host_impl().active_tree()->RegisterSelection(input);
+
+  // The viewport bounds should be properly scaled by the page scale, but should
+  // remain in DIP coordinates.
+  Selection<gfx::SelectionBound> output;
+  host_impl().active_tree()->GetViewportSelection(&output);
+  EXPECT_EQ(input.start.type, output.start.type());
+  auto expected_output_start_top = gfx::PointF(input.start.edge_top);
+  auto expected_output_edge_bottom = gfx::PointF(input.start.edge_bottom);
+  expected_output_start_top.Scale(
+      1.f / (device_scale_factor * painted_device_scale_factor));
+  expected_output_edge_bottom.Scale(
+      1.f / (device_scale_factor * painted_device_scale_factor));
+  EXPECT_EQ(expected_output_start_top, output.start.edge_top());
+  EXPECT_EQ(expected_output_edge_bottom, output.start.edge_bottom());
+  EXPECT_TRUE(output.start.visible());
+  EXPECT_EQ(input.end.type, output.end.type());
+
+  auto expected_output_end_top = gfx::PointF(input.end.edge_top);
+  auto expected_output_end_bottom = gfx::PointF(input.end.edge_bottom);
+  expected_output_end_top.Offset(sub_layer_offset.x(), sub_layer_offset.y());
+  expected_output_end_bottom.Offset(sub_layer_offset.x(), sub_layer_offset.y());
+  expected_output_end_top.Scale(
+      1.f / (device_scale_factor * painted_device_scale_factor));
+  expected_output_end_bottom.Scale(
+      1.f / (device_scale_factor * painted_device_scale_factor));
+  EXPECT_EQ(expected_output_end_top, output.end.edge_top());
+  EXPECT_EQ(expected_output_end_bottom, output.end.edge_bottom());
+  EXPECT_TRUE(output.end.visible());
+}
+
 TEST_F(LayerTreeImplTest, SelectionBoundsWithLargeTransforms) {
   LayerImpl* root = root_layer();
   root->SetBounds(gfx::Size(100, 100));
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 20c0234..be8935f 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -87,7 +87,6 @@
   int max_staging_buffer_usage_in_bytes = 32 * 1024 * 1024;
   ManagedMemoryPolicy gpu_memory_policy;
   ManagedMemoryPolicy software_memory_policy;
-  size_t decoded_image_cache_budget_bytes = 128 * 1024 * 1024;
   size_t decoded_image_working_set_budget_bytes = 128 * 1024 * 1024;
   int max_preraster_distance_in_screen_pixels = 1000;
   viz::ResourceFormat preferred_tile_format;
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 089eaa4..89a5882 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -343,8 +343,7 @@
     } else {
       DCHECK(Filters(layer).HasFilterThatMovesPixels());
       node.clip_type = ClipNode::ClipType::EXPANDS_CLIP;
-      node.clip_expander =
-          std::make_unique<ClipExpander>(layer->effect_tree_index());
+      node.clip_expander = ClipExpander(layer->effect_tree_index());
     }
     data_for_children->clip_tree_parent = clip_tree_.Insert(node, parent_id);
   }
diff --git a/chrome/VERSION b/chrome/VERSION
index 34f8b80f..3448362 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=63
 MINOR=0
-BUILD=3207
+BUILD=3208
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index b11304d..141bc71 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -18,6 +18,7 @@
 import("//tools/resources/generate_resource_whitelist.gni")
 import("channel.gni")
 import("java_sources.gni")
+import("static_initializers.gni")
 
 manifest_package = "org.chromium.chrome"
 
@@ -544,6 +545,7 @@
     "//chrome/test/data/geolocation/",
     "//chrome/test/data/google/",
     "//chrome/test/data/image_search/valid.png",
+    "//chrome/test/data/media/",
     "//chrome/test/data/navigation_interception/",
     "//chrome/test/data/notifications/",
     "//chrome/test/data/popup_blocker/",
@@ -1069,6 +1071,12 @@
     "//net/android:net_test_support_apk",
   ]
   proguard_enabled = !is_java_debug
+  if (proguard_enabled && !enable_proguard_obfuscation &&
+      enable_proguard_obfuscation_for_tests) {
+    proguard_configs = [ "//base/android/proguard/enable_obfuscation.flags" ]
+    proguard_config_exclusions =
+        [ "//base/android/proguard/disable_chromium_obfuscation.flags" ]
+  }
 
   # The test APK contains code from both the APK under test and the
   # test APK when proguard is enabled. That causes this APK to exceed
@@ -1088,6 +1096,12 @@
     ]
     additional_apks = [ "//net/android:net_test_support_apk" ]
     proguard_enabled = !is_java_debug
+    if (proguard_enabled && !enable_proguard_obfuscation &&
+        enable_proguard_obfuscation_for_tests) {
+      proguard_configs = [ "//base/android/proguard/enable_obfuscation.flags" ]
+      proguard_config_exclusions =
+          [ "//base/android/proguard/disable_chromium_obfuscation.flags" ]
+    }
   }
 
   android_apk("vr_nfc_simulator_apk") {
@@ -1143,4 +1157,33 @@
     "//ui/android:ui_java",
   ]
   proguard_enabled = !is_java_debug
+  if (proguard_enabled && !enable_proguard_obfuscation &&
+      enable_proguard_obfuscation_for_tests) {
+    proguard_configs = [ "//base/android/proguard/enable_obfuscation.flags" ]
+    proguard_config_exclusions =
+        [ "//base/android/proguard/disable_chromium_obfuscation.flags" ]
+  }
+}
+
+if (defined(expected_static_initializer_count)) {
+  action("monochrome_static_initializers") {
+    script = "//build/android/gyp/assert_static_initializers.py"
+    inputs = [
+      "$root_build_dir/apks/MonochromePublic.apk",
+    ]
+    outputs = [
+      "$target_gen_dir/$target_name.stamp",
+    ]
+    deps = [
+      ":monochrome_public_apk",
+    ]
+    args = [
+      "--expected-count=$expected_static_initializer_count",
+      "--tool-prefix",
+      rebase_path(android_tool_prefix, root_build_dir),
+      "--touch",
+      rebase_path(outputs[0], root_build_dir),
+      rebase_path(inputs[0], root_build_dir),
+    ]
+  }
 }
diff --git a/chrome/android/OWNERS b/chrome/android/OWNERS
index 3ad8474..d798ab1 100644
--- a/chrome/android/OWNERS
+++ b/chrome/android/OWNERS
@@ -5,6 +5,7 @@
 tedchoc@chromium.org
 yfriedman@chromium.org
 
+per-file static_initializers.gni=*
 per-file java_sources.gni=*
 per-file *.gn*=agrieve@chromium.org
 
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 5a115915..e2905197 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -27,6 +27,9 @@
   # Enables ProGuard obfuscation of Chromium packages.
   enable_proguard_obfuscation = false
 
+  # Enables ProGuard obfuscation of chrome_public_test_apk.
+  enable_proguard_obfuscation_for_tests = false
+
   # Enable multidex in release builds.
   multidex_in_release = false
 }
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 536ebb6..21115b4193 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -61,6 +61,12 @@
     <uses-feature android:name="android.software.vr.mode" android:required="false"/>
     <!-- Indicates use of VR features that are available only on Daydream-ready devices. -->
     <uses-feature android:name="android.hardware.vr.high_performance" android:required="false"/>
+    <!--
+      Indicates that we don't need Chrome to be available on devices that only support landscape
+      orientation. This is needed because we have VR specific activities that declare the
+      android:orientation attribute.
+    -->
+    <uses-feature android:name="android.hardware.screen.landscape" android:required="false"/>
     {% endif %}
 
     <permission android:name="{{ manifest_package }}.permission.CHILD_SERVICE" android:protectionLevel="signature" />
@@ -130,10 +136,14 @@
         <!-- Samsung MultiWindow Support -->
         <meta-data android:name="com.samsung.android.sdk.multiwindow.enable"
             android:value="true" />
+
+        {% if min_sdk_version < 24 %}
         <meta-data android:name="com.samsung.android.sdk.multiwindow.multiinstance.enable"
             android:value="true" />
         <meta-data android:name="com.samsung.android.sdk.multiwindow.multiinstance.launchmode"
             android:value="singleTask" />
+        {% endif %}
+
         <meta-data android:name="com.samsung.android.sdk.multiwindow.penwindow.enable"
             android:value="true"/>
 
@@ -352,6 +362,7 @@
         {% if enable_vr == "true" %}
         <activity android:name="org.chromium.chrome.browser.vr_shell.SeparateTaskCustomTabVrActivity"
             android:theme="@style/VrSupportTheme"
+            android:screenOrientation="landscape"
             android:exported="false"
             android:enableVrMode="@string/gvr_vr_mode_component"
             android:taskAffinity=""
diff --git a/chrome/android/java/res/drawable/bottom_toolbar_shadow.xml b/chrome/android/java/res/drawable/bottom_toolbar_shadow.xml
index 242138a4..66ef7a9 100644
--- a/chrome/android/java/res/drawable/bottom_toolbar_shadow.xml
+++ b/chrome/android/java/res/drawable/bottom_toolbar_shadow.xml
@@ -2,7 +2,7 @@
 <!-- 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. -->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
         <bitmap
             android:src="@drawable/toolbar_shadow_focused"
@@ -13,4 +13,4 @@
             android:src="@drawable/bottom_toolbar_top_line"
             android:gravity="top|fill_horizontal" />
     </item>
-</layer-list>
+</transition>
diff --git a/chrome/android/java/res/layout/content_suggestions_card_modern.xml b/chrome/android/java/res/layout/content_suggestions_card_modern.xml
index 59347b72b..8a2cbf57 100644
--- a/chrome/android/java/res/layout/content_suggestions_card_modern.xml
+++ b/chrome/android/java/res/layout/content_suggestions_card_modern.xml
@@ -32,6 +32,7 @@
         android:layout_marginStart="@dimen/content_suggestions_card_modern_offline_badge_overlay_margin_start"
         android:layout_marginTop="@dimen/content_suggestions_card_modern_offline_badge_overlay_margin_top"
         android:contentDescription="@null"
+        android:visibility="gone"
         app:srcCompat="@drawable/ic_offline_pin_white"
         tools:src="@drawable/ic_offline_pin_white"/>
 
diff --git a/chrome/android/java/res/layout/contextual_suggestions_card.xml b/chrome/android/java/res/layout/contextual_suggestions_card.xml
index 08f6906e..2e77c316 100644
--- a/chrome/android/java/res/layout/contextual_suggestions_card.xml
+++ b/chrome/android/java/res/layout/contextual_suggestions_card.xml
@@ -10,7 +10,6 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginStart="@dimen/contextual_carousel_space_between_cards"
     android:background="@drawable/card_single"
     android:foreground="@drawable/button_borderless_compat">
 
diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
index 15ffa32..e313e5e 100644
--- a/chrome/android/java/res/xml/main_preferences.xml
+++ b/chrome/android/java/res/xml/main_preferences.xml
@@ -3,54 +3,72 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orderingFromXml="false">
 
     <org.chromium.chrome.browser.preferences.SignInPreference
         android:key="sign_in"
-        android:title="@string/sign_in_to_chrome" />
+        android:order="0"
+        android:title="@string/sign_in_to_chrome"/>
 
     <PreferenceCategory
+        android:key="basics_section"
+        android:order="1"
         android:title="@string/prefs_section_basics"/>
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.preferences.SearchEnginePreference"
         android:key="search_engine"
+        android:order="2"
         android:title="@string/prefs_search_engine"/>
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.preferences.autofill.AutofillAndPaymentsPreferences"
         android:key="autofill_settings"
-        android:title="@string/prefs_autofill_and_payments" />
+        android:order="3"
+        android:title="@string/prefs_autofill_and_payments"/>
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
-        android:key="saved_passwords"/>
+        android:fragment="org.chromium.chrome.browser.preferences.password.SavePasswordsPreferences"
+        android:key="saved_passwords"
+        android:order="4"
+        android:title="@string/prefs_saved_passwords"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.NotificationsPreferences"
         android:key="notifications"
-        android:title="@string/prefs_notifications" />
+        android:order="5"
+        android:title="@string/prefs_notifications"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.HomepagePreferences"
         android:key="homepage"
-        android:title="@string/options_homepage_title" />
+        android:order="6"
+        android:title="@string/options_homepage_title"/>
 
     <PreferenceCategory
+        android:key="advanced_section"
+        android:order="7"
         android:title="@string/prefs_section_advanced"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.privacy.PrivacyPreferences"
         android:key="privacy"
-        android:title="@string/prefs_privacy" />
+        android:order="8"
+        android:title="@string/prefs_privacy"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.AccessibilityPreferences"
         android:key="accessibility"
-        android:title="@string/prefs_accessibility" />
+        android:order="9"
+        android:title="@string/prefs_accessibility"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.website.SiteSettingsPreferences"
         android:key="content_settings"
-        android:title="@string/prefs_site_settings" />
+        android:order="10"
+        android:title="@string/prefs_site_settings"/>
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
         android:fragment="org.chromium.chrome.browser.preferences.datareduction.DataReductionPreferences"
         android:key="data_reduction"
-        android:title="@string/data_reduction_title" />
+        android:order="11"
+        android:title="@string/data_reduction_title"/>
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.AboutChromePreferences"
         android:key="about_chrome"
-        android:title="@string/prefs_about_chrome" />
+        android:order="12"
+        android:title="@string/prefs_about_chrome"/>
 
 </PreferenceScreen>
diff --git a/chrome/android/java/res/xml/notifications_preferences.xml b/chrome/android/java/res/xml/notifications_preferences.xml
index 2f7c103..56a6565d 100644
--- a/chrome/android/java/res/xml/notifications_preferences.xml
+++ b/chrome/android/java/res/xml/notifications_preferences.xml
@@ -3,14 +3,12 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:chrome="http://schemas.android.com/apk/res-auto" >
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 
     <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
         android:key="content_suggestions"
         android:title="@string/notifications_content_suggestions_title"
-        android:summary="@string/notifications_content_suggestions_summary"
-        chrome:drawDivider="true" />
+        android:summary="@string/notifications_content_suggestions_summary" />
 
     <Preference
         android:fragment="org.chromium.chrome.browser.preferences.website.SingleCategoryPreferences"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/FullscreenActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/FullscreenActivity.java
index dde299f..6ee1602 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/FullscreenActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/FullscreenActivity.java
@@ -10,6 +10,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Log;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
@@ -163,4 +165,16 @@
 
         tab.detachAndStartReparenting(intent, null, setFullscreen);
     }
+
+    public static boolean shouldUseFullscreenActivity(Tab tab) {
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.FULLSCREEN_ACTIVITY)) return false;
+
+        ChromeActivity activity = tab.getActivity();
+        if (!activity.supportsFullscreenActivity()) return false;
+
+        // FullscreenActivity transitions involve Intent-ing to a new Activity. If the current
+        // Activity is not in the foreground we don't want to do this (as it would re-launch
+        // Chrome).
+        return ApplicationStatus.getStateForActivity(activity) == ActivityState.RESUMED;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index 0b04b733d..f47e263 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -255,13 +255,16 @@
         ViewGroup contentView =
                 (ViewGroup) LayoutInflater.from(context).inflate(R.layout.app_menu_layout, null);
         mListView = (ListView) contentView.findViewById(R.id.app_menu_list);
-        mListView.setAdapter(mAdapter);
 
         int footerHeight =
                 inflateFooter(footerResourceId, contentView, menuWidth, highlightedItemId);
         int headerHeight =
                 inflateHeader(headerResourceId, headerOnClickListener, context, menuWidth);
 
+        // Set the adapter after the header is added to avoid crashes on JellyBean.
+        // See crbug.com/761726.
+        mListView.setAdapter(mAdapter);
+
         int popupHeight = setMenuHeight(menuItems.size(), visibleDisplayFrame, screenHeight,
                 sizingPadding, footerHeight, headerHeight, anchorView);
         int[] popupPosition = getPopupPosition(mCurrentScreenRotation, visibleDisplayFrame,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java
index 09f9f73a..da5954b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java
@@ -27,9 +27,8 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mIconView.setImageDrawable(
+        setIconDrawable(
                 TintedDrawable.constructTintedDrawable(getResources(), R.drawable.bookmark_folder));
-        onIconDrawableChanged();
     }
 
     // BookmarkRow implementation.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java
index 50413a44..3d4f68b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemRow.java
@@ -89,14 +89,13 @@
         if (icon == null) {
             mIconGenerator.setBackgroundColor(fallbackColor);
             icon = mIconGenerator.generateIconForUrl(mUrl);
-            mIconView.setImageDrawable(new BitmapDrawable(getResources(), icon));
+            setIconDrawable(new BitmapDrawable(getResources(), icon));
         } else {
             RoundedBitmapDrawable roundedIcon = RoundedBitmapDrawableFactory.create(
                     getResources(),
                     Bitmap.createScaledBitmap(icon, mDisplayedIconSize, mDisplayedIconSize, false));
             roundedIcon.setCornerRadius(mCornerRadius);
-            mIconView.setImageDrawable(roundedIcon);
+            setIconDrawable(roundedIcon);
         }
-        onIconDrawableChanged();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
index 182cb068..7a7004f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
@@ -126,16 +126,14 @@
 
         boolean isDarkTheme = tab.isIncognito();
         // The theme might require lighter text.
-        if (!DeviceFormFactor.isTablet()) {
+        if (!DeviceFormFactor.isTablet() && !FeatureUtilities.isChromeHomeModernEnabled()) {
             isDarkTheme |= ColorUtils.shouldUseLightForegroundOnBackground(tab.getThemeColor());
         }
 
         ColorUtils.shouldUseLightForegroundOnBackground(tab.getThemeColor());
         boolean isRtl = tab.isTitleDirectionRtl();
         TitleBitmapFactory titleBitmapFactory =
-                isDarkTheme && !FeatureUtilities.isChromeHomeModernEnabled()
-                ? mDarkTitleBitmapFactory
-                : mStandardTitleBitmapFactory;
+                isDarkTheme ? mDarkTitleBitmapFactory : mStandardTitleBitmapFactory;
 
         Title title = mTitles.get(tabId);
         if (title == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
index 979894f3..24eb690 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
@@ -2275,7 +2275,8 @@
      */
     public float getMaxTabHeight() {
         if (FeatureUtilities.isChromeHomeEnabled() && mCurrentMode == Orientation.PORTRAIT) {
-            return mLayout.getHeight();
+            if (!FeatureUtilities.isChromeHomeModernEnabled()) return mLayout.getHeight();
+            return mLayout.getHeightMinusBrowserControls() - StackLayout.MODERN_TOP_MARGIN_DP;
         }
         return mLayout.getHeightMinusBrowserControls();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java
index 3dedaa3..d6e4637 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java
@@ -10,6 +10,7 @@
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PackageUtils;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeClassQualifiedName;
@@ -133,6 +134,7 @@
      */
     @CalledByNative
     private void onDestroy() {
+        ThreadUtils.assertOnUiThread();
         mNativeExternalDataUseObserverBridge = 0;
     }
 
@@ -143,6 +145,7 @@
      */
     @CalledByNative
     protected void fetchMatchingRules() {
+        ThreadUtils.assertOnUiThread();
         fetchMatchingRulesDone(null, null, null);
     }
 
@@ -158,6 +161,7 @@
      */
     protected void fetchMatchingRulesDone(
             String[] appPackageName, String[] domainPathRegEx, String[] label) {
+        ThreadUtils.assertOnUiThread();
         // Check if native object is destroyed. This may happen at the time of Chromium shutdown.
         if (mNativeExternalDataUseObserverBridge == 0) {
             return;
@@ -196,6 +200,7 @@
      * @param success true if the data report was successfully submitted to the external observer.
      */
     protected void onReportDataUseDone(boolean success) {
+        ThreadUtils.assertOnUiThread();
         // Check if native object is destroyed.  This may happen at the time of Chromium shutdown.
         if (mNativeExternalDataUseObserverBridge == 0) {
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/BrowsingHistoryBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/history/BrowsingHistoryBridge.java
index ddb01462..e18eca6e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/BrowsingHistoryBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/BrowsingHistoryBridge.java
@@ -34,8 +34,13 @@
     }
 
     @Override
-    public void queryHistory(String query, long endQueryTime) {
-        nativeQueryHistory(mNativeHistoryBridge, new ArrayList<HistoryItem>(), query, endQueryTime);
+    public void queryHistory(String query) {
+        nativeQueryHistory(mNativeHistoryBridge, new ArrayList<HistoryItem>(), query);
+    }
+
+    @Override
+    public void queryHistoryContinuation() {
+        nativeQueryHistoryContinuation(mNativeHistoryBridge, new ArrayList<HistoryItem>());
     }
 
     @Override
@@ -96,8 +101,10 @@
 
     private native long nativeInit(boolean isIncognito);
     private native void nativeDestroy(long nativeBrowsingHistoryBridge);
-    private native void nativeQueryHistory(long nativeBrowsingHistoryBridge,
-            List<HistoryItem> historyItems, String query, long queryEndTime);
+    private native void nativeQueryHistory(
+            long nativeBrowsingHistoryBridge, List<HistoryItem> historyItems, String query);
+    private native void nativeQueryHistoryContinuation(
+            long nativeBrowsingHistoryBridge, List<HistoryItem> historyItems);
     private native void nativeMarkItemForRemoval(
             long nativeBrowsingHistoryBridge, String url, long[] nativeTimestamps);
     private native void nativeRemoveItems(long nativeBrowsingHistoryBridge);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
index 8d2f83b..09aeda55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
@@ -73,7 +73,6 @@
     private boolean mClearOnNextQueryComplete;
     private boolean mPrivacyDisclaimersVisible;
     private boolean mClearBrowsingDataButtonVisible;
-    private long mNextQueryEndTime;
     private String mQueryText = EMPTY_QUERY;
 
     public HistoryAdapter(SelectionDelegate<HistoryItem> delegate, HistoryManager manager,
@@ -115,9 +114,8 @@
     public void initialize() {
         mIsInitialized = false;
         mIsLoadingItems = true;
-        mNextQueryEndTime = 0;
         mClearOnNextQueryComplete = true;
-        mHistoryProvider.queryHistory(mQueryText, mNextQueryEndTime);
+        mHistoryProvider.queryHistory(mQueryText);
     }
 
     @Override
@@ -143,7 +141,7 @@
         mIsLoadingItems = true;
         addFooter();
         notifyDataSetChanged();
-        mHistoryProvider.queryHistory(mQueryText, mNextQueryEndTime);
+        mHistoryProvider.queryHistoryContinuation();
     }
 
     /**
@@ -159,10 +157,9 @@
      */
     public void search(String query) {
         mQueryText = query;
-        mNextQueryEndTime = 0;
         mIsSearching = true;
         mClearOnNextQueryComplete = true;
-        mHistoryProvider.queryHistory(mQueryText, mNextQueryEndTime);
+        mHistoryProvider.queryHistory(mQueryText);
     }
 
     /**
@@ -267,9 +264,6 @@
 
         mIsLoadingItems = false;
         mHasMorePotentialItems = hasMorePotentialMatches;
-        if (items.size() > 0) {
-            mNextQueryEndTime = items.get(items.size() - 1).getTimestamp();
-        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
index 2620833..7d47532 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
@@ -93,17 +93,17 @@
                         getContext().getResources(), R.drawable.ic_block_red,
                         getContext().getTheme());
             }
-            mIconView.setImageDrawable(mBlockedVisitDrawable);
+            setIconDrawable(mBlockedVisitDrawable);
             mTitleView.setTextColor(
                     ApiCompatibilityUtils.getColor(getResources(), R.color.google_red_700));
         } else {
-            mIconView.setImageResource(R.drawable.default_favicon);
+            setIconDrawable(
+                    ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.default_favicon));
             if (mHistoryManager != null) requestIcon();
 
             mTitleView.setTextColor(
                     ApiCompatibilityUtils.getColor(getResources(), R.color.default_text_color));
         }
-        onIconDrawableChanged();
     }
 
     /**
@@ -159,15 +159,14 @@
         if (icon == null) {
             mIconGenerator.setBackgroundColor(fallbackColor);
             icon = mIconGenerator.generateIconForUrl(getItem().getUrl());
-            mIconView.setImageDrawable(new BitmapDrawable(getResources(), icon));
+            setIconDrawable(new BitmapDrawable(getResources(), icon));
         } else {
             RoundedBitmapDrawable roundedIcon = RoundedBitmapDrawableFactory.create(
                     getResources(),
                     Bitmap.createScaledBitmap(icon, mDisplayedIconSize, mDisplayedIconSize, false));
             roundedIcon.setCornerRadius(mCornerRadius);
-            mIconView.setImageDrawable(roundedIcon);
+            setIconDrawable(roundedIcon);
         }
-        onIconDrawableChanged();
     }
 
     private void requestIcon() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryProvider.java
index b90a9d6e..0678197 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryProvider.java
@@ -19,7 +19,7 @@
          * @param items The items that matched the #queryHistory() parameters.
          * @param hasMorePotentialMatches Whether there are more items that match the query text.
          *                                This will be false once the entire local history database
-         *                                has been searched.
+         *                                and remote web history has been searched.
          */
         void onQueryHistoryComplete(List<HistoryItem> items,
                 boolean hasMorePotentialMatches);
@@ -50,10 +50,14 @@
      * Query browsing history. Only one query may be in-flight at any time. See
      * BrowsingHistoryService::QueryHistory.
      * @param query The query search text. May be empty.
-     * @param endQueryTime The end of the time range to search. A value of 0 indicates that there
-     *                     is no limit on the end time. See the native QueryOptions.
      */
-    void queryHistory(String query, long endQueryTime);
+    void queryHistory(String query);
+
+    /*
+     * Fetches more results using the previous query's text, only valid to call
+     * after queryHistory is called.
+     */
+    void queryHistoryContinuation();
 
     /**
      * Adds the HistoryItem to the list of items being removed. The removal will not be committed
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 64d8ac38..8b4cdef 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
@@ -13,8 +13,12 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.preferences.website.SiteSettingsCategory;
+import org.chromium.chrome.browser.preferences.website.Website;
+import org.chromium.chrome.browser.preferences.website.WebsitePermissionsFetcher;
 import org.chromium.webapk.lib.common.WebApkConstants;
 
+import java.util.Collection;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -198,6 +202,13 @@
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
+    public static void logUnimportantStorageSizeInUMA() {
+        WebsitePermissionsFetcher fetcher =
+                new WebsitePermissionsFetcher(new UnimportantStorageSizeCalculator());
+        fetcher.fetchPreferencesForCategory(
+                SiteSettingsCategory.fromString(SiteSettingsCategory.CATEGORY_USE_STORAGE));
+    }
+
     /**
      * Mirror the system-derived calculation of reserved bytes and return that value.
      */
@@ -232,4 +243,27 @@
 
         return Math.min(minFreeBytes, minFreePercentInBytes);
     }
+
+    private static class UnimportantStorageSizeCalculator
+            implements WebsitePermissionsFetcher.WebsitePermissionsCallback {
+        @Override
+        public void onWebsitePermissionsAvailable(Collection<Website> sites) {
+            long siteStorageSize = 0;
+            long importantSiteStorageTotal = 0;
+            for (Website site : sites) {
+                siteStorageSize += site.getTotalUsage();
+                if (site.getLocalStorageInfo() != null
+                        && site.getLocalStorageInfo().isDomainImportant()) {
+                    importantSiteStorageTotal += site.getTotalUsage();
+                }
+            }
+            long unimportantSiteStorageTotal = siteStorageSize - importantSiteStorageTotal;
+            int unimportantSiteStorageTotalMb =
+                    (int) (unimportantSiteStorageTotal / 1024L / 1024L / 10L * 10L);
+            unimportantSiteStorageTotalMb = Math.min(unimportantSiteStorageTotalMb, 1000);
+
+            RecordHistogram.recordSparseSlowlyHistogram(
+                    "WebApk.Install.ChromeUnimportantStorage.Fail", unimportantSiteStorageTotalMb);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
index be58948..217d04bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
@@ -87,13 +87,11 @@
      * @param profile The profile used to get bridge.
      * @param useEvaluationScheduler True if using the evaluation scheduler instead of the
      *                               GCMNetworkManager one.
-     * @param useBackgroundLoader True if using background loader. False for prerenderer.
      */
-    public OfflinePageEvaluationBridge(
-            Profile profile, boolean useEvaluationScheduler, boolean useBackgroundLoader) {
+    public OfflinePageEvaluationBridge(Profile profile, boolean useEvaluationScheduler) {
         ThreadUtils.assertOnUiThread();
         mNativeOfflinePageEvaluationBridge =
-                nativeCreateBridgeForProfile(profile, useEvaluationScheduler, useBackgroundLoader);
+                nativeCreateBridgeForProfile(profile, useEvaluationScheduler);
     }
 
     private static final String TAG = "OPEvalBridge";
@@ -269,7 +267,7 @@
     }
 
     private native long nativeCreateBridgeForProfile(
-            Profile profile, boolean useEvaluationScheduler, boolean useBackgroundLoader);
+            Profile profile, boolean useEvaluationScheduler);
     private native void nativeDestroy(long nativeOfflinePageEvaluationBridge);
 
     private native void nativeGetAllPages(long nativeOfflinePageEvaluationBridge,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index 51106db..1c41349 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -5,34 +5,32 @@
 package org.chromium.chrome.browser.preferences;
 
 import android.content.Intent;
-import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 
 import org.chromium.base.BuildInfo;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.PasswordUIView;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
 import org.chromium.chrome.browser.preferences.datareduction.DataReductionPreferences;
-import org.chromium.chrome.browser.preferences.password.SavePasswordsPreferences;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
-import org.chromium.chrome.browser.search_engines.TemplateUrlService.LoadListener;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl;
 import org.chromium.chrome.browser.signin.SigninManager;
-import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
+
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * The main settings screen, shown when the user first opens Settings.
  */
 public class MainPreferences extends PreferenceFragment
-        implements SignInStateObserver, Preference.OnPreferenceClickListener, LoadListener {
+        implements SigninManager.SignInStateObserver, TemplateUrlService.LoadListener {
     public static final String PREF_SIGN_IN = "sign_in";
-    public static final String PREF_DOCUMENT_MODE = "document_mode";
     public static final String PREF_AUTOFILL_SETTINGS = "autofill_settings";
     public static final String PREF_SEARCH_ENGINE = "search_engine";
     public static final String PREF_SAVED_PASSWORDS = "saved_passwords";
@@ -40,11 +38,8 @@
     public static final String PREF_DATA_REDUCTION = "data_reduction";
     public static final String PREF_NOTIFICATIONS = "notifications";
 
-    public static final String ACCOUNT_PICKER_DIALOG_TAG = "account_picker_dialog_tag";
-    public static final String EXTRA_SHOW_SEARCH_ENGINE_PICKER = "show_search_engine_picker";
-
-    private SignInPreference mSignInPreference;
-    private ManagedPreferenceDelegate mManagedPreferenceDelegate;
+    private final ManagedPreferenceDelegate mManagedPreferenceDelegate;
+    private final Map<String, Preference> mAllPreferences = new HashMap<>();
 
     public MainPreferences() {
         setHasOptionsMenu(true);
@@ -54,18 +49,16 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        createPreferences();
     }
 
     @Override
     public void onResume() {
         super.onResume();
-        // updatePreferences() must be called before setupSignInPref as updatePreferences loads
-        // the SignInPreference.
         updatePreferences();
-
         if (SigninManager.get(getActivity()).isSigninSupported()) {
             SigninManager.get(getActivity()).addSignInStateObserver(this);
-            setupSignInPref();
+            ((SignInPreference) mAllPreferences.get(PREF_SIGN_IN)).registerForUpdates();
         }
     }
 
@@ -74,82 +67,32 @@
         super.onPause();
         if (SigninManager.get(getActivity()).isSigninSupported()) {
             SigninManager.get(getActivity()).removeSignInStateObserver(this);
-            clearSignInPref();
+            ((SignInPreference) mAllPreferences.get(PREF_SIGN_IN)).unregisterForUpdates();
         }
     }
 
-    @Override
-    public boolean onPreferenceClick(Preference preference) {
-        Intent intent = new Intent(
-                  Intent.ACTION_VIEW,
-                  Uri.parse(PasswordUIView.getAccountDashboardURL()));
-        intent.setPackage(getActivity().getPackageName());
-        getActivity().startActivity(intent);
-        return true;
-    }
-
-    private void updatePreferences() {
-        if (getPreferenceScreen() != null) getPreferenceScreen().removeAll();
-
+    private void createPreferences() {
         PreferenceUtils.addPreferencesFromResource(this, R.xml.main_preferences);
 
-        if (TemplateUrlService.getInstance().isLoaded()) {
-            updateSummary();
-        } else {
-            TemplateUrlService.getInstance().registerLoadListener(this);
-            TemplateUrlService.getInstance().load();
-            ChromeBasePreference searchEnginePref =
-                    (ChromeBasePreference) findPreference(PREF_SEARCH_ENGINE);
-            searchEnginePref.setEnabled(false);
-        }
-
-        ChromeBasePreference autofillPref =
-                (ChromeBasePreference) findPreference(PREF_AUTOFILL_SETTINGS);
-        autofillPref.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-
-        ChromeBasePreference passwordsPref =
-                (ChromeBasePreference) findPreference(PREF_SAVED_PASSWORDS);
-
-        passwordsPref.setTitle(getResources().getString(R.string.prefs_saved_passwords));
-        passwordsPref.setFragment(SavePasswordsPreferences.class.getCanonicalName());
-        setOnOffSummary(
-                passwordsPref, PrefServiceBridge.getInstance().isRememberPasswordsEnabled());
-        passwordsPref.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-
-        Preference homepagePref = findPreference(PREF_HOMEPAGE);
-        if (HomepageManager.shouldShowHomepageSetting()) {
-            setOnOffSummary(homepagePref,
-                    HomepageManager.getInstance(getActivity()).getPrefHomepageEnabled());
-        } else {
-            getPreferenceScreen().removePreference(homepagePref);
-        }
-
-        ChromeBasePreference dataReduction =
-                (ChromeBasePreference) findPreference(PREF_DATA_REDUCTION);
-        dataReduction.setSummary(DataReductionPreferences.generateSummary(getResources()));
-        dataReduction.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-
-        if (!SigninManager.get(getActivity()).isSigninSupported()) {
-            getPreferenceScreen().removePreference(findPreference(PREF_SIGN_IN));
-        }
+        cachePreferences();
+        setManagedPreferenceDelegateForPreference(PREF_SEARCH_ENGINE);
+        setManagedPreferenceDelegateForPreference(PREF_AUTOFILL_SETTINGS);
+        setManagedPreferenceDelegateForPreference(PREF_SAVED_PASSWORDS);
+        setManagedPreferenceDelegateForPreference(PREF_DATA_REDUCTION);
 
         if (BuildInfo.isAtLeastO()) {
             // If we are on Android O+ the Notifications preference should lead to the Android
             // Settings notifications page, not to Chrome's notifications settings page.
             Preference notifications = findPreference(PREF_NOTIFICATIONS);
-            notifications.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
-                @Override
-                public boolean onPreferenceClick(Preference preference) {
-                    // TODO(crbug.com/707804): Use Android O constants.
-                    Intent intent = new Intent();
-                    intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
-                    intent.putExtra(
-                            "android.provider.extra.APP_PACKAGE", BuildInfo.getPackageName());
-                    startActivity(intent);
-                    // We handle the click so the default action (opening NotificationsPreference)
-                    // isn't triggered.
-                    return true;
-                }
+            notifications.setOnPreferenceClickListener(preference -> {
+                // TODO(crbug.com/707804): Use Android O constants.
+                Intent intent = new Intent();
+                intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
+                intent.putExtra("android.provider.extra.APP_PACKAGE", BuildInfo.getPackageName());
+                startActivity(intent);
+                // We handle the click so the default action (opening NotificationsPreference)
+                // isn't triggered.
+                return true;
             });
         } else if (!ChromeFeatureList.isEnabled(
                            ChromeFeatureList.CONTENT_SUGGESTIONS_NOTIFICATIONS)) {
@@ -163,55 +106,96 @@
             // enabled (which is what the user can toggle on the Notifications Preferences page).
             getPreferenceScreen().removePreference(findPreference(PREF_NOTIFICATIONS));
         }
+
+        if (!TemplateUrlService.getInstance().isLoaded()) {
+            TemplateUrlService.getInstance().registerLoadListener(this);
+            TemplateUrlService.getInstance().load();
+        }
     }
 
-    @Override
-    public void onTemplateUrlServiceLoaded() {
-        TemplateUrlService.getInstance().unregisterLoadListener(this);
-        updateSummary();
+    /**
+     * Stores all preferences in memory so that, if they needed to be added/removed from the
+     * PreferenceScreen, there would be no need to reload them from 'main_preferences.xml'.
+     */
+    private void cachePreferences() {
+        int preferenceCount = getPreferenceScreen().getPreferenceCount();
+        for (int index = 0; index < preferenceCount; index++) {
+            Preference preference = getPreferenceScreen().getPreference(index);
+            mAllPreferences.put(preference.getKey(), preference);
+        }
     }
 
-    private void updateSummary() {
-        ChromeBasePreference searchEnginePref =
-                (ChromeBasePreference) findPreference(PREF_SEARCH_ENGINE);
-        searchEnginePref.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
-        searchEnginePref.setEnabled(true);
+    private void setManagedPreferenceDelegateForPreference(String key) {
+        ChromeBasePreference chromeBasePreference = (ChromeBasePreference) mAllPreferences.get(key);
+        chromeBasePreference.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
+    }
+
+    private void updatePreferences() {
+        if (SigninManager.get(getActivity()).isSigninSupported()) {
+            addPreferenceIfAbsent(PREF_SIGN_IN);
+        } else {
+            removePreferenceIfPresent(PREF_SIGN_IN);
+        }
+
+        updateSearchEnginePreference();
+
+        ChromeBasePreference passwordsPref =
+                (ChromeBasePreference) findPreference(PREF_SAVED_PASSWORDS);
+        setOnOffSummary(
+                passwordsPref, PrefServiceBridge.getInstance().isRememberPasswordsEnabled());
+
+        if (HomepageManager.shouldShowHomepageSetting()) {
+            Preference homepagePref = addPreferenceIfAbsent(PREF_HOMEPAGE);
+            setOnOffSummary(homepagePref,
+                    HomepageManager.getInstance(getActivity()).getPrefHomepageEnabled());
+        } else {
+            removePreferenceIfPresent(PREF_HOMEPAGE);
+        }
+
+        ChromeBasePreference dataReduction =
+                (ChromeBasePreference) findPreference(PREF_DATA_REDUCTION);
+        dataReduction.setSummary(DataReductionPreferences.generateSummary(getResources()));
+    }
+
+    private Preference addPreferenceIfAbsent(String key) {
+        Preference preference = getPreferenceScreen().findPreference(key);
+        if (preference == null) getPreferenceScreen().addPreference(mAllPreferences.get(key));
+        return mAllPreferences.get(key);
+    }
+
+    private void removePreferenceIfPresent(String key) {
+        Preference preference = getPreferenceScreen().findPreference(key);
+        if (preference != null) getPreferenceScreen().removePreference(preference);
+    }
+
+    private void updateSearchEnginePreference() {
+        if (!TemplateUrlService.getInstance().isLoaded()) {
+            ChromeBasePreference searchEnginePref =
+                    (ChromeBasePreference) findPreference(PREF_SEARCH_ENGINE);
+            searchEnginePref.setEnabled(false);
+            return;
+        }
 
         String defaultSearchEngineName = null;
         TemplateUrl dseTemplateUrl =
                 TemplateUrlService.getInstance().getDefaultSearchEngineTemplateUrl();
         if (dseTemplateUrl != null) defaultSearchEngineName = dseTemplateUrl.getShortName();
-        searchEnginePref.setSummary(defaultSearchEngineName);
+
+        Preference searchEnginePreference = findPreference(PREF_SEARCH_ENGINE);
+        searchEnginePreference.setEnabled(true);
+        searchEnginePreference.setSummary(defaultSearchEngineName);
     }
 
     private void setOnOffSummary(Preference pref, boolean isOn) {
         pref.setSummary(getResources().getString(isOn ? R.string.text_on : R.string.text_off));
     }
 
-    private void setupSignInPref() {
-        mSignInPreference = (SignInPreference) findPreference(PREF_SIGN_IN);
-        mSignInPreference.registerForUpdates();
-    }
-
-    private void clearSignInPref() {
-        if (mSignInPreference != null) {
-            mSignInPreference.unregisterForUpdates();
-            mSignInPreference = null;
-        }
-    }
-
-    // SignInStateObserver
-
+    // SigninManager.SignInStateObserver implementation.
     @Override
     public void onSignedIn() {
         // After signing in or out of a managed account, preferences may change or become enabled
         // or disabled.
-        new Handler().post(new Runnable() {
-            @Override
-            public void run() {
-                updatePreferences();
-            }
-        });
+        new Handler().post(() -> updatePreferences());
     }
 
     @Override
@@ -219,6 +203,14 @@
         updatePreferences();
     }
 
+    // TemplateUrlService.LoadListener implementation.
+    @Override
+    public void onTemplateUrlServiceLoaded() {
+        TemplateUrlService.getInstance().unregisterLoadListener(this);
+        updateSearchEnginePreference();
+    }
+
+    @VisibleForTesting
     ManagedPreferenceDelegate getManagedPreferenceDelegateForTest() {
         return mManagedPreferenceDelegate;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java
index b50945d..188a155 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java
@@ -39,7 +39,7 @@
 
         mSnippetsBridge = new SnippetsBridge(Profile.getLastUsedProfile());
 
-        addPreferencesFromResource(R.xml.notifications_preferences);
+        PreferenceUtils.addPreferencesFromResource(this, R.xml.notifications_preferences);
         getActivity().setTitle(R.string.prefs_notifications);
 
         mSuggestionsPref = (ChromeSwitchPreference) findPreference(PREF_SUGGESTIONS);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
index ee3a626..ffa88e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
@@ -105,6 +105,8 @@
             PREF_ADS_PERMISSION,
     };
 
+    private static final int REQUEST_CODE_NOTIFICATION_CHANNEL_SETTINGS = 1;
+
     // The website this page is displaying details about.
     private Website mSite;
 
@@ -356,7 +358,7 @@
         }
     }
 
-    private void setUpNotificationsPreference(Preference listPreference) {
+    private void setUpNotificationsPreference(Preference preference) {
         if (BuildInfo.isAtLeastO()
                 && ChromeFeatureList.isEnabled(ChromeFeatureList.SITE_NOTIFICATION_CHANNELS)) {
             final ContentSetting value = mSite.getNotificationPermission();
@@ -364,23 +366,23 @@
                 // TODO(crbug.com/735110): Figure out if this is the correct thing to do, for values
                 // that are non-null, but not ALLOW or BLOCK either. (In setupListPreference we
                 // treat non-ALLOW settings as BLOCK, but here we are simply removing them.)
-                getPreferenceScreen().removePreference(listPreference);
+                getPreferenceScreen().removePreference(preference);
                 return;
             }
-            // On Android O this preference is read-only, so we replace the ListPreference with a
+            // On Android O this preference is read-only, so we replace the existing pref with a
             // regular Preference that takes users to OS settings on click.
-            Preference preference = new Preference(listPreference.getContext());
-            preference.setKey(listPreference.getKey());
-            setUpPreferenceCommon(preference);
+            Preference newPreference = new Preference(preference.getContext());
+            newPreference.setKey(preference.getKey());
+            setUpPreferenceCommon(newPreference);
 
-            preference.setSummary(
+            newPreference.setSummary(
                     getResources().getString(ContentSettingsResources.getSiteSummary(value)));
-            preference.setDefaultValue(value);
+            newPreference.setDefaultValue(value);
 
             // This preference is read-only so should not attempt to persist to shared prefs.
-            preference.setPersistent(false);
+            newPreference.setPersistent(false);
 
-            preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+            newPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                 @Override
                 public boolean onPreferenceClick(Preference preference) {
                     // There is no guarantee that a channel has been initialized yet for sites
@@ -395,19 +397,43 @@
                     return true;
                 }
             });
-            preference.setOrder(listPreference.getOrder());
-            getPreferenceScreen().removePreference(listPreference);
-            getPreferenceScreen().addPreference(preference);
+            newPreference.setOrder(preference.getOrder());
+            getPreferenceScreen().removePreference(preference);
+            getPreferenceScreen().addPreference(newPreference);
         } else {
-            setUpListPreference(listPreference, mSite.getNotificationPermission());
+            setUpListPreference(preference, mSite.getNotificationPermission());
         }
     }
 
-    private static void launchOsChannelSettings(Context context, String channelId) {
+    private void launchOsChannelSettings(Context context, String channelId) {
         Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
         intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId);
         intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
-        context.startActivity(intent);
+        startActivityForResult(intent, REQUEST_CODE_NOTIFICATION_CHANNEL_SETTINGS);
+    }
+
+    /**
+     * If we are returning to Site Settings from another activity, the preferences displayed may be
+     * out of date. Here we refresh any we suspect may have changed.
+     */
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        // The preference screen and mSite may be null if this activity was killed in the
+        // background, and the tasks scheduled from onActivityCreated haven't completed yet. Those
+        // tasks will take care of reinitializing everything afresh so there is no work to do here.
+        if (getPreferenceScreen() == null || mSite == null) {
+            return;
+        }
+        if (requestCode == REQUEST_CODE_NOTIFICATION_CHANNEL_SETTINGS) {
+            // User has navigated back from system channel settings on O+. Ensure notification
+            // preference is up to date, since they might have toggled it from channel settings.
+            Preference notificationsPreference =
+                    getPreferenceScreen().findPreference(PREF_NOTIFICATIONS_PERMISSION);
+            if (notificationsPreference != null) {
+                setUpNotificationsPreference(notificationsPreference);
+            }
+        }
     }
 
     private void setUpUsbPreferences(int maxPermissionOrder) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java
index 06fc08e..d7884af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninAndSyncView.java
@@ -15,6 +15,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.signin.AccountSigninActivity.AccessPoint;
@@ -30,8 +31,8 @@
  * A View that shows the user the next step they must complete to start syncing their data (eg.
  * Recent Tabs or Bookmarks). For example, if the user is not signed in, the View will prompt them
  * to do so and link to the AccountSigninActivity.
- * If inflated manually, {@link SigninAndSyncView#init()} must be called before attaching this View
- * to a ViewGroup.
+ * If inflated manually, {@link SigninAndSyncView#init(Listener, int)} must be called before
+ * attaching this View to a ViewGroup.
  */
 public class SigninAndSyncView extends LinearLayout
         implements AndroidSyncSettingsObserver, SignInStateObserver {
@@ -300,6 +301,7 @@
     // AndroidSyncStateObserver
     @Override
     public void androidSyncSettingsChanged() {
-        update();
+        // AndroidSyncSettings calls this method from non-UI threads.
+        ThreadUtils.runOnUiThread(() -> update());
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
index 8923155..97e1ebc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
@@ -9,9 +9,11 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.displaystyle.DisplayStyleObserver;
 import org.chromium.chrome.browser.widget.displaystyle.DisplayStyleObserverAdapter;
 import org.chromium.chrome.browser.widget.displaystyle.HorizontalDisplayStyle;
@@ -33,13 +35,17 @@
 
     public ContextualSuggestionsCardViewHolder(
             ViewGroup recyclerView, UiConfig uiConfig, SuggestionsUiDelegate uiDelegate) {
-        super(LayoutInflater.from(recyclerView.getContext())
-                        .inflate(R.layout.contextual_suggestions_card, recyclerView, false));
+        super(getCardView(recyclerView));
 
         mUiConfig = uiConfig;
         mUiDelegate = uiDelegate;
         mSuggestionsBinder = new SuggestionsBinder(itemView, uiDelegate);
 
+        int startMargin = itemView.getResources().getDimensionPixelOffset(
+                R.dimen.contextual_carousel_space_between_cards);
+        ApiCompatibilityUtils.setMarginStart(
+                (ViewGroup.MarginLayoutParams) itemView.getLayoutParams(), startMargin);
+
         itemView.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -62,6 +68,14 @@
                 /* showThumbnailVideoOverlay = */ false, /* headerMaxLines = */ 3);
     }
 
+    private static View getCardView(ViewGroup recyclerView) {
+        int res = FeatureUtilities.isChromeHomeModernEnabled()
+                ? R.layout.content_suggestions_card_modern
+                : R.layout.contextual_suggestions_card;
+
+        return LayoutInflater.from(recyclerView.getContext()).inflate(res, recyclerView, false);
+    }
+
     public void onBindViewHolder(SnippetArticle suggestion) {
         mSuggestion = suggestion;
         mDisplayStyleObserver.attach();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
index f59019e..432838e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -27,7 +27,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.FullscreenActivity;
 import org.chromium.chrome.browser.RepostFormWarningDialog;
 import org.chromium.chrome.browser.document.DocumentUtils;
@@ -219,8 +218,7 @@
 
     @Override
     public void toggleFullscreenModeForTab(boolean enableFullscreen) {
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.FULLSCREEN_ACTIVITY)
-                && mTab.getActivity().supportsFullscreenActivity()) {
+        if (FullscreenActivity.shouldUseFullscreenActivity(mTab)) {
             FullscreenActivity.toggleFullscreenMode(enableFullscreen, mTab);
         } else {
             mTab.toggleFullscreenMode(enableFullscreen);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java
deleted file mode 100644
index a2565b85..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.vr_shell;
-
-/**
- * Abstracts away the NonPresentingGvrContext class, which may or may not be present at runtime
- * depending on compile flags.
- */
-public interface NonPresentingGvrContext {
-    /**
-     * Returns the native gvr context.
-     */
-    long getNativeGvrContext();
-
-    /**
-     * Shutdown the native gvr context.
-     */
-    void shutdown();
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextImpl.java
deleted file mode 100644
index c6010c1..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextImpl.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.vr_shell;
-
-import android.app.Activity;
-import android.os.StrictMode;
-
-import com.google.vr.ndk.base.GvrLayout;
-
-/**
- * Creates an active GvrContext from a detached GvrLayout. This is used by magic window mode.
- */
-public class NonPresentingGvrContextImpl implements NonPresentingGvrContext {
-    private GvrLayout mGvrLayout;
-
-    public NonPresentingGvrContextImpl(Activity activity) {
-        // Creating the GvrLayout can sometimes create the Daydream config file.
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-        try {
-            mGvrLayout = new GvrLayout(activity);
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
-    }
-
-    @Override
-    public long getNativeGvrContext() {
-        return mGvrLayout.getGvrApi().getNativeGvrContext();
-    }
-
-    @Override
-    public void shutdown() {
-        mGvrLayout.shutdown();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapper.java
index 81003c90..04041ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapper.java
@@ -17,11 +17,6 @@
  */
 public interface VrClassesWrapper {
     /**
-     * Creates a NonPresentingGvrContextImpl instance.
-     */
-    public NonPresentingGvrContext createNonPresentingGvrContext(ChromeActivity activity);
-
-    /**
      * Creates a VrShellImpl instance.
      */
     public VrShell createVrShell(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapperImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapperImpl.java
index 2f67a65..02e2ac63 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapperImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapperImpl.java
@@ -27,19 +27,6 @@
     public VrClassesWrapperImpl() {}
 
     @Override
-    public NonPresentingGvrContext createNonPresentingGvrContext(ChromeActivity activity) {
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        try {
-            return new NonPresentingGvrContextImpl(activity);
-        } catch (Exception ex) {
-            Log.e(TAG, "Unable to instantiate NonPresentingGvrContextImpl", ex);
-            return null;
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
-    }
-
-    @Override
     public VrShell createVrShell(
             ChromeActivity activity, VrShellDelegate delegate, TabModelSelector tabModelSelector) {
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 10f9e25..98cb105 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -124,7 +124,6 @@
 
     private final VrClassesWrapper mVrClassesWrapper;
     private VrShell mVrShell;
-    private NonPresentingGvrContext mNonPresentingGvrContext;
     private VrDaydreamApi mVrDaydreamApi;
     private Boolean mIsDaydreamCurrentViewer;
     private VrCoreVersionChecker mVrCoreVersionChecker;
@@ -512,7 +511,6 @@
         mStopped = ApplicationStatus.getStateForActivity(activity) == ActivityState.STOPPED;
         updateVrSupportLevel(null);
         mNativeVrShellDelegate = nativeInit();
-        createNonPresentingNativeContext();
         mFeedbackFrequency = VrFeedbackStatus.getFeedbackFrequency();
         mEnterVrHandler = new Handler();
         mExpectPauseOrDonSucceeded = new Handler();
@@ -562,8 +560,6 @@
         if (mActivity == activity) return;
         mActivity = activity;
         mVrDaydreamApi = mVrClassesWrapper.createVrDaydreamApi(mActivity);
-        if (mNativeVrShellDelegate == 0 || mNonPresentingGvrContext == null) return;
-        resetNonPresentingNativeContext();
     }
 
     private void maybeUpdateVrSupportLevel() {
@@ -590,7 +586,6 @@
     private void updateVrSupportLevel(Integer vrCorePackageVersion) {
         if (mVrClassesWrapper == null) {
             mVrSupportLevel = VR_NOT_AVAILABLE;
-            shutdownNonPresentingNativeContext();
             return;
         }
         if (vrCorePackageVersion == null) vrCorePackageVersion = getVrCorePackageVersion();
@@ -606,7 +601,6 @@
                 mVrDaydreamApi, mVrCoreVersionChecker, mActivity.getActivityTab());
         if (supportLevel == mVrSupportLevel) return;
         mVrSupportLevel = supportLevel;
-        resetNonPresentingNativeContext();
     }
 
     /**
@@ -705,7 +699,6 @@
             return;
         }
         mExitedDueToUnsupportedMode = false;
-        shutdownNonPresentingNativeContext();
 
         // Lock orientation to landscape after enter VR.
         mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
@@ -989,10 +982,7 @@
             new Handler().post(new Runnable() {
                 @Override
                 public void run() {
-                    if (!mPaused) {
-                        registerDaydreamIntent(mVrDaydreamApi, mActivity);
-                        createNonPresentingNativeContext();
-                    }
+                    if (!mPaused) registerDaydreamIntent(mVrDaydreamApi, mActivity);
                 }
             });
         }
@@ -1141,31 +1131,6 @@
         return mIsDaydreamCurrentViewer;
     }
 
-    private void resetNonPresentingNativeContext() {
-        shutdownNonPresentingNativeContext();
-        createNonPresentingNativeContext();
-    }
-
-    private void createNonPresentingNativeContext() {
-        if (mNonPresentingGvrContext != null) return;
-        if (mVrClassesWrapper == null) return;
-        if (mVrSupportLevel == VR_NOT_AVAILABLE) return;
-        if (mNativeVrShellDelegate == 0) return;
-        mNonPresentingGvrContext = mVrClassesWrapper.createNonPresentingGvrContext(mActivity);
-        if (mNonPresentingGvrContext == null) return;
-        nativeUpdateNonPresentingContext(
-                mNativeVrShellDelegate, mNonPresentingGvrContext.getNativeGvrContext());
-    }
-
-    private void shutdownNonPresentingNativeContext() {
-        if (mNonPresentingGvrContext == null) return;
-        if (mNativeVrShellDelegate != 0) {
-            nativeUpdateNonPresentingContext(mNativeVrShellDelegate, 0);
-        }
-        mNonPresentingGvrContext.shutdown();
-        mNonPresentingGvrContext = null;
-    }
-
     @CalledByNative
     private void setListeningForWebVrActivate(boolean listening) {
         // Non-Daydream devices may not have the concept of display activate. So disable
@@ -1227,7 +1192,6 @@
         if (disableVrMode) mVrClassesWrapper.setVrModeEnabled(mActivity, false);
 
         promptForFeedbackIfNeeded(stayingInChrome);
-        if (stayingInChrome) createNonPresentingNativeContext();
 
         assert mOnExitVrRequestListener == null;
     }
@@ -1551,7 +1515,6 @@
         shutdownVr(false /* disableVrMode */, false /* stayingInChrome */);
         if (mNativeVrShellDelegate != 0) nativeDestroy(mNativeVrShellDelegate);
         mNativeVrShellDelegate = 0;
-        shutdownNonPresentingNativeContext();
         ApplicationStatus.unregisterActivityStateListener(this);
         sInstance = null;
     }
@@ -1562,7 +1525,6 @@
     private native void nativeDisplayActivate(long nativeVrShellDelegate);
     private native void nativeOnPause(long nativeVrShellDelegate);
     private native void nativeOnResume(long nativeVrShellDelegate);
-    private native void nativeUpdateNonPresentingContext(long nativeVrShellDelegate, long context);
     private native boolean nativeIsClearActivatePending(long nativeVrShellDelegate);
     private native void nativeDestroy(long nativeVrShellDelegate);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java
index c19430a2..f8a82c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java
@@ -16,10 +16,9 @@
      * @param version The version of WebAPK to install.
      * @param title The title of the WebAPK to display during installation.
      * @param token The token from WebAPK Minter Server.
-     * @param url The start URL of the WebAPK to install.
      * @param callback The callback to invoke when the install completes, times out or fails.
      */
-    void installAsync(String packageName, int version, String title, String token, String url,
+    void installAsync(String packageName, int version, String title, String token,
             Callback<Integer> callback);
 
     /**
@@ -28,9 +27,8 @@
      * @param version The version of WebAPK to update.
      * @param title The title of the WebAPK to display during update.
      * @param token The token from WebAPK Minter Server.
-     * @param url The start URL of the WebAPK to update.
      * @param callback The callback to invoke when the update completes, times out or fails.
      */
-    void updateAsync(String packageName, int version, String title, String token, String url,
+    void updateAsync(String packageName, int version, String title, String token,
             Callback<Integer> callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
index 28da8f2..f7559bdf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
@@ -50,14 +50,13 @@
      * @param version The version of WebAPK to install.
      * @param title The title of the WebAPK to display during installation.
      * @param token The token from WebAPK Server.
-     * @param url The start URL of the WebAPK to install.
      * @param source The source (either app banner or menu) that the install of a WebAPK was
      *               triggered.
      * @param icon The primary icon of the WebAPK to install.
      */
     @CalledByNative
     private void installWebApkAsync(final String packageName, int version, final String title,
-            String token, final String url, final int source, final Bitmap icon) {
+            String token, final int source, final Bitmap icon) {
         // Check whether the WebAPK package is already installed. The WebAPK may have been installed
         // by another Chrome version (e.g. Chrome Dev). We have to do this check because the Play
         // install API fails silently if the package is already installed.
@@ -91,7 +90,7 @@
                         });
             }
         };
-        mInstallDelegate.installAsync(packageName, version, title, token, url, callback);
+        mInstallDelegate.installAsync(packageName, version, title, token, callback);
     }
 
     private void notify(@WebApkInstallResult int result) {
@@ -106,11 +105,10 @@
      * @param version The version of WebAPK to install.
      * @param title The title of the WebAPK to display during installation.
      * @param token The token from WebAPK Server.
-     * @param url The start URL of the WebAPK to install.
      */
     @CalledByNative
     private void updateAsync(
-            String packageName, int version, String title, String token, String url) {
+            String packageName, int version, String title, String token) {
         if (mInstallDelegate == null) {
             notify(WebApkInstallResult.FAILURE);
             return;
@@ -122,7 +120,7 @@
                 WebApkInstaller.this.notify(result);
             }
         };
-        mInstallDelegate.updateAsync(packageName, version, title, token, url, callback);
+        mInstallDelegate.updateAsync(packageName, version, title, token, callback);
     }
 
     private boolean isWebApkInstalled(String packageName) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
index 51d30178..e7bafa73 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
@@ -278,8 +278,7 @@
                         WebApkVersion.CURRENT_SHELL_APK_VERSION);
             }
         };
-        nativeUpdateWebApk(info.webApkPackageName(), info.manifestStartUrl(), info.shortName(),
-                serializedProto, callback);
+        nativeUpdateWebApk(info.webApkPackageName(), info.shortName(), serializedProto, callback);
     }
 
     /**
@@ -418,6 +417,6 @@
             int displayMode, int orientation, long themeColor, long backgroundColor,
             String manifestUrl, String webApkPackage, int webApkVersion, boolean isManifestStale,
             Callback<byte[]> callback);
-    private static native void nativeUpdateWebApk(String webApkPackage, String startUrl,
-            String shortName, byte[] serializedProto, WebApkUpdateCallback callback);
+    private static native void nativeUpdateWebApk(String webApkPackage, String shortName,
+            byte[] serializedProto, WebApkUpdateCallback callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
index d7cee5e..f4ec2ec34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
@@ -38,12 +38,12 @@
     protected TintedImageView mIconView;
     protected TextView mTitleView;
     protected TextView mDescriptionView;
-    protected Drawable mIconDrawable;
     protected ColorStateList mIconColorList;
 
     private SelectionDelegate<E> mSelectionDelegate;
     private E mItem;
     private boolean mIsChecked;
+    private Drawable mIconDrawable;
 
     /**
      * Constructor for inflating from XML.
@@ -190,12 +190,12 @@
     }
 
     /**
-     * Update cached icon drawable when icon view's drawable is changed. Note that this method must
-     * be called after the drawable is changed to ensure that it can be set back from the check
-     * icon in selection mode.
+     * Set drawable for the icon view. Note that you may need to use this method instead of
+     * mIconView#setImageDrawable to ensure icon view is correctly set in selection mode.
      */
-    protected void onIconDrawableChanged() {
-        mIconDrawable = mIconView.getDrawable();
+    protected void setIconDrawable(Drawable iconDrawable) {
+        mIconDrawable = iconDrawable;
+        updateIconView();
     }
 
     /**
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 360cd62..14f013d 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3138,13 +3138,13 @@
         Pull up to see bookmarks and more
       </message>
       <message name="IDS_BOTTOM_SHEET_ACCESSIBILITY_HELP_BUBBLE_MESSAGE" desc="Text displayed in a help bubble above the bottom navigation sheet prompting users to pull the sheet up to see their bookmarks and other content when accessibility is enabled.">
-        Pull up on the address bar to see bookmarks, downloads, and history
+        Pull up on the address bar with two fingers to see bookmarks, downloads, and history
       </message>
       <message name="IDS_BOTTOM_SHEET_ACCESSIBILITY_TOOLBAR" desc="Accessibilty string read when the bottom toolbar, containing the adddress bar and some buttons, is focused. Informs users that they can pull up on the address bar to see their bookmarks and other content.">
-        Address bar. Pull up to see bookmarks, downloads, and history.
+        Address bar. Pull up with two fingers to see bookmarks, downloads, and history.
       </message>
       <message name="IDS_BOTTOM_SHEET_OPEN_ACCESSIBILITY_TOOLBAR" desc="Accessibilty string read when the bottom toolbar, containing the adddress bar and some buttons, is focused and the Chrome Home navigation panel is open. Informs users that they can pull down on the address bar to close the navigation panel.">
-        Address bar. Pull down to close navigation panel.
+        Address bar. Pull down with two fingers to close navigation panel.
       </message>
       <message name="IDS_BOTTOM_SHEET_EXPAND_BUTTON_HELP_BUBBLE_MESSAGE" desc="Text displayed in a help bubble above the toolbar expand button prompting users to tap the button to see their bookmarks and other content.">
         Tap to see bookmarks and more
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 8127dd0..a25f200b 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1184,7 +1184,6 @@
   "java/src/org/chromium/chrome/browser/util/ViewUtils.java",
   "java/src/org/chromium/chrome/browser/vr_shell/SeparateTaskCustomTabVrActivity.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrCancelAnimationActivity.java",
-  "java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapper.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionChecker.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrDaydreamApi.java",
@@ -1330,7 +1329,6 @@
 chrome_vr_java_sources = [
   "java/src/org/chromium/chrome/browser/vr_shell/AndroidUiGestureTarget.java",
   "java/src/org/chromium/chrome/browser/vr_shell/AndroidVSyncHelper.java",
-  "java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextImpl.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrClassesWrapperImpl.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrCoreInfo.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionCheckerImpl.java",
@@ -1510,6 +1508,7 @@
   "javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java",
   "javatests/src/org/chromium/chrome/browser/media/ui/AutoplayMutedNotificationTest.java",
   "javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java",
+  "javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java",
   "javatests/src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java",
   "javatests/src/org/chromium/chrome/browser/metrics/UkmIncognitoTest.java",
@@ -1672,6 +1671,7 @@
   "javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetUiCaptureTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/NavigationRecorderTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java",
+  "javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTestRule.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetUiCaptureTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java",
   "javatests/src/org/chromium/chrome/browser/suggestions/TileGridLayoutTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
index 42f08070..c66ea947 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FullscreenActivityTest.java
@@ -5,8 +5,10 @@
 package org.chromium.chrome.browser;
 
 import android.app.Activity;
+import android.app.Instrumentation;
 import android.content.Intent;
 import android.provider.Browser;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.UiThreadTestRule;
 
@@ -19,6 +21,7 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -201,4 +204,51 @@
 
         Assert.assertEquals(old, mActivity.getTabsView().getSystemUiVisibility());
     }
+
+    /**
+     * When a FullscreenActivity goes to the background it exits fullscreen if the video is paused.
+     * In this case we want to exit fullscreen normally, not through Intenting back to the CTA,
+     * since this will appear to relaunch Chrome.
+     */
+    @Test
+    @MediumTest
+    public void testNoIntentWhenInBackground() throws Throwable {
+        final Boolean[] isTabFullscreen = new Boolean[1];
+        Tab tab = mActivity.getActivityTab();
+        tab.addObserver(new EmptyTabObserver() {
+            @Override
+            public void onToggleFullscreenMode(Tab tab, boolean enable) {
+                isTabFullscreen[0] = enable;
+            }
+        });
+
+        enterFullscreen();
+        Assert.assertTrue(isTabFullscreen[0]);
+        DOMUtils.pauseMedia(tab.getWebContents(), VIDEO_ID);
+
+        // Add a monitor to track any intents launched to a ChromeTabbedActivity.
+        Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
+                ChromeTabbedActivity.class.getName(), null, true);
+        InstrumentationRegistry.getInstrumentation().addMonitor(monitor);
+
+        Assert.assertEquals(0, monitor.getHits());
+
+        // Launch a ChromeTabbedActivity2 to go foreground and put the FullscreenActivity in the
+        // background.
+        mUiThreadTestRule.runOnUiThread(() -> {
+            Intent intent = new Intent(mActivity, ChromeTabbedActivity2.class);
+            mActivity.startActivity(intent);
+        });
+        waitForActivity(ChromeTabbedActivity2.class);
+
+        // Wait for the Tab to leave fullscreen.
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return !isTabFullscreen[0];
+            }
+        });
+
+        Assert.assertEquals(0, monitor.getHits());
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index bb23d01..7bb6e2b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -2903,10 +2903,11 @@
      * Tests that Contextual Search is fully disabled when offline.
      */
     @Test
-    @SmallTest
-    @Feature({"ContextualSearch"})
-    // NOTE: Remove the flag so we will run just this test with onLine detection enabled.
-    @CommandLineFlags.Remove(ContextualSearchFieldTrial.ONLINE_DETECTION_DISABLED)
+    @DisabledTest(message = "https://crbug.com/761946")
+    // @SmallTest
+    // @Feature({"ContextualSearch"})
+    // // NOTE: Remove the flag so we will run just this test with onLine detection enabled.
+    // @CommandLineFlags.Remove(ContextualSearchFieldTrial.ONLINE_DETECTION_DISABLED)
     public void testNetworkDisconnectedDeactivatesSearch()
             throws InterruptedException, TimeoutException {
         setOnlineStatusAndReload(false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 2e7ac137..1ce32c0a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -3029,8 +3029,7 @@
                 BrowsingHistoryBridge historyService = new BrowsingHistoryBridge(false);
                 historyService.setObserver(historyObserver);
                 String historyQueryFilter = "";
-                int historyQueryTimeout = 0;
-                historyService.queryHistory(historyQueryFilter, historyQueryTimeout);
+                historyService.queryHistory(historyQueryFilter);
             }
         });
         historyObserver.getQueryCallback().waitForCallback(0);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java
index 6f5fb81..88d4f50 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/history/StubbedHistoryProvider.java
@@ -33,38 +33,33 @@
     }
 
     @Override
-    public void queryHistory(String query, long endQueryTime) {
-        // endQueryTime should be 0 if the query is changing.
-        if (!TextUtils.equals(query, mLastQuery)) assert endQueryTime == 0;
+    public void queryHistory(String query) {
+        mLastQueryEndPosition = 0;
+        mLastQuery = query;
+        queryHistoryContinuation();
+    }
 
-        if (endQueryTime == 0) {
-            mLastQueryEndPosition = 0;
-        } else {
-            // If endQueryTime is not 0, more items are being paged in and endQueryTime should
-            // equal the timestamp of the last HistoryItem returned in the previous query.
-            assert endQueryTime == mItems.get(mLastQueryEndPosition - 1).getTimestamp();
-        }
-
+    @Override
+    public void queryHistoryContinuation() {
         // Simulate basic paging to facilitate testing loading more items.
         // TODO(twellington): support loading more items while searching.
         int queryStartPosition = mLastQueryEndPosition;
         int queryStartPositionPlusFive = mLastQueryEndPosition + 5;
-        boolean hasMoreItems = queryStartPositionPlusFive < mItems.size()
-                && TextUtils.isEmpty(query);
+        boolean hasMoreItems =
+                queryStartPositionPlusFive < mItems.size() && TextUtils.isEmpty(mLastQuery);
         int queryEndPosition = hasMoreItems ? queryStartPositionPlusFive : mItems.size();
 
         mLastQueryEndPosition = queryEndPosition;
-        mLastQuery = query;
 
         List<HistoryItem> items = new ArrayList<>();
-        if (TextUtils.isEmpty(query)) {
+        if (TextUtils.isEmpty(mLastQuery)) {
             items = mItems.subList(queryStartPosition, queryEndPosition);
         } else {
             // Simulate basic search.
-            query = query.toLowerCase(Locale.getDefault());
+            mLastQuery = mLastQuery.toLowerCase(Locale.getDefault());
             for (HistoryItem item : mItems) {
-                if (item.getUrl().toLowerCase(Locale.getDefault()).contains(query)
-                        || item.getTitle().toLowerCase(Locale.getDefault()).contains(query)) {
+                if (item.getUrl().toLowerCase(Locale.getDefault()).contains(mLastQuery)
+                        || item.getTitle().toLowerCase(Locale.getDefault()).contains(mLastQuery)) {
                     items.add(item);
                 }
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java
new file mode 100644
index 0000000..7436001c
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java
@@ -0,0 +1,212 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.media.ui;
+
+import android.os.Build;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.UiThreadTestRule;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.DOMUtils;
+import org.chromium.content.browser.test.util.JavaScriptUtils;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.media.MediaSwitches;
+import org.chromium.net.test.EmbeddedTestServer;
+
+/**
+ * Tests for PictureInPictureController and related methods.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        MediaSwitches.IGNORE_AUTOPLAY_RESTRICTIONS_FOR_TESTS})
+public class PictureInPictureControllerTest {
+    // TODO(peconn): Add a test for exit on Tab Reparenting.
+    private static final String TEST_PATH = "/chrome/test/data/media/bigbuck-player.html";
+    private static final String VIDEO_ID = "video";
+
+    @Rule
+    public UiThreadTestRule mUiThreadTestRule = new UiThreadTestRule();
+    @Rule
+    public ChromeActivityTestRule<ChromeTabbedActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeTabbedActivity.class);
+
+    private EmbeddedTestServer mTestServer;
+    private ChromeTabbedActivity mActivity;
+
+    @Before
+    public void setUp() throws InterruptedException {
+        mTestServer = EmbeddedTestServer.createAndStartServer(
+                mActivityTestRule.getInstrumentation().getContext());
+        mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(TEST_PATH));
+        mActivity = mActivityTestRule.getActivity();
+    }
+
+    @After
+    public void tearDown() {
+        mTestServer.stopAndDestroyServer();
+    }
+
+    /** Tests that we can detect when a video is playing fullscreen, a prerequisite for PiP. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testFullscreenVideoDetected() throws Throwable {
+        enterFullscreen();
+    }
+
+    /** Tests that fullscreen detection only applies to playing videos. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testFullscreenVideoDetectedOnlyWhenPlaying() throws Throwable {
+        enterFullscreen();
+
+        DOMUtils.pauseMedia(getWebContents(), VIDEO_ID);
+        CriteriaHelper.pollUiThread(
+                Criteria.equals(false, getWebContents()::hasActiveEffectivelyFullscreenVideo));
+    }
+
+    /** Tests that we can enter PiP. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testEnterPip() throws Throwable {
+        enterFullscreen();
+        mActivityTestRule.getInstrumentation().callActivityOnUserLeaving(mActivity);
+
+        CriteriaHelper.pollUiThread(Criteria.equals(true, mActivity::isInPictureInPictureMode));
+    }
+
+    /** Tests that PiP is left when we navigate the main page. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testExitPipOnNavigation() throws Throwable {
+        testExitOn(() -> JavaScriptUtils.executeJavaScript(getWebContents(),
+                "window.location.href = 'https://www.example.com/';"));
+    }
+
+    /** Tests that PiP is left when the video leaves fullscreen. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testExitOnLeaveFullscreen() throws Throwable {
+        testExitOn(() -> DOMUtils.exitFullscreen(getWebContents()));
+    }
+
+    /** Tests that PiP is left when the active Tab is closed. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testExitOnCloseTab() throws Throwable {
+        // We want 2 Tabs so we can close the first without any special behaviour.
+        mActivityTestRule.loadUrlInNewTab(mTestServer.getURL(TEST_PATH));
+
+        testExitOn(() -> JavaScriptUtils.executeJavaScript(getWebContents(), "window.close()"));
+    }
+
+    /** Tests that PiP is left when the renderer crashes. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testExitOnCrash() throws Throwable {
+        testExitOn(() -> ThreadUtils.runOnUiThreadBlocking(
+                () -> getWebContents().simulateRendererKilledForTesting(false)));
+    }
+
+    /** Tests that PiP is left when a new Tab is created in the foreground. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testExitOnNewForegroundTab() throws Throwable {
+        testExitOn(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mActivityTestRule.loadUrlInNewTab("https://www.example.com/");
+                } catch (Exception e) {
+                    throw new RuntimeException();
+                }
+            }
+        });
+    }
+
+    /**
+     * A test to determine if PiP is left when navigation happens on a different frame to the video.
+     * This is the current behaviour, but is a bug. When this is fixed, this test should be updated.
+     * https://crbug.com/718415.
+     */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testExitOnIframeNavigation() throws Throwable {
+        testExitOn(() -> JavaScriptUtils.executeJavaScript(getWebContents(),
+                "document.getElementById('iframe').src = 'https://www.example.com/'"));
+    }
+
+    /** Tests that we can resume PiP after it has been cancelled. */
+    @Test
+    @MediumTest
+    @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    public void testReenterPip() throws Throwable {
+        enterFullscreen();
+        mActivityTestRule.getInstrumentation().callActivityOnUserLeaving(mActivity);
+        CriteriaHelper.pollUiThread(Criteria.equals(true, mActivity::isInPictureInPictureMode));
+
+        mActivityTestRule.startMainActivityFromLauncher();
+        CriteriaHelper.pollUiThread(Criteria.equals(false, mActivity::isInPictureInPictureMode));
+
+        enterFullscreen(false);
+        mActivityTestRule.getInstrumentation().callActivityOnUserLeaving(mActivity);
+        CriteriaHelper.pollUiThread(Criteria.equals(true, mActivity::isInPictureInPictureMode));
+    }
+
+    private WebContents getWebContents() {
+        return mActivity.getCurrentContentViewCore().getWebContents();
+    }
+
+    private void enterFullscreen() throws Throwable {
+        enterFullscreen(true);
+    }
+
+    private void enterFullscreen(boolean firstPlay) throws Throwable {
+        // Start playback to guarantee it's properly loaded.
+        if (firstPlay) Assert.assertTrue(DOMUtils.isMediaPaused(getWebContents(), VIDEO_ID));
+        DOMUtils.playMedia(getWebContents(), VIDEO_ID);
+        DOMUtils.waitForMediaPlay(getWebContents(), VIDEO_ID);
+
+        // Trigger requestFullscreen() via a click on a button.
+        Assert.assertTrue(DOMUtils.clickNode(mActivity.getCurrentContentViewCore(), "fullscreen"));
+
+        // We use the web contents fullscreen heuristic.
+        CriteriaHelper.pollUiThread(
+                Criteria.equals(true, getWebContents()::hasActiveEffectivelyFullscreenVideo));
+    }
+
+    private void testExitOn(Runnable runnable) throws Throwable {
+        enterFullscreen();
+        mActivityTestRule.getInstrumentation().callActivityOnUserLeaving(mActivity);
+        CriteriaHelper.pollUiThread(Criteria.equals(true, mActivity::isInPictureInPictureMode));
+
+        runnable.run();
+
+        CriteriaHelper.pollUiThread(Criteria.equals(false, mActivity::isInPictureInPictureMode));
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
index bbc08dc..98ef1a44 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
@@ -53,11 +53,10 @@
  * Tests OfflinePageBridge.SavePageLater over a batch of urls.
  * Tests against a list of top EM urls, try to call SavePageLater on each of the url. It also
  * record metrics (failure rate, time elapsed etc.) by writing metrics to a file on external
- * storage. This will always use prerenderer.
+ * storage.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({"disable-features=BackgroundLoader",
-        ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG})
 public class OfflinePageSavePageLaterEvaluationTest {
     /**
@@ -114,7 +113,6 @@
     private boolean mIsUserRequested;
     private boolean mUseTestScheduler;
     private int mScheduleBatchSize;
-    private boolean mUseBackgroundLoader;
 
     private LongSparseArray<RequestMetadata> mRequestMetadata;
 
@@ -225,17 +223,15 @@
      * Initializes the evaluation bridge which will be used.
      * @param useCustomScheduler True if customized scheduler (the one with immediate scheduling)
      *                           will be used. False otherwise.
-     * @param useBackgroundLoader True if use background loader. False if use prerenderer.
      */
-    private void initializeBridgeForProfile(final boolean useTestingScheduler,
-            final boolean useBackgroundLoader) throws InterruptedException {
+    private void initializeBridgeForProfile(final boolean useTestingScheduler)
+            throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 Profile profile = Profile.getLastUsedProfile();
-                mBridge = new OfflinePageEvaluationBridge(
-                        profile, useTestingScheduler, useBackgroundLoader);
+                mBridge = new OfflinePageEvaluationBridge(profile, useTestingScheduler);
                 if (mBridge == null) {
                     Assert.fail("OfflinePageEvaluationBridge initialization failed!");
                     return;
@@ -261,10 +257,8 @@
      * Set up the input/output, bridge and observer we're going to use.
      * @param useCustomScheduler True if customized scheduler (the one with immediate scheduling)
      *                           will be used. False otherwise.
-     * @param useBackgroundLoader True if use background loader. False if use prerenderer.
      */
-    protected void setUpIOAndBridge(final boolean useCustomScheduler,
-            final boolean useBackgroundLoader) throws InterruptedException {
+    protected void setUpIOAndBridge(final boolean useCustomScheduler) throws InterruptedException {
         try {
             getUrlListFromInputFile(INPUT_FILE_PATH);
         } catch (IOException e) {
@@ -277,7 +271,7 @@
             mScheduleBatchSize = mUrls.size();
         }
 
-        initializeBridgeForProfile(useCustomScheduler, useBackgroundLoader);
+        initializeBridgeForProfile(useCustomScheduler);
         mObserver = new OfflinePageEvaluationObserver() {
             public void savePageRequestAdded(SavePageRequest request) {
                 RequestMetadata metadata = new RequestMetadata();
@@ -498,8 +492,6 @@
             mIsUserRequested = Boolean.parseBoolean(properties.getProperty("IsUserRequested"));
             mUseTestScheduler = Boolean.parseBoolean(properties.getProperty("UseTestScheduler"));
             mScheduleBatchSize = Integer.parseInt(properties.getProperty("ScheduleBatchSize"));
-            mUseBackgroundLoader =
-                    Boolean.parseBoolean(properties.getProperty("UseBackgroundLoader"));
         } catch (FileNotFoundException e) {
             Log.e(TAG, e.getMessage(), e);
             Assert.fail(String.format(
@@ -530,7 +522,7 @@
     @CommandLineFlags.Remove({"disable-features=OfflinePagesSvelteConcurrentLoading"})
     public void testFailureRate() throws IOException, InterruptedException {
         parseConfigFile();
-        setUpIOAndBridge(mUseTestScheduler, mUseBackgroundLoader);
+        setUpIOAndBridge(mUseTestScheduler);
         processUrls(mUrls);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetTilesUiCaptureTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetTilesUiCaptureTest.java
index e07cb617..f248ca5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetTilesUiCaptureTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetTilesUiCaptureTest.java
@@ -4,12 +4,10 @@
 
 package org.chromium.chrome.browser.suggestions;
 
-import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 import static org.chromium.chrome.test.BottomSheetTestRule.ENABLE_CHROME_HOME;
+import static org.chromium.chrome.test.BottomSheetTestRule.waitForWindowUpdates;
 
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
-import android.support.test.uiautomator.UiDevice;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -42,7 +40,7 @@
 @ScreenShooter.Directory("HomeSheetTiles")
 public class HomeSheetTilesUiCaptureTest {
     @Rule
-    public BottomSheetTestRule mActivityTestRule = new BottomSheetTestRule();
+    public BottomSheetTestRule mActivityRule = new BottomSheetTestRule();
 
     @Rule
     public SuggestionsDependenciesRule setupSuggestions() {
@@ -58,7 +56,7 @@
 
     @Before
     public void setup() throws InterruptedException {
-        mActivityTestRule.startMainActivityOnBlankPage();
+        mActivityRule.startMainActivityOnBlankPage();
     }
 
     @Test
@@ -69,21 +67,9 @@
                     + ChromeFeatureList.CHROME_HOME})
     @ScreenShooter.Directory("Tiles")
     public void testTiles() {
-        setSheetState(BottomSheet.SHEET_STATE_FULL);
+        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_FULL, false);
+        waitForWindowUpdates();
         mScreenShooter.shoot(
                 "Tiles" + (FeatureUtilities.isChromeHomeModernEnabled() ? "_modern" : ""));
     }
-
-    private void setSheetState(final int position) {
-        mActivityTestRule.setSheetState(position, false);
-        waitForWindowUpdates();
-    }
-
-    /** Wait for update to start and finish. */
-    private static void waitForWindowUpdates() {
-        final long maxWindowUpdateTimeMs = scaleTimeout(1000);
-        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        device.waitForWindowUpdate(null, maxWindowUpdateTimeMs);
-        device.waitForIdle(maxWindowUpdateTimeMs);
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetUiCaptureTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetUiCaptureTest.java
index 61453892..5c57c79b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetUiCaptureTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/HomeSheetUiCaptureTest.java
@@ -5,14 +5,11 @@
 package org.chromium.chrome.browser.suggestions;
 
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
 
-import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 import static org.chromium.chrome.test.BottomSheetTestRule.ENABLE_CHROME_HOME;
+import static org.chromium.chrome.test.BottomSheetTestRule.waitForWindowUpdates;
 
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
-import android.support.test.uiautomator.UiDevice;
 import android.support.v7.widget.RecyclerView;
 
 import org.junit.Before;
@@ -25,17 +22,13 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.ScreenShooter;
-import org.chromium.chrome.R;
+import org.chromium.base.test.util.parameter.CommandLineParameter;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.NtpUiCaptureTestData;
 import org.chromium.chrome.browser.ntp.cards.ItemViewType;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
-import org.chromium.chrome.test.BottomSheetTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.util.browser.RecyclerViewTestUtils;
-import org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils;
 import org.chromium.chrome.test.util.browser.suggestions.FakeSuggestionsSource;
 import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
 import org.chromium.ui.test.util.UiRestriction;
@@ -51,16 +44,14 @@
 @ScreenShooter.Directory("HomeSheetStates")
 public class HomeSheetUiCaptureTest {
     @Rule
-    public BottomSheetTestRule mActivityTestRule = new BottomSheetTestRule();
-
-    private FakeSuggestionsSource mSuggestionsSource;
+    public SuggestionsBottomSheetTestRule mActivityRule = new SuggestionsBottomSheetTestRule();
 
     @Rule
     public SuggestionsDependenciesRule setupSuggestions() {
         SuggestionsDependenciesRule.TestFactory depsFactory = NtpUiCaptureTestData.createFactory();
-        mSuggestionsSource = new FakeSuggestionsSource();
-        NtpUiCaptureTestData.registerArticleSamples(mSuggestionsSource);
-        depsFactory.suggestionsSource = mSuggestionsSource;
+        FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource();
+        NtpUiCaptureTestData.registerArticleSamples(suggestionsSource);
+        depsFactory.suggestionsSource = suggestionsSource;
         return new SuggestionsDependenciesRule(depsFactory);
     }
 
@@ -69,90 +60,50 @@
 
     @Before
     public void setup() throws InterruptedException {
-        mActivityTestRule.startMainActivityOnBlankPage();
+        mActivityRule.startMainActivityOnBlankPage();
     }
 
     @Test
     @MediumTest
     @Feature({"UiCatalogue"})
-    // TODO(bauerb): Parameterize this test to test without the modern layout.
-    @CommandLineFlags.Add({
-            "enable-features=" + ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT + ","
-            + ChromeFeatureList.CHROME_HOME})
+    @CommandLineParameter({ENABLE_CHROME_HOME,
+            "enable-features=" + ChromeFeatureList.CHROME_HOME + ","
+                    + ChromeFeatureList.ANDROID_SIGNIN_PROMOS})
     @ScreenShooter.Directory("SignInPromo")
     public void testSignInPromo() {
         // Needs to be "Full" to for this to work on small screens in landscape.
-        setSheetState(BottomSheet.SHEET_STATE_FULL);
+        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_FULL, false);
+        waitForWindowUpdates();
 
-        scrollToFirstItemOfType(ItemViewType.PROMO);
+        mActivityRule.scrollToFirstItemOfType(ItemViewType.PROMO);
 
-        mScreenShooter.shoot(
-                "SignInPromo" + (FeatureUtilities.isChromeHomeModernEnabled() ? "_modern" : ""));
+        boolean newSigninPromo =
+                ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SIGNIN_PROMOS);
+        mScreenShooter.shoot("SignInPromo" + (newSigninPromo ? "_new" : ""));
     }
 
     @Test
     @MediumTest
     @Feature({"UiCatalogue"})
-    // TODO(bauerb): Parameterize this test to test without the modern layout.
-    @CommandLineFlags.Add({
-            "enable-features=" + ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT + ","
-            + ChromeFeatureList.CHROME_HOME})
+    @CommandLineFlags.Add(ENABLE_CHROME_HOME)
     @ScreenShooter.Directory("AllDismissed")
     public void testAllDismissed() {
-        final SuggestionsRecyclerView recyclerView = getRecyclerView();
+        NewTabPageAdapter adapter = mActivityRule.getAdapter();
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            NewTabPageAdapter newTabPageAdapter = recyclerView.getNewTabPageAdapter();
-            int signInPromoPosition = newTabPageAdapter.getFirstPositionForType(ItemViewType.PROMO);
+            int signInPromoPosition = adapter.getFirstPositionForType(ItemViewType.PROMO);
             assertNotEquals(signInPromoPosition, RecyclerView.NO_POSITION);
-            newTabPageAdapter.dismissItem(signInPromoPosition, ignored -> { });
+            adapter.dismissItem(signInPromoPosition, ignored -> { });
 
             // Dismiss all articles.
             while (true) {
-                int articlePosition =
-                        newTabPageAdapter.getFirstPositionForType(ItemViewType.SNIPPET);
+                int articlePosition = adapter.getFirstPositionForType(ItemViewType.SNIPPET);
                 if (articlePosition == RecyclerView.NO_POSITION) break;
-                newTabPageAdapter.dismissItem(articlePosition, ignored -> { });
+                adapter.dismissItem(articlePosition, ignored -> { });
             }
         });
 
-        scrollToFirstItemOfType(ItemViewType.ALL_DISMISSED);
+        mActivityRule.scrollToFirstItemOfType(ItemViewType.ALL_DISMISSED);
 
-        mScreenShooter.shoot(
-                "All_dismissed" + (FeatureUtilities.isChromeHomeModernEnabled() ? "_modern" : ""));
-    }
-
-    private void scrollToFirstItemOfType(@ItemViewType int itemViewType) {
-        SuggestionsRecyclerView recyclerView = getRecyclerView();
-        NewTabPageAdapter newTabPageAdapter = recyclerView.getNewTabPageAdapter();
-        int position = newTabPageAdapter.getFirstPositionForType(itemViewType);
-        assertNotEquals("Scroll target of type " + itemViewType + " not found\n"
-                        + ContentSuggestionsTestUtils.stringify(
-                                  newTabPageAdapter.getRootForTesting()),
-                RecyclerView.NO_POSITION, position);
-
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> recyclerView.getLinearLayoutManager().scrollToPosition(position));
-        RecyclerViewTestUtils.waitForView(recyclerView, position);
-    }
-
-    private void setSheetState(final int position) {
-        mActivityTestRule.setSheetState(position, false);
-        waitForWindowUpdates();
-    }
-
-    private SuggestionsRecyclerView getRecyclerView() {
-        SuggestionsRecyclerView recyclerView =
-                mActivityTestRule.getBottomSheetContent().getContentView().findViewById(
-                        R.id.recycler_view);
-        assertNotNull(recyclerView);
-        return recyclerView;
-    }
-
-    /** Wait for update to start and finish. */
-    private static void waitForWindowUpdates() {
-        final long maxWindowUpdateTimeMs = scaleTimeout(1000);
-        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        device.waitForWindowUpdate(null, maxWindowUpdateTimeMs);
-        device.waitForIdle(maxWindowUpdateTimeMs);
+        mScreenShooter.shoot("All_dismissed");
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java
index c1499ef..436cbb0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java
@@ -21,12 +21,9 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.RetryOnFailure;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.NtpUiCaptureTestData;
 import org.chromium.chrome.browser.ntp.cards.ItemViewType;
-import org.chromium.chrome.test.BottomSheetTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.util.browser.RecyclerViewTestUtils;
 import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
 import org.chromium.content.browser.test.util.TestTouchUtils;
 import org.chromium.ui.test.util.UiRestriction;
@@ -38,7 +35,7 @@
 @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) // ChromeHome is only enabled on phones
 public class SuggestionsBottomSheetTest {
     @Rule
-    public BottomSheetTestRule mActivityRule = new BottomSheetTestRule();
+    public SuggestionsBottomSheetTestRule mActivityRule = new SuggestionsBottomSheetTestRule();
 
     @Rule
     public SuggestionsDependenciesRule createSuggestions() {
@@ -54,15 +51,8 @@
     @RetryOnFailure
     @MediumTest
     public void testContextMenu() throws InterruptedException {
-        SuggestionsRecyclerView recyclerView =
-                mActivityRule.getBottomSheetContent().getContentView().findViewById(
-                        R.id.recycler_view);
-
-        int suggestionPosition =
-                recyclerView.getNewTabPageAdapter().getFirstPositionForType(ItemViewType.SNIPPET);
         ViewHolder suggestionViewHolder =
-                RecyclerViewTestUtils.scrollToView(recyclerView, suggestionPosition);
-
+                mActivityRule.scrollToFirstItemOfType(ItemViewType.SNIPPET);
         assertFalse(mActivityRule.getBottomSheet().onInterceptTouchEvent(createTapEvent()));
 
         TestTouchUtils.longClickView(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTestRule.java
new file mode 100644
index 0000000..f30ff98
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTestRule.java
@@ -0,0 +1,61 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.suggestions;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.support.v7.widget.RecyclerView;
+
+import org.chromium.chrome.browser.ntp.cards.ItemViewType;
+import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
+import org.chromium.chrome.test.BottomSheetTestRule;
+import org.chromium.chrome.test.util.browser.RecyclerViewTestUtils;
+import org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils;
+
+/**
+ * Junit4 rule for testing suggestions in the Chrome Home "Home" sheet.
+ */
+public class SuggestionsBottomSheetTestRule extends BottomSheetTestRule {
+    /**
+     * @return The {@link SuggestionsRecyclerView} for this sheet.
+     */
+    public SuggestionsRecyclerView getRecyclerView() {
+        SuggestionsRecyclerView recyclerView =
+                getBottomSheetContent().getContentView().findViewById(
+                        org.chromium.chrome.R.id.recycler_view);
+        assertNotNull(recyclerView);
+        return recyclerView;
+    }
+
+    /**
+     * @return The {@link NewTabPageAdapter} for this sheet.
+     */
+    public NewTabPageAdapter getAdapter() {
+        return getRecyclerView().getNewTabPageAdapter();
+    }
+
+    /**
+     * @param itemViewType The type of item to find.
+     * @return The position of the first item of the given type.
+     */
+    public int getFirstPositionForType(@ItemViewType int itemViewType) {
+        return getAdapter().getFirstPositionForType(itemViewType);
+    }
+
+    /**
+     * Finds and scrolls to the first item of the given type.
+     * @param type The type of item to find and scroll to.
+     * @return the ViewHolder for the given {@code position}.
+     */
+    public RecyclerView.ViewHolder scrollToFirstItemOfType(@ItemViewType int type) {
+        int position = getFirstPositionForType(type);
+        assertNotEquals("Scroll target of type " + type + " not found\n"
+                        + ContentSuggestionsTestUtils.stringify(getAdapter().getRootForTesting()),
+                RecyclerView.NO_POSITION, position);
+
+        return RecyclerViewTestUtils.scrollToView(getRecyclerView(), position);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetUiCaptureTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetUiCaptureTest.java
index 85cd5fb..10de79e3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetUiCaptureTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetUiCaptureTest.java
@@ -4,13 +4,14 @@
 
 package org.chromium.chrome.browser.suggestions;
 
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.espresso.contrib.RecyclerViewActions;
-import android.support.test.espresso.matcher.ViewMatchers;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.longClick;
+import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import static org.chromium.chrome.test.BottomSheetTestRule.waitForWindowUpdates;
+
 import android.support.test.filters.MediumTest;
-import android.support.test.uiautomator.UiDevice;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -22,20 +23,21 @@
 import org.chromium.base.test.util.ScreenShooter;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.NtpUiCaptureTestData;
+import org.chromium.chrome.browser.ntp.cards.ItemViewType;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
-import org.chromium.chrome.test.BottomSheetTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
 import org.chromium.ui.test.util.UiRestriction;
 
 /**
- * Tests for the appearance of Article Snippets.
+ * Tests for the appearance of Article Suggestions.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) // ChromeHome is only enabled on phones
 public class SuggestionsBottomSheetUiCaptureTest {
     @Rule
-    public BottomSheetTestRule mActivityTestRule = new BottomSheetTestRule();
+    public SuggestionsBottomSheetTestRule mActivityRule = new SuggestionsBottomSheetTestRule();
+
     @Rule
     public SuggestionsDependenciesRule createSuggestions() {
         return new SuggestionsDependenciesRule(NtpUiCaptureTestData.createFactory());
@@ -44,48 +46,40 @@
     @Rule
     public ScreenShooter mScreenShooter = new ScreenShooter();
 
-    private static final int MAX_WINDOW_UPDATE_TIME_MS = 1000;
-
     @Before
     public void setup() throws InterruptedException {
-        mActivityTestRule.startMainActivityOnBlankPage();
-    }
-
-    private void setSheetState(final int position) {
-        mActivityTestRule.setSheetState(position, false);
-        waitForWindowUpdates();
-    }
-
-    private void waitForWindowUpdates() {
-        // Wait for update to start and finish.
-        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        device.waitForWindowUpdate(null, MAX_WINDOW_UPDATE_TIME_MS);
-        device.waitForIdle(MAX_WINDOW_UPDATE_TIME_MS);
+        mActivityRule.startMainActivityOnBlankPage();
     }
 
     @Test
     @MediumTest
     @Feature({"UiCatalogue"})
-    @ScreenShooter.Directory("Suggestions Bottom Sheet Position")
+    @ScreenShooter.Directory("SuggestionsBottomSheetPosition")
     public void testBottomSheetPosition() throws Exception {
-        setSheetState(BottomSheet.SHEET_STATE_HALF);
+        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_HALF, false);
+        waitForWindowUpdates();
         mScreenShooter.shoot("Half");
-        setSheetState(BottomSheet.SHEET_STATE_FULL);
+
+        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_FULL, false);
+        waitForWindowUpdates();
         mScreenShooter.shoot("Full");
-        setSheetState(BottomSheet.SHEET_STATE_PEEK);
+
+        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_PEEK, false);
+        waitForWindowUpdates();
         mScreenShooter.shoot("Peek");
     }
 
     @Test
     @MediumTest
     @Feature({"UiCatalogue"})
-    @ScreenShooter.Directory("Suggestions Context Menu")
+    @ScreenShooter.Directory("SuggestionsContextMenu")
     public void testContextMenu() throws Exception {
         // Needs to be "Full" to for this to work on small screens in landscape.
-        setSheetState(BottomSheet.SHEET_STATE_FULL);
-        Espresso.onView(ViewMatchers.withId(R.id.recycler_view))
-                .perform(RecyclerViewActions.actionOnItemAtPosition(2, ViewActions.longClick()));
+        mActivityRule.setSheetState(BottomSheet.SHEET_STATE_FULL, false);
         waitForWindowUpdates();
-        mScreenShooter.shoot("Context_menu");
+        int position = mActivityRule.getFirstPositionForType(ItemViewType.SNIPPET);
+        onView(withId(R.id.recycler_view)).perform(actionOnItemAtPosition(position, longClick()));
+        waitForWindowUpdates();
+        mScreenShooter.shoot("ContextMenu");
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
index 11cab78..63aa0b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java
@@ -83,6 +83,8 @@
      */
     @Test
     @MediumTest
+    @DisableIf.Build(message = "Flaky on K/L crbug.com/762126",
+            sdk_is_less_than = Build.VERSION_CODES.M)
     public void testScreenTapsNotRegistered() throws InterruptedException {
         mVrTestFramework.loadUrlAndAwaitInitialization(
                 VrTestFramework.getHtmlTestFile("test_screen_taps_not_registered"),
diff --git a/chrome/android/static_initializers.gni b/chrome/android/static_initializers.gni
new file mode 100644
index 0000000..417dc3f
--- /dev/null
+++ b/chrome/android/static_initializers.gni
@@ -0,0 +1,20 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+
+# Be very specific here so that our static initializer count does not vary
+# between bots. This target will cause release bots to fail if the count
+# changes in either direction, and so should be updated when static initializers
+# are removed.
+if (current_toolchain == default_toolchain &&
+    (!is_debug && !using_sanitizer && proprietary_codecs)) {
+  # Define expectations only for target_cpu covered by trybots.
+  if (target_cpu == "arm") {
+    expected_static_initializer_count = 12
+  } else if (target_cpu == "arm64") {
+    expected_static_initializer_count = 9
+  }
+}
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml
index 8c4c17e..0878b1c 100644
--- a/chrome/android/webapk/shell_apk/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -16,7 +16,8 @@
     <application
         android:icon="@mipmap/app_icon"
         android:label="@string/short_name"
-        android:allowBackup="false">
+        android:allowBackup="false"
+        android:supportsRtl="true">
         <activity android:name="org.chromium.webapk.shell_apk.MainActivity"
                   android:theme="@android:style/Theme.Translucent.NoTitleBar"
                   android:excludeFromRecents="true">
@@ -32,6 +33,7 @@
                 <data android:scheme="{{{scope_url_scheme}}}" android:host="{{{scope_url_host}}}" {{{scope_url_path_type}}}="{{{scope_url_path}}}"></data>
             </intent-filter>
             {{/intent_filters}}
+            {{{raw_intent_filters}}}
         </activity>
         <meta-data android:name="org.chromium.webapk.shell_apk.shellApkVersion" android:value="{{{shell_apk_version}}}" />
         {{#bound_webapk}}
diff --git a/chrome/android/webapk/shell_apk/res/layout/choose_host_browser_dialog.xml b/chrome/android/webapk/shell_apk/res/layout/choose_host_browser_dialog.xml
index 20c2f07..2f63747 100644
--- a/chrome/android/webapk/shell_apk/res/layout/choose_host_browser_dialog.xml
+++ b/chrome/android/webapk/shell_apk/res/layout/choose_host_browser_dialog.xml
@@ -11,16 +11,18 @@
 
     <TextView
         android:id="@+id/desc"
-        android:textColor="@android:color/black"
-        android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content" />
+        android:layout_height="wrap_content"
+        android:textSize="@dimen/text_size_large"
+        android:textColor="@color/black_alpha_54"
+        android:layout_marginBottom="12dp" />
 
-   <ListView
+    <ListView
         android:id="@+id/browser_list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:divider="@null"
-        android:dividerHeight="0dp" />
+        android:dividerHeight="0dp"
+        android:layout_marginTop="4dp" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/webapk/shell_apk/res/layout/host_browser_list_item.xml b/chrome/android/webapk/shell_apk/res/layout/host_browser_list_item.xml
index 726504ac..440a6f5 100644
--- a/chrome/android/webapk/shell_apk/res/layout/host_browser_list_item.xml
+++ b/chrome/android/webapk/shell_apk/res/layout/host_browser_list_item.xml
@@ -14,13 +14,19 @@
     <ImageView
         android:id="@+id/browser_icon"
         android:contentDescription="@null"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_gravity="start" />
+        android:layout_width="36dp"
+        android:layout_height="36dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp" />
+
 
     <TextView
         android:id="@+id/browser_name"
         android:layout_gravity="center"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content" />
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="@color/black_alpha_87"
+        android:textSize="@dimen/text_size_medium_dense"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp" />
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/webapk/shell_apk/res/values/colors.xml b/chrome/android/webapk/shell_apk/res/values/colors.xml
new file mode 100644
index 0000000..e4539560
--- /dev/null
+++ b/chrome/android/webapk/shell_apk/res/values/colors.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<resources>
+    <!-- Common colors-->
+    <color name="black_alpha_38">#61000000</color>
+    <color name="black_alpha_54">#8A000000</color>
+    <color name="black_alpha_87">#DE000000</color>
+</resources>
\ No newline at end of file
diff --git a/chrome/android/webapk/shell_apk/res/values/dimens.xml b/chrome/android/webapk/shell_apk/res/values/dimens.xml
new file mode 100644
index 0000000..521318d
--- /dev/null
+++ b/chrome/android/webapk/shell_apk/res/values/dimens.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Common text sizes -->
+    <dimen name="headline_size_medium">20sp</dimen>
+    <dimen name="text_size_large">16sp</dimen>
+    <dimen name="text_size_medium_dense">13sp</dimen>
+
+    <!-- Refers to https://material.googleplex.com/components/dialogs.html#dialogs-specs. -->
+    <dimen name="dialog_content_padding">24dp</dimen>
+    <dimen name="dialog_content_top_padding">12dp</dimen>
+    <dimen name="list_column_padding">16dp</dimen>
+</resources>
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni
index 96a8e70..a719946 100644
--- a/chrome/android/webapk/shell_apk/shell_apk_version.gni
+++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -6,7 +6,7 @@
 # (including AndroidManifest.xml) is updated. This version should be incremented
 # prior to uploading a new ShellAPK to the WebAPK Minting Server.
 # Does not affect Chrome.apk
-template_shell_apk_version = 21
+template_shell_apk_version = 22
 
 # The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK
 # if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java
index c2862b8..68a3b8e7 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java
@@ -9,7 +9,7 @@
 import android.content.DialogInterface;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.graphics.Color;
+import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -89,27 +89,30 @@
                 getBrowserInfosForHostBrowserSelection(context.getPackageManager(), infos);
 
         // The dialog contains:
-        // 1) a description of the dialog.
-        // 2) a list of browsers for user to choose from.
+        // 1) a title
+        // 2) a description of the dialog
+        // 3) a list of browsers for user to choose from
+        TextView title = new TextView(context);
+        title.setText(context.getString(R.string.choose_host_browser_dialog_title, appName));
         View view = LayoutInflater.from(context).inflate(R.layout.choose_host_browser_dialog, null);
+        WebApkUtils.applyAlertDialogContentStyle(context, view, title);
+
         TextView desc = (TextView) view.findViewById(R.id.desc);
-        ListView browserList = (ListView) view.findViewById(R.id.browser_list);
         desc.setText(R.string.choose_host_browser);
-        WebApkUtils.setPadding(desc, context, WebApkUtils.PADDING_DP, 0, WebApkUtils.PADDING_DP, 0);
+
+        ListView browserList = (ListView) view.findViewById(R.id.browser_list);
         browserList.setAdapter(new BrowserArrayAdapter(context, browserItems));
 
         // The context theme wrapper is needed for pre-L.
         AlertDialog.Builder builder = new AlertDialog.Builder(
                 new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light_Dialog));
-        builder.setTitle(context.getString(R.string.choose_host_browser_dialog_title, appName))
-                .setView(view)
-                .setNegativeButton(R.string.choose_host_browser_dialog_quit,
-                        new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                listener.onQuit();
-                            }
-                        });
+        builder.setCustomTitle(title).setView(view).setNegativeButton(
+                R.string.choose_host_browser_dialog_quit, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        listener.onQuit();
+                    }
+                });
 
         final AlertDialog dialog = builder.create();
         browserList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@@ -174,24 +177,25 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
                 convertView = LayoutInflater.from(mContext).inflate(
-                        R.layout.host_browser_list_item, null);
+                        R.layout.host_browser_list_item, parent, false);
             }
 
-            TextView name = (TextView) convertView.findViewById(R.id.browser_name);
-            WebApkUtils.setPadding(name, mContext, WebApkUtils.PADDING_DP, 0, 0, 0);
+            Resources res = mContext.getResources();
             ImageView icon = (ImageView) convertView.findViewById(R.id.browser_icon);
-            WebApkUtils.setPadding(icon, mContext, WebApkUtils.PADDING_DP, 0, 0, 0);
-            BrowserItem item = mBrowsers.get(position);
+            TextView name = (TextView) convertView.findViewById(R.id.browser_name);
+            WebApkUtils.setPaddingInPixel(
+                    name, res.getDimensionPixelSize(R.dimen.list_column_padding), 0, 0, 0);
 
+            BrowserItem item = mBrowsers.get(position);
             name.setEnabled(item.supportsWebApks());
             if (item.supportsWebApks()) {
                 name.setText(item.getApplicationName());
-                name.setTextColor(Color.BLACK);
+                name.setTextColor(WebApkUtils.getColor(res, R.color.black_alpha_87));
             } else {
                 name.setText(mContext.getString(R.string.host_browser_item_not_supporting_webapks,
                         item.getApplicationName()));
                 name.setSingleLine(false);
-                name.setTextColor(Color.LTGRAY);
+                name.setTextColor(WebApkUtils.getColor(res, R.color.black_alpha_38));
             }
             icon.setImageDrawable(item.getApplicationIcon());
             icon.setEnabled(item.supportsWebApks());
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java
index 9be5c059..0ac54579 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java
@@ -7,7 +7,6 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.graphics.Color;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -38,19 +37,22 @@
             final String hostBrowserPackageName, String hostBrowserApplicationName,
             int hostBrowserIconId) {
         View view = LayoutInflater.from(context).inflate(R.layout.host_browser_list_item, null);
-        TextView name = (TextView) view.findViewById(R.id.browser_name);
-        WebApkUtils.setPadding(name, context, WebApkUtils.PADDING_DP, 0, 0, 0);
-        ImageView icon = (ImageView) view.findViewById(R.id.browser_icon);
-        WebApkUtils.setPadding(icon, context, WebApkUtils.PADDING_DP, 0, 0, 0);
+        TextView title = new TextView(context);
+        title.setText(context.getString(R.string.install_host_browser_dialog_title, appName));
+        WebApkUtils.applyAlertDialogContentStyle(context, view, title);
 
-        name.setText(hostBrowserApplicationName);
-        name.setTextColor(Color.BLACK);
+        ImageView icon = (ImageView) view.findViewById(R.id.browser_icon);
         icon.setImageResource(hostBrowserIconId);
 
+        TextView name = (TextView) view.findViewById(R.id.browser_name);
+        name.setText(hostBrowserApplicationName);
+        WebApkUtils.setPaddingInPixel(name,
+                context.getResources().getDimensionPixelSize(R.dimen.list_column_padding), 0, 0, 0);
+
         // The context theme wrapper is needed for pre-L.
         AlertDialog.Builder builder = new AlertDialog.Builder(
                 new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light_Dialog));
-        builder.setTitle(context.getString(R.string.install_host_browser_dialog_title, appName))
+        builder.setCustomTitle(title)
                 .setView(view)
                 .setNegativeButton(R.string.choose_host_browser_dialog_quit,
                         new DialogInterface.OnClickListener() {
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
index 4181fc66..89971bd 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
@@ -11,12 +11,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.TypedValue;
 import android.view.View;
+import android.widget.TextView;
 
 import org.chromium.webapk.lib.common.WebApkConstants;
 import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
@@ -32,7 +34,6 @@
  */
 public class WebApkUtils {
     public static final String SHARED_PREF_RUNTIME_HOST = "runtime_host";
-    public static final int PADDING_DP = 20;
 
     /**
      * The package names of the channels of Chrome that support WebAPKs. The most preferred one
@@ -280,26 +281,48 @@
         editor.apply();
     }
 
-    /** Converts a dp value to a px value. */
-    public static int dpToPx(Context context, int value) {
-        return Math.round(TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_DIP, value, context.getResources().getDisplayMetrics()));
-    }
-
     /**
      * Android uses padding_left under API level 17 and uses padding_start after that.
      * If we set the padding in resource file, android will create duplicated resource xml
      * with the padding to be different.
      */
-    @SuppressWarnings("deprecation")
-    public static void setPadding(
-            View view, Context context, int start, int top, int end, int bottom) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            view.setPaddingRelative(dpToPx(context, start), dpToPx(context, top),
-                    dpToPx(context, end), dpToPx(context, bottom));
+    public static void setPaddingInPixel(View view, int start, int top, int end, int bottom) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setPaddingRelative(start, top, end, bottom);
         } else {
-            view.setPadding(dpToPx(context, start), dpToPx(context, top), dpToPx(context, end),
-                    dpToPx(context, bottom));
+            view.setPadding(start, top, end, bottom);
+        }
+    }
+
+    /**
+     * Imitates Chrome's @style/AlertDialogContent. We set the style via Java instead of via
+     * specifying the style in the XML to avoid having layout files in both layout-v17/ and in
+     * layout/.
+     */
+    public static void applyAlertDialogContentStyle(
+            Context context, View contentView, TextView titleView) {
+        Resources res = context.getResources();
+        titleView.setTextColor(getColor(res, R.color.black_alpha_87));
+        titleView.setTextSize(
+                TypedValue.COMPLEX_UNIT_PX, res.getDimension(R.dimen.headline_size_medium));
+        int dialogContentPadding = res.getDimensionPixelSize(R.dimen.dialog_content_padding);
+        setPaddingInPixel(
+                titleView, dialogContentPadding, dialogContentPadding, dialogContentPadding, 0);
+
+        int dialogContentTopPadding = res.getDimensionPixelSize(R.dimen.dialog_content_top_padding);
+        setPaddingInPixel(contentView, dialogContentPadding, dialogContentTopPadding,
+                dialogContentPadding, dialogContentPadding);
+    }
+
+    /**
+     * @see android.content.res.Resources#getColor(int id).
+     */
+    @SuppressWarnings("deprecation")
+    public static int getColor(Resources res, int id) throws Resources.NotFoundException {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return res.getColor(id, null);
+        } else {
+            return res.getColor(id);
         }
     }
 }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 1b95832..643f8d3 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -238,11 +238,11 @@
   <message name="IDS_FILE_BROWSER_ERROR_WHITESPACE_NAME" desc="Error message displayed when the user enters a file name consisting of only whitespace characters.">
     Invalid name
   </message>
-  <message name="IDS_FILE_BROWSER_ERROR_LONG_NAME" desc="Error message displayed when user trys to enter too long name for a file or a folder.">
-    This name is too long
+  <message name="IDS_FILE_BROWSER_ERROR_LONG_NAME" desc="Error message displayed when user tries to enter too long name for a file or a folder.">
+    Use a shorter name
   </message>
-  <message name="IDS_FILE_BROWSER_ERROR_EXTERNAL_DRIVE_LONG_NAME" desc="Error message displayed when user trys to enter too long name for an external drive.">
-    This name is too long and exceeds $1 character length limit.
+  <message name="IDS_FILE_BROWSER_ERROR_EXTERNAL_DRIVE_LONG_NAME" desc="Error message displayed when user tries to enter too long name for an external drive.">
+    Use a name that's $1 characters or less
   </message>
   <message name="IDS_FILE_BROWSER_EMPTY_FOLDER" desc="Label shown in an empty folder.">
     Nothing to see here...
@@ -5197,6 +5197,9 @@
   </message>
 
   <!-- Print Job Notification -->
+  <message name="IDS_PRINT_JOB_NOTIFICATION_DISPLAY_SOURCE" desc="The context title of printing notification.">
+    Print
+  </message>
   <message name="IDS_PRINT_JOB_PRINTING_NOTIFICATION_TITLE" desc="Title of the printing-in-progress notification.">
     Now printing <ph name="DOCUMENT_NAME">$1<ex>document.pdf</ex></ph>
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 029c2b2..ec607079 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8592,10 +8592,10 @@
           Open <ph name="APPLICATION">$1<ex>Adobe Acrobat</ex></ph>
         </message>
         <message name="IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT" desc="Button in External Protocol Dialog that does not launch the application associated with the protocol">
-          Don't open
+          Cancel
         </message>
         <message name="IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT" desc="Checkbox to ask the user whether they would like their decision remembered.">
-          Remember my choice for <ph name="APPLICATION">$1<ex>Adobe Acrobat</ex></ph> links
+          Always open these types of links in the associated app
         </message>
       </if>
       <if expr="chromeos">
@@ -8752,6 +8752,9 @@
       </message>
 
       <!-- Sync/sign-in error messages -->
+      <message name="IDS_SIGNIN_ERROR_DISPLAY_SOURCE" desc="Context title shown in the notification header of sign-in error notification.">
+        Sign In
+      </message>
       <message name="IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE" desc="Title in the sign-in error bubble view/notification.">
         Sign-in Error
       </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index f664e72a..d3f73099 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3444,14 +3444,14 @@
 
   <!-- Multidevice Page -->
   <if expr="chromeos">
-    <message name="IDS_SETTINGS_MULTIDEVICE" desc="Name of the settings page features the user's other devices connected to the Chromebook.">
+    <message name="IDS_SETTINGS_MULTIDEVICE" desc="Title of a section of settings. This section describes settings for devices that are connected to the Chromebook, like phones.">
       Connected devices
     </message>
-    <message name="IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT" desc="Title of the multi-device feature for displaying SMS notifications.">
-      SMS connect
+    <message name="IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT" desc="Name of a feature. This feature lets the user read and reply to text messages from their Chromebook. New text messages will appear as notifications.">
+      SMS Connect
     </message>
-    <message name="IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT_SUMMARY" desc="Summary explaining what the SMS connect feature does.">
-      Get notifications for new text messages on your Chromebook
+    <message name="IDS_SETTINGS_MULTIDEVICE_SMS_CONNECT_SUMMARY" desc="Description of for the 'SMS Connect' setting.  This feature lets the user read and reply to text messages from their Chromebook. New text messages will appear as notifications.">
+      Read and reply to text messages on your Chromebook
     </message>
   </if>
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 05b360f1..f22b101 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -273,6 +273,8 @@
     "component_updater/supervised_user_whitelist_installer.h",
     "component_updater/sw_reporter_installer_win.cc",
     "component_updater/sw_reporter_installer_win.h",
+    "component_updater/third_party_module_list_component_installer_win.cc",
+    "component_updater/third_party_module_list_component_installer_win.h",
     "conflicts/enumerate_input_method_editors_win.cc",
     "conflicts/enumerate_input_method_editors_win.h",
     "conflicts/enumerate_shell_extensions_win.cc",
@@ -290,6 +292,8 @@
     "conflicts/module_info_win.h",
     "conflicts/module_inspector_win.cc",
     "conflicts/module_inspector_win.h",
+    "conflicts/module_list_manager_win.cc",
+    "conflicts/module_list_manager_win.h",
     "conflicts/msi_util_win.cc",
     "conflicts/msi_util_win.h",
     "conflicts/third_party_metrics_recorder_win.cc",
@@ -590,6 +594,8 @@
     "media/cast_remoting_connector.h",
     "media/cast_remoting_sender.cc",
     "media/cast_remoting_sender.h",
+    "media/cdm_storage_id.cc",
+    "media/cdm_storage_id.h",
     "media/media_access_handler.cc",
     "media/media_access_handler.h",
     "media/media_device_id_salt.cc",
@@ -602,6 +608,8 @@
     "media/media_engagement_service.h",
     "media/media_engagement_service_factory.cc",
     "media/media_engagement_service_factory.h",
+    "media/media_storage_id_salt.cc",
+    "media/media_storage_id_salt.h",
     "media/media_url_constants.cc",
     "media/media_url_constants.h",
     "media/midi_permission_context.cc",
@@ -2375,18 +2383,16 @@
       "task_manager/providers/arc/arc_process_task_provider.cc",
       "task_manager/providers/arc/arc_process_task_provider.h",
     ]
-    deps += [ "//chrome/browser/chromeos" ]
+    deps += [
+      "//chrome/browser/chromeos",
+      "//services/ui/public/cpp/input_devices",
+      "//services/ui/public/cpp/input_devices:input_device_controller",
+      "//ui/ozone",
+    ]
     public_deps += [
       "//components/metrics/leak_detector:interfaces",
       "//components/metrics/leak_detector:leak_detector",
     ]
-    if (use_ozone) {
-      deps += [
-        "//services/ui/public/cpp/input_devices",
-        "//services/ui/public/cpp/input_devices:input_device_controller",
-        "//ui/ozone",
-      ]
-    }
     allow_circular_includes_from += [ "//chrome/browser/chromeos" ]
   } else {  # Non-ChromeOS.
     sources += [
@@ -3014,12 +3020,8 @@
       "dom_distiller/dom_distiller_service_factory_android.cc",
       "dom_distiller/dom_distiller_service_factory_android.h",
       "dom_distiller/tab_utils_android.cc",
-      "download/download_request_infobar_delegate_android.cc",
-      "download/download_request_infobar_delegate_android.h",
       "engagement/site_engagement_service_android.cc",
       "engagement/site_engagement_service_android.h",
-      "geolocation/geolocation_infobar_delegate_android.cc",
-      "geolocation/geolocation_infobar_delegate_android.h",
       "history/android/android_history_provider_service.cc",
       "history/android/android_history_provider_service.h",
       "history/android/android_provider_backend.cc",
@@ -3049,12 +3051,6 @@
       "media/android/router/media_router_android_bridge.h",
       "media/android/router/media_router_dialog_controller_android.cc",
       "media/android/router/media_router_dialog_controller_android.h",
-      "media/midi_permission_infobar_delegate_android.cc",
-      "media/midi_permission_infobar_delegate_android.h",
-      "media/protected_media_identifier_infobar_delegate_android.cc",
-      "media/protected_media_identifier_infobar_delegate_android.h",
-      "media/webrtc/media_stream_infobar_delegate_android.cc",
-      "media/webrtc/media_stream_infobar_delegate_android.h",
       "media/webrtc/screen_capture_infobar_delegate_android.cc",
       "media/webrtc/screen_capture_infobar_delegate_android.h",
       "metrics/android_metrics_provider.cc",
@@ -3065,8 +3061,6 @@
       "net/spdyproxy/data_reduction_promo_infobar_delegate_android.h",
       "net/spdyproxy/data_reduction_proxy_settings_android.cc",
       "net/spdyproxy/data_reduction_proxy_settings_android.h",
-      "notifications/notification_permission_infobar_delegate.cc",
-      "notifications/notification_permission_infobar_delegate.h",
       "notifications/notification_platform_bridge_android.cc",
       "notifications/notification_platform_bridge_android.h",
       "page_load_metrics/observers/android_page_load_metrics_observer.cc",
@@ -3095,12 +3089,8 @@
       "permissions/grouped_permission_infobar_delegate_android.h",
       "permissions/permission_dialog_delegate.cc",
       "permissions/permission_dialog_delegate.h",
-      "permissions/permission_infobar_delegate.cc",
-      "permissions/permission_infobar_delegate.h",
       "permissions/permission_prompt_android.cc",
       "permissions/permission_prompt_android.h",
-      "permissions/permission_queue_controller.cc",
-      "permissions/permission_queue_controller.h",
       "permissions/permission_update_infobar_delegate_android.cc",
       "permissions/permission_update_infobar_delegate_android.h",
       "platform_util_android.cc",
@@ -3731,6 +3721,10 @@
 
   if ((is_linux && !is_chromeos) || is_win) {
     sources += [
+      "feature_engagement/bookmark/bookmark_tracker.cc",
+      "feature_engagement/bookmark/bookmark_tracker.h",
+      "feature_engagement/bookmark/bookmark_tracker_factory.cc",
+      "feature_engagement/bookmark/bookmark_tracker_factory.h",
       "feature_engagement/feature_tracker.cc",
       "feature_engagement/feature_tracker.h",
       "feature_engagement/new_tab/new_tab_tracker.cc",
@@ -4666,6 +4660,8 @@
       "ui/webui/web_ui_test_handler.cc",
       "ui/webui/web_ui_test_handler.h",
     ]
+
+    deps += [ "//chrome/common:mojo_bindings" ]
   }
 
   configs += [ "//build/config:precompiled_headers" ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 65f4aba..4c544b5c 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3103,11 +3103,6 @@
      FEATURE_VALUE_TYPE(features::kWebNfc)},
 #endif
 
-    {"enable-idle-time-spell-checking",
-     flag_descriptions::kEnableIdleTimeSpellCheckingName,
-     flag_descriptions::kEnableIdleTimeSpellCheckingDescription, kOsAll,
-     FEATURE_VALUE_TYPE(features::kIdleTimeSpellChecking)},
-
 #if defined(OS_ANDROID)
     {"enable-clipboard-provider",
      flag_descriptions::kEnableOmniboxClipboardProviderName,
@@ -3277,6 +3272,12 @@
      flag_descriptions::kEnableOutOfBlinkCORSDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kOutOfBlinkCORS)},
 
+    {"keep-alive-renderer-for-keepalive-requests",
+     flag_descriptions::kKeepAliveRendererForKeepaliveRequestsName,
+     flag_descriptions::kKeepAliveRendererForKeepaliveRequestsDescription,
+     kOsAll,
+     FEATURE_VALUE_TYPE(features::kKeepAliveRendererForKeepaliveRequests)},
+
     {"use-ddljson-api", flag_descriptions::kUseDdljsonApiName,
      flag_descriptions::kUseDdljsonApiDescription, kOsAll,
      FEATURE_WITH_PARAMS_VALUE_TYPE(
diff --git a/chrome/browser/android/history/browsing_history_bridge.cc b/chrome/browser/android/history/browsing_history_bridge.cc
index 11c81d8f5..abb5ac5 100644
--- a/chrome/browser/android/history/browsing_history_bridge.cc
+++ b/chrome/browser/android/history/browsing_history_bridge.cc
@@ -58,27 +58,33 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jobject>& j_result_obj,
-    jstring j_query,
-    int64_t j_query_end_time) {
+    jstring j_query) {
   j_query_result_obj_.Reset(env, j_result_obj);
+  query_history_continuation_.Reset();
 
   history::QueryOptions options;
   options.max_count = kMaxQueryCount;
-  if (j_query_end_time == 0) {
-    options.end_time = base::Time();
-  } else {
-    options.end_time = base::Time::FromJavaTime(j_query_end_time);
-  }
   options.duplicate_policy = history::QueryOptions::REMOVE_DUPLICATES_PER_DAY;
 
   browsing_history_service_->QueryHistory(
       base::android::ConvertJavaStringToUTF16(env, j_query), options);
 }
 
+void BrowsingHistoryBridge::QueryHistoryContinuation(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& j_result_obj) {
+  DCHECK(query_history_continuation_);
+  j_query_result_obj_.Reset(env, j_result_obj);
+  std::move(query_history_continuation_).Run();
+}
+
 void BrowsingHistoryBridge::OnQueryComplete(
     const std::vector<BrowsingHistoryService::HistoryEntry>& results,
-    const BrowsingHistoryService::QueryResultsInfo& query_results_info) {
+    const BrowsingHistoryService::QueryResultsInfo& query_results_info,
+    base::OnceClosure continuation_closure) {
   JNIEnv* env = base::android::AttachCurrentThread();
+  query_history_continuation_ = std::move(continuation_closure);
 
   for (const BrowsingHistoryService::HistoryEntry& entry : results) {
     // TODO(twellington): Move the domain logic to BrowsingHistoryServce so it
@@ -108,7 +114,7 @@
 
   Java_BrowsingHistoryBridge_onQueryHistoryComplete(
       env, j_history_service_obj_, j_query_result_obj_,
-      !(query_results_info.reached_beginning_of_local));
+      !(query_results_info.reached_beginning));
 }
 
 void BrowsingHistoryBridge::MarkItemForRemoval(
diff --git a/chrome/browser/android/history/browsing_history_bridge.h b/chrome/browser/android/history/browsing_history_bridge.h
index ca802e2..93d0ed0 100644
--- a/chrome/browser/android/history/browsing_history_bridge.h
+++ b/chrome/browser/android/history/browsing_history_bridge.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
 #include "base/macros.h"
 #include "chrome/browser/history/profile_based_browsing_history_driver.h"
 
@@ -27,8 +28,11 @@
   void QueryHistory(JNIEnv* env,
                     const JavaParamRef<jobject>& obj,
                     const JavaParamRef<jobject>& j_result_obj,
-                    jstring j_query,
-                    int64_t j_query_end_time);
+                    jstring j_query);
+
+  void QueryHistoryContinuation(JNIEnv* env,
+                                const JavaParamRef<jobject>& obj,
+                                const JavaParamRef<jobject>& j_result_obj);
 
   // Adds a HistoryEntry with the |j_url| and |j_native_timestamps| to the list
   // of items being removed. The removal will not be committed until
@@ -47,7 +51,8 @@
   void OnQueryComplete(
       const std::vector<history::BrowsingHistoryService::HistoryEntry>& results,
       const history::BrowsingHistoryService::QueryResultsInfo&
-          query_results_info) override;
+          query_results_info,
+      base::OnceClosure continuation_closure) override;
   void OnRemoveVisitsComplete() override;
   void OnRemoveVisitsFailed() override;
   void HistoryDeleted() override;
@@ -68,6 +73,8 @@
 
   Profile* profile_;
 
+  base::OnceClosure query_history_continuation_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowsingHistoryBridge);
 };
 
diff --git a/chrome/browser/android/mock_location_settings.cc b/chrome/browser/android/mock_location_settings.cc
index 6b80b9cc..9020b96 100644
--- a/chrome/browser/android/mock_location_settings.cc
+++ b/chrome/browser/android/mock_location_settings.cc
@@ -4,13 +4,23 @@
 
 #include "chrome/browser/android/mock_location_settings.h"
 
-bool MockLocationSettings::has_android_location_permission_ = false;
-bool MockLocationSettings::is_system_location_setting_enabled_ = false;
-bool MockLocationSettings::can_prompt_for_android_location_permission_ = false;
-bool MockLocationSettings::location_settings_dialog_enabled_ = false;
-LocationSettingsDialogOutcome
-    MockLocationSettings::location_settings_dialog_outcome_ = NO_PROMPT;
-bool MockLocationSettings::has_shown_location_settings_dialog_ = false;
+#include "base/lazy_instance.h"
+
+namespace {
+
+static bool has_android_location_permission_ = false;
+static bool is_system_location_setting_enabled_ = false;
+static bool can_prompt_for_android_location_permission_ = false;
+static bool location_settings_dialog_enabled_ = false;
+static LocationSettingsDialogOutcome location_settings_dialog_outcome_ =
+    NO_PROMPT;
+static bool has_shown_location_settings_dialog_ = false;
+static bool resolve_location_settings_dialog_async_ = false;
+static base::LazyInstance<
+    LocationSettings::LocationSettingsDialogOutcomeCallback>::Leaky
+    location_settings_dialog_callback_ = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
 
 MockLocationSettings::MockLocationSettings() : LocationSettings() {
 }
@@ -44,6 +54,16 @@
   has_shown_location_settings_dialog_ = false;
 }
 
+void MockLocationSettings::SetAsyncLocationSettingsDialog() {
+  resolve_location_settings_dialog_async_ = true;
+}
+
+void MockLocationSettings::ResolveAsyncLocationSettingsDialog() {
+  DCHECK(!location_settings_dialog_callback_.Get().is_null());
+  std::move(location_settings_dialog_callback_.Get())
+      .Run(location_settings_dialog_outcome_);
+}
+
 bool MockLocationSettings::HasAndroidLocationPermission() {
   return has_android_location_permission_;
 }
@@ -66,5 +86,10 @@
     content::WebContents* web_contents,
     LocationSettingsDialogOutcomeCallback callback) {
   has_shown_location_settings_dialog_ = true;
-  std::move(callback).Run(location_settings_dialog_outcome_);
+
+  if (resolve_location_settings_dialog_async_) {
+    location_settings_dialog_callback_.Get() = std::move(callback);
+  } else {
+    std::move(callback).Run(location_settings_dialog_outcome_);
+  }
 }
diff --git a/chrome/browser/android/mock_location_settings.h b/chrome/browser/android/mock_location_settings.h
index 316805a..5f7167e 100644
--- a/chrome/browser/android/mock_location_settings.h
+++ b/chrome/browser/android/mock_location_settings.h
@@ -25,6 +25,9 @@
   static bool HasShownLocationSettingsDialog();
   static void ClearHasShownLocationSettingsDialog();
 
+  static void SetAsyncLocationSettingsDialog();
+  static void ResolveAsyncLocationSettingsDialog();
+
   // LocationSettings implementation:
   bool HasAndroidLocationPermission() override;
   bool CanPromptForAndroidLocationPermission(
@@ -36,14 +39,6 @@
       content::WebContents* web_contents,
       LocationSettingsDialogOutcomeCallback callback) override;
 
- private:
-  static bool has_android_location_permission_;
-  static bool can_prompt_for_android_location_permission_;
-  static bool is_system_location_setting_enabled_;
-  static bool location_settings_dialog_enabled_;
-  static bool has_shown_location_settings_dialog_;
-  static LocationSettingsDialogOutcome location_settings_dialog_outcome_;
-
   DISALLOW_COPY_AND_ASSIGN(MockLocationSettings);
 };
 
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.cc b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
index 93263ba..3a16b98 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/origin_util.h"
 #include "device/vr/android/gvr/gvr_delegate.h"
+#include "device/vr/android/gvr/gvr_delegate_provider_factory.h"
 #include "device/vr/vr_device.h"
 #include "device/vr/vr_device_manager.h"
 #include "device/vr/vr_display_impl.h"
@@ -47,6 +48,22 @@
   return true;
 }
 
+class VrShellDelegateProviderFactory
+    : public device::GvrDelegateProviderFactory {
+ public:
+  VrShellDelegateProviderFactory() = default;
+  ~VrShellDelegateProviderFactory() override = default;
+  device::GvrDelegateProvider* CreateGvrDelegateProvider() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VrShellDelegateProviderFactory);
+};
+
+device::GvrDelegateProvider*
+VrShellDelegateProviderFactory::CreateGvrDelegateProvider() {
+  return VrShellDelegate::CreateVrShellDelegate();
+}
+
 }  // namespace
 
 class DelegateWebContentsObserver : public content::WebContentsObserver {
@@ -177,26 +194,19 @@
 }
 
 void VrShellDelegate::OnPause(JNIEnv* env, const JavaParamRef<jobject>& obj) {
-  if (gvr_api_) {
-    gvr_api_->PauseTracking();
-  }
+  if (vr_shell_)
+    return;
+  device::VRDevice* device = GetDevice();
+  if (device)
+    device->PauseTracking();
 }
 
 void VrShellDelegate::OnResume(JNIEnv* env, const JavaParamRef<jobject>& obj) {
-  if (gvr_api_) {
-    gvr_api_->ResumeTracking();
-  }
-}
-
-void VrShellDelegate::UpdateNonPresentingContext(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    jlong context) {
-  if (context == 0) {
-    gvr_api_ = nullptr;
+  if (vr_shell_)
     return;
-  }
-  gvr_api_ = gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context));
+  device::VRDevice* device = GetDevice();
+  if (device)
+    device->ResumeTracking();
 }
 
 bool VrShellDelegate::IsClearActivatePending(JNIEnv* env,
@@ -347,19 +357,20 @@
 }
 
 void VrShellDelegate::GetNextMagicWindowPose(
+    gvr::GvrApi* gvr_api,
     device::VRDisplayImpl* display,
     device::mojom::VRDisplay::GetNextMagicWindowPoseCallback callback) {
   content::RenderFrameHost* host = GetHostForDisplay(display);
-  if (!gvr_api_ || vr_shell_ || host == nullptr ||
-      !host->GetView()->HasFocus()) {
+  if (vr_shell_ || host == nullptr || !host->GetView()->HasFocus()) {
     std::move(callback).Run(nullptr);
     return;
   }
   std::move(callback).Run(
-      device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), nullptr));
+      device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api, nullptr));
 }
 
 void VrShellDelegate::CreateVRDisplayInfo(
+    gvr::GvrApi* gvr_api,
     const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback,
     uint32_t device_id) {
   if (vr_shell_) {
@@ -367,8 +378,8 @@
     return;
   }
   // This is for magic window mode, which doesn't care what the render size is.
-  callback.Run(device::GvrDelegate::CreateDefaultVRDisplayInfo(gvr_api_.get(),
-                                                               device_id));
+  callback.Run(
+      device::GvrDelegate::CreateDefaultVRDisplayInfo(gvr_api, device_id));
 }
 
 device::VRDevice* VrShellDelegate::GetDevice() {
@@ -384,8 +395,8 @@
 }
 
 static void OnLibraryAvailable(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
-  device::GvrDelegateProvider::SetInstance(
-      base::Bind(&VrShellDelegate::CreateVrShellDelegate));
+  device::GvrDelegateProviderFactory::Install(
+      new VrShellDelegateProviderFactory);
 }
 
 }  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.h b/chrome/browser/android/vr_shell/vr_shell_delegate.h
index a2598b94..5476e99 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.h
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.h
@@ -54,10 +54,6 @@
                        const base::android::JavaParamRef<jobject>& obj);
   void OnPause(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
-  void UpdateNonPresentingContext(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      jlong context);
   bool IsClearActivatePending(JNIEnv* env,
                               const base::android::JavaParamRef<jobject>& obj);
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
@@ -69,9 +65,6 @@
 
   // device::GvrDelegateProvider implementation.
   void ExitWebVRPresent() override;
-  void CreateVRDisplayInfo(
-      const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback,
-      uint32_t device_id) override;
 
  private:
   // device::GvrDelegateProvider implementation.
@@ -82,7 +75,12 @@
   void OnDisplayAdded(device::VRDisplayImpl* display) override;
   void OnDisplayRemoved(device::VRDisplayImpl* display) override;
   void OnListeningForActivateChanged(device::VRDisplayImpl* display) override;
+  void CreateVRDisplayInfo(
+      gvr::GvrApi* gvr_api,
+      const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback,
+      uint32_t device_id) override;
   void GetNextMagicWindowPose(
+      gvr::GvrApi* gvr_api,
       device::VRDisplayImpl* display,
       device::mojom::VRDisplay::GetNextMagicWindowPoseCallback callback)
       override;
@@ -102,7 +100,6 @@
   device::mojom::VRSubmitFrameClientPtr submit_client_;
   device::mojom::VRPresentationProviderRequest presentation_provider_request_;
   bool pending_successful_present_request_ = false;
-  std::unique_ptr<gvr::GvrApi> gvr_api_;
 
   std::map<content::RenderWidgetHost*, device::VRDisplayImpl*> displays_;
   std::map<device::VRDisplayImpl*, std::unique_ptr<DelegateWebContentsObserver>>
diff --git a/chrome/browser/android/webapk/webapk_install_service.cc b/chrome/browser/android/webapk/webapk_install_service.cc
index e402a277..6b28b71 100644
--- a/chrome/browser/android/webapk/webapk_install_service.cc
+++ b/chrome/browser/android/webapk/webapk_install_service.cc
@@ -60,13 +60,11 @@
 
 void WebApkInstallService::UpdateAsync(
     const std::string& webapk_package,
-    const GURL& start_url,
     const base::string16& short_name,
     std::unique_ptr<std::vector<uint8_t>> serialized_proto,
     const FinishCallback& finish_callback) {
-  WebApkInstaller::UpdateAsync(browser_context_, webapk_package, start_url,
-                               short_name, std::move(serialized_proto),
-                               finish_callback);
+  WebApkInstaller::UpdateAsync(browser_context_, webapk_package, short_name,
+                               std::move(serialized_proto), finish_callback);
 }
 
 void WebApkInstallService::OnFinishedInstall(
diff --git a/chrome/browser/android/webapk/webapk_install_service.h b/chrome/browser/android/webapk/webapk_install_service.h
index 520babf..b37f794 100644
--- a/chrome/browser/android/webapk/webapk_install_service.h
+++ b/chrome/browser/android/webapk/webapk_install_service.h
@@ -73,7 +73,6 @@
   // the Google Play server to install the downloaded WebAPK. Calls
   // |finish_callback| once the update completed or failed.
   void UpdateAsync(const std::string& webapk_package,
-                   const GURL& start_url,
                    const base::string16& short_name,
                    std::unique_ptr<std::vector<uint8_t>> serialized_proto,
                    const FinishCallback& finish_callback);
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index 30492e1..3cbfe8c 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -214,13 +214,12 @@
 void WebApkInstaller::UpdateAsync(
     content::BrowserContext* context,
     const std::string& webapk_package,
-    const GURL& start_url,
     const base::string16& short_name,
     std::unique_ptr<std::vector<uint8_t>> serialized_proto,
     const FinishCallback& finish_callback) {
   // The installer will delete itself when it is done.
   WebApkInstaller* installer = new WebApkInstaller(context);
-  installer->UpdateAsync(webapk_package, start_url, short_name,
+  installer->UpdateAsync(webapk_package, short_name,
                          std::move(serialized_proto), finish_callback);
 }
 
@@ -237,11 +236,10 @@
 void WebApkInstaller::UpdateAsyncForTesting(
     WebApkInstaller* installer,
     const std::string& webapk_package,
-    const GURL& start_url,
     const base::string16& short_name,
     std::unique_ptr<std::vector<uint8_t>> serialized_proto,
     const FinishCallback& finish_callback) {
-  installer->UpdateAsync(webapk_package, start_url, short_name,
+  installer->UpdateAsync(webapk_package, short_name,
                          std::move(serialized_proto), finish_callback);
 }
 
@@ -287,8 +285,6 @@
       base::android::ConvertUTF16ToJavaString(env, short_name_);
   base::android::ScopedJavaLocalRef<jstring> java_token =
       base::android::ConvertUTF8ToJavaString(env, token);
-  base::android::ScopedJavaLocalRef<jstring> java_url =
-      base::android::ConvertUTF8ToJavaString(env, start_url_.spec());
 
   if (task_type_ == WebApkInstaller::INSTALL) {
     webapk::TrackRequestTokenDuration(install_duration_timer_->Elapsed());
@@ -296,10 +292,10 @@
         gfx::ConvertToJavaBitmap(&install_primary_icon_);
     Java_WebApkInstaller_installWebApkAsync(
         env, java_ref_, java_webapk_package, version, java_title, java_token,
-        java_url, install_shortcut_info_->source, java_primary_icon);
+        install_shortcut_info_->source, java_primary_icon);
   } else {
     Java_WebApkInstaller_updateAsync(env, java_ref_, java_webapk_package,
-                                     version, java_title, java_token, java_url);
+                                     version, java_title, java_token);
   }
 }
 
@@ -346,7 +342,6 @@
   install_shortcut_info_.reset(new ShortcutInfo(shortcut_info));
   install_primary_icon_ = primary_icon;
   install_badge_icon_ = badge_icon;
-  start_url_ = shortcut_info.url;
   short_name_ = shortcut_info.short_name;
   finish_callback_ = finish_callback;
   task_type_ = INSTALL;
@@ -367,12 +362,10 @@
 
 void WebApkInstaller::UpdateAsync(
     const std::string& webapk_package,
-    const GURL& start_url,
     const base::string16& short_name,
     std::unique_ptr<std::vector<uint8_t>> serialized_proto,
     const FinishCallback& finish_callback) {
   webapk_package_ = webapk_package;
-  start_url_ = start_url;
   short_name_ = short_name;
   finish_callback_ = finish_callback;
   task_type_ = UPDATE;
diff --git a/chrome/browser/android/webapk/webapk_installer.h b/chrome/browser/android/webapk/webapk_installer.h
index 3a9418d..9f1cd7a 100644
--- a/chrome/browser/android/webapk/webapk_installer.h
+++ b/chrome/browser/android/webapk/webapk_installer.h
@@ -54,7 +54,6 @@
   static void UpdateAsync(
       content::BrowserContext* context,
       const std::string& webapk_package,
-      const GURL& start_url,
       const base::string16& short_name,
       std::unique_ptr<std::vector<uint8_t>> serialized_proto,
       const FinishCallback& callback);
@@ -72,7 +71,6 @@
   static void UpdateAsyncForTesting(
       WebApkInstaller* installer,
       const std::string& webapk_package,
-      const GURL& start_url,
       const base::string16& short_name,
       std::unique_ptr<std::vector<uint8_t>> serialized_proto,
       const FinishCallback& callback);
@@ -132,7 +130,6 @@
   // the Google Play server to install the downloaded WebAPK. Calls
   // |finish_callback| once the update completed or failed.
   void UpdateAsync(const std::string& webapk_package,
-                   const GURL& start_url,
                    const base::string16& short_name,
                    const std::unique_ptr<std::vector<uint8_t>> serialized_proto,
                    const FinishCallback& callback);
diff --git a/chrome/browser/android/webapk/webapk_installer_unittest.cc b/chrome/browser/android/webapk/webapk_installer_unittest.cc
index 341c5ec..eac9a0e 100644
--- a/chrome/browser/android/webapk/webapk_installer_unittest.cc
+++ b/chrome/browser/android/webapk/webapk_installer_unittest.cc
@@ -124,8 +124,7 @@
 
     WebApkInstaller::UpdateAsyncForTesting(
         CreateWebApkInstaller(), kDownloadedWebApkPackageName,
-        GURL() /* start_url */, base::string16() /* short_name */,
-        std::move(serialized_proto_vector),
+        base::string16() /* short_name */, std::move(serialized_proto_vector),
         base::Bind(&WebApkInstallerRunner::OnCompleted,
                    base::Unretained(this)));
 
diff --git a/chrome/browser/android/webapk/webapk_update_manager.cc b/chrome/browser/android/webapk/webapk_update_manager.cc
index 9af9a7b..1756901 100644
--- a/chrome/browser/android/webapk/webapk_update_manager.cc
+++ b/chrome/browser/android/webapk/webapk_update_manager.cc
@@ -129,7 +129,6 @@
 static void UpdateWebApk(JNIEnv* env,
                          const JavaParamRef<jclass>& clazz,
                          const JavaParamRef<jstring>& java_webapk_package,
-                         const JavaParamRef<jstring>& java_start_url,
                          const JavaParamRef<jstring>& java_short_name,
                          const JavaParamRef<jbyteArray>& java_serialized_proto,
                          const JavaParamRef<jobject>& java_callback) {
@@ -148,13 +147,12 @@
 
   std::string webapk_package =
       ConvertJavaStringToUTF8(env, java_webapk_package);
-  GURL start_url = GURL(ConvertJavaStringToUTF8(env, java_start_url));
   base::string16 short_name = ConvertJavaStringToUTF16(env, java_short_name);
   std::unique_ptr<std::vector<uint8_t>> serialized_proto =
       base::MakeUnique<std::vector<uint8_t>>();
   JavaByteArrayToByteVector(env, java_serialized_proto, serialized_proto.get());
 
   WebApkInstallService::Get(profile)->UpdateAsync(
-      webapk_package, start_url, short_name, std::move(serialized_proto),
+      webapk_package, short_name, std::move(serialized_proto),
       base::Bind(&OnUpdated, callback_ref));
 }
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index f9a6164..b4bc9fb3 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -596,6 +596,7 @@
         <include name="IDR_SOUND_ENTER_SCREEN_WAV" file="resources\chromeos\sounds\earcons\enter_screen.wav" type="BINDATA" />
         <include name="IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH_WAV" file="resources\chromeos\sounds\spoken_feedback_toggle_countdown_high.wav" type="BINDATA" />
         <include name="IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW_WAV" file="resources\chromeos\sounds\spoken_feedback_toggle_countdown_low.wav" type="BINDATA" />
+        <include name="IDR_SOUND_TOUCH_TYPE_WAV" file="resources\chromeos\sounds\touch_type.wav" type="BINDATA" />
       </if>
      <if expr="chromeos">
         <include name="IDR_ABOUT_POWER_HTML" file="resources\chromeos\power.html" type="BINDATA" />
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index d9baddc..e41b16f5 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -210,6 +210,7 @@
 #include "base/win/win_util.h"
 #include "chrome/browser/chrome_browser_main_win.h"
 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
+#include "chrome/browser/component_updater/third_party_module_list_component_installer_win.h"
 #include "chrome/browser/downgrade/user_data_downgrade.h"
 #include "chrome/browser/first_run/upgrade_util_win.h"
 #include "chrome/browser/ui/network_profile_bubble.h"
@@ -537,6 +538,7 @@
 #if defined(OS_WIN)
 #if defined(GOOGLE_CHROME_BUILD)
   RegisterSwReporterComponent(cus);
+  RegisterThirdPartyModuleListComponent(cus);
 #endif  // defined(GOOGLE_CHROME_BUILD)
 #endif  // defined(OS_WIN)
 }
@@ -1502,13 +1504,22 @@
                     "now to avoid profile corruption.";
       return chrome::RESULT_CODE_PROFILE_IN_USE;
   }
-#endif  // !defined(OS_ANDROID)
 
   // Handle special early return paths (which couldn't be processed even earlier
   // as they require the process singleton to be held) first.
 
   std::string try_chrome =
       parsed_command_line().GetSwitchValueASCII(switches::kTryChromeAgain);
+
+  // The TryChromeDialog may be aborted by a rendezvous from another browser
+  // process (e.g., a launch via Chrome's taskbar icon or some such). In this
+  // case, browser startup should continue without processing the original
+  // command line (the one with --try-chrome-again), but rather with the command
+  // line from the other process (handled in
+  // ProcessSingletonNotificationCallback thanks to the ProcessSingleton). This
+  // variable is cleared in that particular case, leading to a bypass of the
+  // StartupBrowserCreator.
+  bool process_command_line = true;
   if (!try_chrome.empty()) {
 #if defined(OS_WIN)
     // Setup.exe has determined that we need to run a retention experiment
@@ -1519,7 +1530,7 @@
     base::StringToInt(try_chrome, &try_chrome_int);
     TryChromeDialog::Result answer = TryChromeDialog::Show(
         try_chrome_int,
-        base::Bind(&ChromeProcessSingleton::SetActiveModalDialog,
+        base::Bind(&ChromeProcessSingleton::SetModalDialogNotificationHandler,
                    base::Unretained(process_singleton_.get())));
     switch (answer) {
       case TryChromeDialog::NOT_NOW:
@@ -1532,12 +1543,16 @@
             StartupBrowserCreator::WelcomeBackPage::kWelcomeWin10);
       case TryChromeDialog::OPEN_CHROME_DEFAULT:
         break;
+      case TryChromeDialog::OPEN_CHROME_DEFER:
+        process_command_line = false;
+        break;
     }
 #else
     // We don't support retention experiments on Mac or Linux.
     return content::RESULT_CODE_NORMAL_EXIT;
 #endif  // defined(OS_WIN)
   }
+#endif  // !defined(OS_ANDROID)
 
 #if defined(OS_WIN)
   // Do the tasks if chrome has been upgraded while it was last running.
@@ -1801,8 +1816,11 @@
 
   // This step is costly and is already measured in
   // Startup.StartupBrowserCreator_Start.
-  const bool started = browser_creator_->Start(
-      parsed_command_line(), base::FilePath(), profile_, last_opened_profiles);
+  // See the comment above for an explanation of |process_command_line|.
+  const bool started =
+      !process_command_line ||
+      browser_creator_->Start(parsed_command_line(), base::FilePath(), profile_,
+                              last_opened_profiles);
   const base::TimeTicks start_time_step3 = base::TimeTicks::Now();
   if (started) {
 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index a7c305f..9806a20f 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -170,13 +170,145 @@
   UMA_HISTOGRAM_ENUMERATION("FaultTolerantHeap", detected, FTH_FLAGS_COUNT);
 }
 
+// Notes on the OnModuleEvent() callback.
+//
+// The ModuleDatabase uses the TimeDateStamp value of the DLL to uniquely
+// identify modules as they are discovered. Unlike the SizeOfImage, this value
+// isn't provided via LdrDllNotification events or CreateToolhelp32Snapshot().
+//
+// The easiest way to obtain the TimeDateStamp is to read the mapped module in
+// memory. Unfortunately, this could cause an ACCESS_VIOLATION_EXCEPTION if the
+// module is unloaded before being accessed. This can occur when enumerating
+// already loaded modules with CreateToolhelp32Snapshot(). Note that this
+// problem doesn't affect LdrDllNotification events, where it is guaranteed that
+// the module stays in memory for the duration of the callback.
+//
+// To get around this, there are multiple solutions:
+// (1) Read the file on disk instead.
+//     Sidesteps the problem altogether. The drawback is that it must be done on
+//     a sequence that allow blocking IO, and it is way slower. We don't want to
+//     pay that price for each module in the process. This can fail if the file
+//     can not be found when attemping to read it.
+//
+// (2) Increase the reference count of the module.
+//     Calling ::LoadLibraryEx() or ::GetModuleHandleEx() lets us ensure that
+//     the module won't go away while we hold the extra handle. It's still
+//     possible that the module was unloaded before we have a chance to increase
+//     the reference count, which would mean either reloading the DLL, or
+//     failing to get a new handle.
+//
+//     This isn't ideal but the worst that can happen is that we hold the last
+//     reference to the module. The DLL would be unloaded on our thread when
+//     ::FreeLibrary() is called. This could go horribly wrong if the DLL's
+//     creator didn't consider this possibility.
+//
+// (3) Do it in a Structured Exception Handler (SEH)
+//     Make the read inside a __try/__except handler and handle the possible
+//     ACCESS_VIOLATION_EXCEPTION if it happens.
+//
+// The current solution is (3) with a fallback that uses (1). In the rare case
+// that both fail to get the TimeDateStamp, the module load event is dropped
+// altogether, as our best effort was unsuccessful.
+
+// Gets the TimeDateStamp from the file on disk and, if successful, sends the
+// load event to the ModuleDatabase.
+void HandleModuleLoadEventWithoutTimeDateStamp(
+    const base::FilePath& module_path,
+    size_t module_size,
+    uintptr_t load_address) {
+  uint32_t size_of_image = 0;
+  uint32_t time_date_stamp = 0;
+  bool got_time_date_stamp = GetModuleImageSizeAndTimeDateStamp(
+      module_path, &size_of_image, &time_date_stamp);
+
+  // Simple sanity check.
+  got_time_date_stamp = got_time_date_stamp && size_of_image == module_size;
+  UMA_HISTOGRAM_BOOLEAN("ThirdPartyModules.TimeDateStampObtained",
+                        got_time_date_stamp);
+
+  // Drop the load event if it's not possible to get the time date stamp.
+  if (!got_time_date_stamp)
+    return;
+
+  ModuleDatabase::GetInstance()->OnModuleLoad(content::PROCESS_TYPE_BROWSER,
+                                              module_path, module_size,
+                                              time_date_stamp, load_address);
+}
+
+// Helper function for getting the module size associated with a module in this
+// process based on its load address.
+uint32_t GetModuleSizeOfImage(const void* module_load_address) {
+  base::win::PEImage pe_image(module_load_address);
+  return pe_image.GetNTHeaders()->OptionalHeader.SizeOfImage;
+}
+
 // Helper function for getting the time date stamp associated with a module in
-// this process.
+// this process based on its load address.
 uint32_t GetModuleTimeDateStamp(const void* module_load_address) {
   base::win::PEImage pe_image(module_load_address);
   return pe_image.GetNTHeaders()->FileHeader.TimeDateStamp;
 }
 
+// An exception filter for handling Access Violation exceptions within the
+// memory range [module_load_address, module_load_address + size_of_image).
+DWORD FilterAccessViolation(DWORD exception_code,
+                            const EXCEPTION_POINTERS* exception_information,
+                            void* module_load_address,
+                            uint32_t size_of_image) {
+  if (exception_code != EXCEPTION_ACCESS_VIOLATION)
+    return EXCEPTION_CONTINUE_SEARCH;
+
+  // To make sure an unrelated exception is not swallowed by the exception
+  // handler, the address where the exception happened is verified.
+  const EXCEPTION_RECORD* exception_record =
+      exception_information->ExceptionRecord;
+  const DWORD access_violation_address =
+      exception_record->ExceptionInformation[1];
+
+  uintptr_t range_start = reinterpret_cast<uintptr_t>(module_load_address);
+  uintptr_t range_end = range_start + size_of_image;
+  if (range_start > access_violation_address ||
+      range_end <= access_violation_address) {
+    return EXCEPTION_CONTINUE_SEARCH;
+  }
+
+  return EXCEPTION_EXECUTE_HANDLER;
+}
+
+// Wrapper around GetModuleTimeDateStamp that handles a potential
+// EXCEPTION_ACCESS_VIOLATION that can happen if the |module_load_address| is
+// accessed after the module is unloaded. Also ensures that the expected module
+// is loaded at this address.
+bool TryGetModuleTimeDateStamp(void* module_load_address,
+                               const base::FilePath& module_path,
+                               uint32_t size_of_image,
+                               uint32_t* time_date_stamp) {
+  __try {
+    // Make sure it's the correct module, to protect against a potential race
+    // where a new module was loaded at the same address. This is safe because
+    // the only possibles races are either there was a module loaded at
+    // |module_load_address| and it was unloaded, or there was no module loaded
+    // at |module_load_address| and a new one took its place.
+    wchar_t module_file_name[MAX_PATH];
+    DWORD size =
+        ::GetModuleFileName(reinterpret_cast<HMODULE>(module_load_address),
+                            module_file_name, ARRAYSIZE(module_file_name));
+    if (!size || !base::FilePath::CompareEqualIgnoreCase(module_path.value(),
+                                                         module_file_name)) {
+      return false;
+    }
+    if (size_of_image != GetModuleSizeOfImage(module_load_address))
+      return false;
+
+    *time_date_stamp = GetModuleTimeDateStamp(module_load_address);
+  } __except (FilterAccessViolation(GetExceptionCode(),
+                                    GetExceptionInformation(),
+                                    module_load_address, size_of_image)) {
+    return false;
+  }
+  return true;
+}
+
 // Used as the callback for ModuleWatcher events in this process. Dispatches
 // them to the ModuleDatabase.
 void OnModuleEvent(const ModuleWatcher::ModuleEvent& event) {
@@ -185,7 +317,29 @@
       reinterpret_cast<uintptr_t>(event.module_load_address);
 
   switch (event.event_type) {
-    case mojom::ModuleEventType::MODULE_ALREADY_LOADED:
+    case mojom::ModuleEventType::MODULE_ALREADY_LOADED: {
+      // MODULE_ALREADY_LOADED comes from the enumeration of loaded modules
+      // using CreateToolhelp32Snapshot().
+      uint32_t time_date_stamp = 0;
+      if (TryGetModuleTimeDateStamp(event.module_load_address,
+                                    event.module_path, event.module_size,
+                                    &time_date_stamp)) {
+        module_database->OnModuleLoad(content::PROCESS_TYPE_BROWSER,
+                                      event.module_path, event.module_size,
+                                      time_date_stamp, load_address);
+      } else {
+        // Failed to get the TimeDateStamp directly from memory. The next step
+        // to try is to read the file on disk. This must be done in a blocking
+        // task.
+        base::PostTaskWithTraits(
+            FROM_HERE,
+            {base::MayBlock(),
+             base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+            base::Bind(&HandleModuleLoadEventWithoutTimeDateStamp,
+                       event.module_path, event.module_size, load_address));
+      }
+      return;
+    }
     case mojom::ModuleEventType::MODULE_LOADED: {
       module_database->OnModuleLoad(
           content::PROCESS_TYPE_BROWSER, event.module_path, event.module_size,
diff --git a/chrome/browser/chrome_process_singleton.cc b/chrome/browser/chrome_process_singleton.cc
index a682457..e13e262 100644
--- a/chrome/browser/chrome_process_singleton.cc
+++ b/chrome/browser/chrome_process_singleton.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chrome_process_singleton.h"
 
+#include <utility>
+
 ChromeProcessSingleton::ChromeProcessSingleton(
     const base::FilePath& user_data_dir,
     const ProcessSingleton::NotificationCallback& notification_callback)
@@ -13,19 +15,6 @@
                          modal_dialog_lock_.AsNotificationCallback()) {
 }
 
-
-ChromeProcessSingleton::ChromeProcessSingleton(
-      const base::FilePath& user_data_dir,
-      const ProcessSingleton::NotificationCallback& notification_callback,
-      const ProcessSingletonModalDialogLock::SetForegroundWindowHandler&
-          set_foreground_window_handler)
-    : startup_lock_(notification_callback),
-      modal_dialog_lock_(startup_lock_.AsNotificationCallback(),
-                         set_foreground_window_handler),
-      process_singleton_(user_data_dir,
-                         modal_dialog_lock_.AsNotificationCallback()) {
-}
-
 ChromeProcessSingleton::~ChromeProcessSingleton() {
 }
 
@@ -38,9 +27,10 @@
   process_singleton_.Cleanup();
 }
 
-void ChromeProcessSingleton::SetActiveModalDialog(
-    gfx::NativeWindow active_dialog) {
-  modal_dialog_lock_.SetActiveModalDialog(active_dialog);
+void ChromeProcessSingleton::SetModalDialogNotificationHandler(
+    base::Closure notification_handler) {
+  modal_dialog_lock_.SetModalDialogNotificationHandler(
+      std::move(notification_handler));
 }
 
 void ChromeProcessSingleton::Unlock() {
diff --git a/chrome/browser/chrome_process_singleton.h b/chrome/browser/chrome_process_singleton.h
index 7d62731..71df237 100644
--- a/chrome/browser/chrome_process_singleton.h
+++ b/chrome/browser/chrome_process_singleton.h
@@ -5,39 +5,31 @@
 #ifndef CHROME_BROWSER_CHROME_PROCESS_SINGLETON_H_
 #define CHROME_BROWSER_CHROME_PROCESS_SINGLETON_H_
 
+#include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "chrome/browser/process_singleton.h"
 #include "chrome/browser/process_singleton_modal_dialog_lock.h"
 #include "chrome/browser/process_singleton_startup_lock.h"
-#include "ui/gfx/native_widget_types.h"
 
 // Composes a basic ProcessSingleton with ProcessSingletonStartupLock and
 // ProcessSingletonModalDialogLock.
 //
-// Notifications from ProcessSingleton will be discarded if a modal dialog is
-// active. Otherwise, until |Unlock()| is called, they will be queued up.
-// Once unlocked, notifications will be passed to the client-supplied
+// Notifications from ProcessSingleton will first close a modal dialog if
+// active. Otherwise, until |Unlock()| is called, they will be queued up. Once
+// unlocked, notifications will be passed to the client-supplied
 // NotificationCallback.
 //
-// The client must ensure that SetActiveModalDialog is called appropriately when
-// dialogs are displayed or dismissed during startup. While a dialog is active:
-// 1. Neither this process nor the invoking process will handle the command
-//    line.
-// 2. The active dialog is brought to the foreground and/or the taskbar icon
-//    flashed (using ::SetForegroundWindow on Windows).
+// The client must ensure that SetModalDialogNotificationHandler is called
+// appropriately when dialogs are displayed or dismissed during startup. If a
+// dialog is active, it is closed (via the provided handler) and then the
+// notification is processed as normal.
 class ChromeProcessSingleton {
  public:
   ChromeProcessSingleton(
       const base::FilePath& user_data_dir,
       const ProcessSingleton::NotificationCallback& notification_callback);
 
-  ChromeProcessSingleton(
-      const base::FilePath& user_data_dir,
-      const ProcessSingleton::NotificationCallback& notification_callback,
-      const ProcessSingletonModalDialogLock::SetForegroundWindowHandler&
-          set_foreground_window_handler);
-
   ~ChromeProcessSingleton();
 
   // Notify another process, if available. Otherwise sets ourselves as the
@@ -50,9 +42,9 @@
   // Clear any lock state during shutdown.
   void Cleanup();
 
-  // Receives a handle to the active modal dialog, or NULL if the active dialog
-  // is dismissed.
-  void SetActiveModalDialog(gfx::NativeWindow active_dialog);
+  // Receives a callback to be run to close the active modal dialog, or an empty
+  // closure if the active dialog is dismissed.
+  void SetModalDialogNotificationHandler(base::Closure notification_handler);
 
   // Executes previously queued command-line invocations and allows future
   // invocations to be executed immediately.
diff --git a/chrome/browser/chrome_process_singleton_win_unittest.cc b/chrome/browser/chrome_process_singleton_win_unittest.cc
index 7bc4f71..a87262cd 100644
--- a/chrome/browser/chrome_process_singleton_win_unittest.cc
+++ b/chrome/browser/chrome_process_singleton_win_unittest.cc
@@ -85,8 +85,7 @@
 #if defined(OS_WIN) && !defined(USE_AURA)
 namespace {
 
-void SetForegroundWindowHandler(bool* flag,
-                                gfx::NativeWindow /* target_window */) {
+void ModalNotificationHandler(bool* flag) {
   *flag = true;
 }
 
@@ -97,14 +96,14 @@
   ASSERT_TRUE(profile_dir.CreateUniqueTempDir());
 
   int callback_count = 0;
-  bool called_set_foreground_window = false;
+  bool called_modal_notification_handler = false;
 
   ChromeProcessSingleton ps1(
       profile_dir.GetPath(),
-      base::Bind(&ServerCallback, base::Unretained(&callback_count)),
-      base::Bind(&SetForegroundWindowHandler,
-                 base::Unretained(&called_set_foreground_window)));
-  ps1.SetActiveModalDialog(::GetShellWindow());
+      base::Bind(&ServerCallback, base::Unretained(&callback_count)));
+  ps1.SetModalDialogNotificationHandler(
+      base::Bind(&ModalNotificationHandler,
+                 base::Unretained(&called_modal_notification_handler)));
 
   ChromeProcessSingleton ps2(profile_dir.GetPath(),
                              base::Bind(&ClientCallback));
@@ -115,21 +114,21 @@
   ASSERT_EQ(ProcessSingleton::PROCESS_NONE, result);
   ASSERT_EQ(0, callback_count);
 
-  ASSERT_FALSE(called_set_foreground_window);
+  ASSERT_FALSE(called_modal_notification_handler);
   result = ps2.NotifyOtherProcessOrCreate();
   ASSERT_EQ(ProcessSingleton::PROCESS_NOTIFIED, result);
-  ASSERT_TRUE(called_set_foreground_window);
+  ASSERT_TRUE(called_modal_notification_handler);
 
   ASSERT_EQ(0, callback_count);
-  ps1.SetActiveModalDialog(NULL);
+  ps1.SetModalDialogNotificationHandler(base::Closure());
   ps1.Unlock();
-  // The notification sent while a modal dialog was present was silently
-  // dropped.
-  ASSERT_EQ(0, callback_count);
+  // The notifications sent while a modal dialog was open were processed after
+  // unlock.
+  ASSERT_EQ(2, callback_count);
 
-  // But now that the active modal dialog is NULL notifications will be handled.
+  // And now that the handler was cleared notifications will still be handled.
   result = ps2.NotifyOtherProcessOrCreate();
   ASSERT_EQ(ProcessSingleton::PROCESS_NOTIFIED, result);
-  ASSERT_EQ(1, callback_count);
+  ASSERT_EQ(3, callback_count);
 }
 #endif  // defined(OS_WIN) && !defined(USE_AURA)
diff --git a/chrome/browser/chrome_quota_permission_context.cc b/chrome/browser/chrome_quota_permission_context.cc
index 99e2ba8c..171c0d6f 100644
--- a/chrome/browser/chrome_quota_permission_context.cc
+++ b/chrome/browser/chrome_quota_permission_context.cc
@@ -28,9 +28,6 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar.h"
 #else
 #include "components/vector_icons/vector_icons.h"
 #endif
@@ -149,103 +146,6 @@
   return PermissionRequestType::QUOTA;
 }
 
-#if defined(OS_ANDROID)
-// RequestQuotaInfoBarDelegate ------------------------------------------------
-
-class RequestQuotaInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  // Creates a request quota infobar and delegate and adds the infobar to
-  // |infobar_service|.
-  static void Create(
-      InfoBarService* infobar_service,
-      ChromeQuotaPermissionContext* context,
-      const GURL& origin_url,
-      int64_t requested_quota,
-      const content::QuotaPermissionContext::PermissionCallback& callback);
-
- private:
-  RequestQuotaInfoBarDelegate(
-      ChromeQuotaPermissionContext* context,
-      const GURL& origin_url,
-      int64_t requested_quota,
-      const content::QuotaPermissionContext::PermissionCallback& callback);
-  ~RequestQuotaInfoBarDelegate() override;
-
-  // ConfirmInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  base::string16 GetMessageText() const override;
-  bool Accept() override;
-  bool Cancel() override;
-
-  scoped_refptr<ChromeQuotaPermissionContext> context_;
-  GURL origin_url_;
-  int64_t requested_quota_;
-  content::QuotaPermissionContext::PermissionCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(RequestQuotaInfoBarDelegate);
-};
-
-// static
-void RequestQuotaInfoBarDelegate::Create(
-    InfoBarService* infobar_service,
-    ChromeQuotaPermissionContext* context,
-    const GURL& origin_url,
-    int64_t requested_quota,
-    const content::QuotaPermissionContext::PermissionCallback& callback) {
-  infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
-      std::unique_ptr<ConfirmInfoBarDelegate>(new RequestQuotaInfoBarDelegate(
-          context, origin_url, requested_quota, callback))));
-}
-
-RequestQuotaInfoBarDelegate::RequestQuotaInfoBarDelegate(
-    ChromeQuotaPermissionContext* context,
-    const GURL& origin_url,
-    int64_t requested_quota,
-    const content::QuotaPermissionContext::PermissionCallback& callback)
-    : ConfirmInfoBarDelegate(),
-      context_(context),
-      origin_url_(origin_url),
-      requested_quota_(requested_quota),
-      callback_(callback) {}
-
-RequestQuotaInfoBarDelegate::~RequestQuotaInfoBarDelegate() {
-  if (!callback_.is_null()) {
-    context_->DispatchCallbackOnIOThread(
-        callback_,
-        content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED);
-  }
-}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-RequestQuotaInfoBarDelegate::GetIdentifier() const {
-  return REQUEST_QUOTA_INFOBAR_DELEGATE;
-}
-
-base::string16 RequestQuotaInfoBarDelegate::GetMessageText() const {
-  // If the site requested larger quota than this threshold, show a different
-  // message to the user.
-  return l10n_util::GetStringFUTF16(
-      (requested_quota_ > kRequestLargeQuotaThreshold
-           ? IDS_REQUEST_LARGE_QUOTA_INFOBAR_QUESTION
-           : IDS_REQUEST_QUOTA_INFOBAR_QUESTION),
-      url_formatter::FormatUrlForSecurityDisplay(origin_url_));
-}
-
-bool RequestQuotaInfoBarDelegate::Accept() {
-  context_->DispatchCallbackOnIOThread(
-      callback_,
-      content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW);
-  return true;
-}
-
-bool RequestQuotaInfoBarDelegate::Cancel() {
-  context_->DispatchCallbackOnIOThread(
-      callback_,
-      content::QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_CANCELLED);
-  return true;
-}
-#endif
-
 }  // namespace
 
 
@@ -293,27 +193,14 @@
     return;
   }
 
-  if (PermissionRequestManager::IsEnabled()) {
-    PermissionRequestManager* permission_request_manager =
-        PermissionRequestManager::FromWebContents(web_contents);
-    if (permission_request_manager) {
-      bool is_large_quota_request =
-          params.requested_size > kRequestLargeQuotaThreshold;
-      permission_request_manager->AddRequest(new QuotaPermissionRequest(
-          this, params.origin_url, is_large_quota_request, callback));
-      return;
-    }
-#if defined(OS_ANDROID)
-  } else {
-    InfoBarService* infobar_service =
-        InfoBarService::FromWebContents(web_contents);
-    if (infobar_service) {
-      RequestQuotaInfoBarDelegate::Create(infobar_service, this,
-                                          params.origin_url,
-                                          params.requested_size, callback);
-      return;
-    }
-#endif
+  PermissionRequestManager* permission_request_manager =
+      PermissionRequestManager::FromWebContents(web_contents);
+  if (permission_request_manager) {
+    bool is_large_quota_request =
+        params.requested_size > kRequestLargeQuotaThreshold;
+    permission_request_manager->AddRequest(new QuotaPermissionRequest(
+        this, params.origin_url, is_large_quota_request, callback));
+    return;
   }
 
   // The tab has no UI service for presenting the permissions request.
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 36c4460e..e15d8fd 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -301,6 +301,8 @@
   manager->Initialize(SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW,
                       bundle.GetRawDataResource(
                           IDR_SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW_WAV));
+  manager->Initialize(SOUND_TOUCH_TYPE,
+                      bundle.GetRawDataResource(IDR_SOUND_TOUCH_TYPE_WAV));
 
   base::FilePath resources_path;
   if (!PathService::Get(chrome::DIR_RESOURCES, &resources_path))
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
index 3dcfee8..9c1a07a4 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
@@ -4,7 +4,6 @@
 
 #include <string>
 
-#include "ash/accessibility_types.h"
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/shell.h"
@@ -74,10 +73,6 @@
                       enabled);
 }
 
-void SetScreenMagnifierTypePref(ash::MagnifierType type) {
-  prefs()->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType, type);
-}
-
 void SetFullScreenMagnifierScalePref(double scale) {
   prefs()->SetDouble(ash::prefs::kAccessibilityScreenMagnifierScale, scale);
 }
@@ -242,7 +237,6 @@
 
   // Sets prefs to explicitly enable the magnifier.
   SetScreenMagnifierEnabledPref(true);
-  SetScreenMagnifierTypePref(ash::MAGNIFIER_FULL);
   SetFullScreenMagnifierScalePref(2.5);
 }
 
@@ -273,7 +267,6 @@
 
   // Sets prefs to explicitly enable the magnifier.
   SetScreenMagnifierEnabledPref(true);
-  SetScreenMagnifierTypePref(ash::MAGNIFIER_FULL);
   SetFullScreenMagnifierScalePref(2.5);
 }
 
@@ -395,7 +388,6 @@
   EXPECT_FALSE(IsMagnifierEnabled());
 
   // Sets the pref as true to enable magnifier.
-  SetScreenMagnifierTypePref(ash::MAGNIFIER_FULL);
   SetScreenMagnifierEnabledPref(true);
   // Confirms that magnifier is enabled.
   EXPECT_TRUE(IsMagnifierEnabled());
diff --git a/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
index b5778848..f9fedee 100644
--- a/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
@@ -22,6 +22,7 @@
 #include "chrome/test/base/interactive_test_utils.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/prefs/pref_service.h"
+#include "ui/app_list/presenter/app_list.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/events/test/event_generator.h"
@@ -162,7 +163,7 @@
 
   // Make sure that the AppList is not erroneously displayed and the omnibox
   // doesn't lose focus.
-  EXPECT_FALSE(ash::Shell::Get()->GetAppListTargetVisibility());
+  EXPECT_FALSE(ash::Shell::Get()->app_list()->GetTargetVisibility());
   EXPECT_TRUE(omnibox->GetNativeView()->HasFocus());
 
   // Type 'foo'.
@@ -176,14 +177,14 @@
   ASSERT_EQ(3U, start);
   ASSERT_EQ(3U, end);
 
-  EXPECT_FALSE(ash::Shell::Get()->GetAppListTargetVisibility());
+  EXPECT_FALSE(ash::Shell::Get()->app_list()->GetTargetVisibility());
   EXPECT_TRUE(omnibox->GetNativeView()->HasFocus());
 
   // Hit Home by sequencing Search (left Windows) and Left (arrow).
   SendKeyPress(ui::VKEY_LWIN);
   SendKeyPress(ui::VKEY_LEFT);
 
-  EXPECT_FALSE(ash::Shell::Get()->GetAppListTargetVisibility());
+  EXPECT_FALSE(ash::Shell::Get()->app_list()->GetTargetVisibility());
   EXPECT_TRUE(omnibox->GetNativeView()->HasFocus());
 
   // Verify caret moved to the beginning.
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc
index 54fc5b72..60858b0 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.cc
+++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -43,9 +43,13 @@
 constexpr char kActionCloseWindow[] = "closeWindow";
 
 // Action to show a page. The message should have "page" field, which is one of
-// IDs for section div elements.
+// IDs for section div elements. For the "active-directory-auth" page, the
+// "federationUrl" and "deviceManagementUrlPrefix" options are required.
 constexpr char kActionShowPage[] = "showPage";
 constexpr char kPage[] = "page";
+constexpr char kOptions[] = "options";
+constexpr char kFederationUrl[] = "federationUrl";
+constexpr char kDeviceManagementUrlPrefix[] = "deviceManagementUrlPrefix";
 
 // Action to show the error page. The message should have "errorMessage",
 // which is a localized error text, and "shouldShowSendFeedback" boolean value.
@@ -53,11 +57,6 @@
 constexpr char kErrorMessage[] = "errorMessage";
 constexpr char kShouldShowSendFeedback[] = "shouldShowSendFeedback";
 
-// Action to set the Active Directory Federation Services SAML redirect URL.
-constexpr char kActionActiveDirectoryAuthUrls[] = "setActiveDirectoryAuthUrls";
-constexpr char kFederationUrl[] = "federationUrl";
-constexpr char kDeviceManagementUrlPrefix[] = "deviceManagementUrlPrefix";
-
 // The preference update should have those two fields.
 constexpr char kEnabled[] = "enabled";
 constexpr char kManaged[] = "managed";
@@ -239,7 +238,6 @@
   active_directory_auth_federation_url_ = federation_url;
   active_directory_auth_device_management_url_prefix_ =
       device_management_url_prefix;
-  SendActiveDirectoryAuthUrls();
   ShowPage(UIPage::ACTIVE_DIRECTORY_AUTH);
 }
 
@@ -270,9 +268,15 @@
       message.SetString(kPage, "arc-loading");
       break;
     case UIPage::ACTIVE_DIRECTORY_AUTH:
-      // TODO(ljusten): Change this to a function similar to ShowError that
-      // sends the active_directory_auth* URLS along with the show message.
+      DCHECK(active_directory_auth_federation_url_.is_valid());
+      DCHECK(!active_directory_auth_device_management_url_prefix_.empty());
       message.SetString(kPage, "active-directory-auth");
+      message.SetPath(
+          {kOptions, kFederationUrl},
+          base::Value(active_directory_auth_federation_url_.spec()));
+      message.SetPath(
+          {kOptions, kDeviceManagementUrlPrefix},
+          base::Value(active_directory_auth_device_management_url_prefix_));
       break;
     default:
       NOTREACHED();
@@ -366,26 +370,6 @@
   message_host_->SendMessage(message);
 }
 
-void ArcSupportHost::SendActiveDirectoryAuthUrls() {
-  // Missing |message_host_| is normal on first run.
-  if (!message_host_)
-    return;
-
-  // URLs might be invalid when called from SetMessageHost.
-  if (!active_directory_auth_federation_url_.is_valid() ||
-      active_directory_auth_device_management_url_prefix_.empty()) {
-    return;
-  }
-
-  base::DictionaryValue message;
-  message.SetString(kAction, kActionActiveDirectoryAuthUrls);
-  message.SetString(kFederationUrl,
-                    active_directory_auth_federation_url_.spec());
-  message.SetString(kDeviceManagementUrlPrefix,
-                    active_directory_auth_device_management_url_prefix_);
-  message_host_->SendMessage(message);
-}
-
 void ArcSupportHost::SetMessageHost(arc::ArcSupportMessageHost* message_host) {
   if (message_host_ == message_host)
     return;
@@ -413,9 +397,6 @@
   SendPreferenceCheckboxUpdate(kActionLocationServiceMode,
                                location_services_checkbox_);
 
-  // Send URLs needed for Active Directory SAML authentication.
-  SendActiveDirectoryAuthUrls();
-
   if (ui_page_ == UIPage::NO_PAGE) {
     // Close() is called before opening the window.
     Close();
@@ -611,6 +592,10 @@
       NOTREACHED();
       return;
     }
+    // TODO(https://crbug.com/756144): Remove once reason for crash has been
+    // determined.
+    LOG_IF(ERROR, !auth_delegate_)
+        << "auth_delegate_ is NULL, error: " << error_message;
     auth_delegate_->OnAuthFailed(error_message);
   } else if (event == kEventOnAgreed) {
     DCHECK(tos_delegate_);
diff --git a/chrome/browser/chromeos/arc/arc_support_host.h b/chrome/browser/chromeos/arc/arc_support_host.h
index 1c1eb2b..49c43b4 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.h
+++ b/chrome/browser/chromeos/arc/arc_support_host.h
@@ -204,9 +204,6 @@
   void SendPreferenceCheckboxUpdate(const std::string& action_name,
                                     const PreferenceCheckboxData& data);
 
-  // Sends the two active_directory_auth_* URLs (see below) to the extension.
-  void SendActiveDirectoryAuthUrls();
-
   void DisconnectMessageHost();
 
   Profile* const profile_;
diff --git a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
index ba5d455..48df771 100644
--- a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
+++ b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
@@ -152,6 +152,17 @@
       ui_page_ = ArcSupportHost::UIPage::ARC_LOADING;
     } else if (page == "active-directory-auth") {
       ui_page_ = ArcSupportHost::UIPage::ACTIVE_DIRECTORY_AUTH;
+      const base::Value* federation_url = message->FindPathOfType(
+          {"options", "federationUrl"}, base::Value::Type::STRING);
+      const base::Value* device_management_url_prefix = message->FindPathOfType(
+          {"options", "deviceManagementUrlPrefix"}, base::Value::Type::STRING);
+      if (!federation_url || !device_management_url_prefix) {
+        NOTREACHED() << message_string;
+        return;
+      }
+      active_directory_auth_federation_url_ = federation_url->GetString();
+      active_directory_auth_device_management_url_prefix_ =
+          device_management_url_prefix->GetString();
     } else {
       NOTREACHED() << message_string;
     }
@@ -172,15 +183,6 @@
       NOTREACHED() << message_string;
       return;
     }
-  } else if (action == "setActiveDirectoryAuthUrls") {
-    if (!message->GetString("federationUrl",
-                            &active_directory_auth_federation_url_) ||
-        !message->GetString(
-            "deviceManagementUrlPrefix",
-            &active_directory_auth_device_management_url_prefix_)) {
-      NOTREACHED() << message_string;
-      return;
-    }
   } else if (action == "closeWindow") {
     // Do nothing as emulation.
   } else {
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 a3491e5..4779256 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -99,6 +99,7 @@
 class ArcSettingsServiceImpl
     : public chromeos::system::TimezoneSettings::Observer,
       public ArcSessionManager::Observer,
+      public InstanceHolder<mojom::AppInstance>::Observer,
       public chromeos::NetworkStateHandlerObserver {
  public:
   ArcSettingsServiceImpl(content::BrowserContext* context,
@@ -137,7 +138,11 @@
   void SyncInitialSettings() const;
   // Retrieves Chrome's state for the settings that need to be synced on each
   // Android boot and send it to Android.
-  void SyncRuntimeSettings() const;
+  void SyncBootTimeSettings() const;
+  // Retrieves Chrome's state for the settings that need to be synced on each
+  // Android boot after AppInstance is ready and send it to Android.
+  // TODO(crbug.com/762553): Sync settings at proper time.
+  void SyncAppTimeSettings() const;
   // Determine whether a particular setting needs to be synced to Android.
   // Keep these lines ordered lexicographically.
   bool ShouldSyncBackupEnabled() const;
@@ -180,6 +185,9 @@
   void SendSettingsBroadcast(const std::string& action,
                              const base::DictionaryValue& extras) const;
 
+  // InstanceHolder<mojom::AppInstance>::Observer:
+  void OnInstanceReady() override;
+
   content::BrowserContext* const context_;
   ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
 
@@ -201,14 +209,22 @@
       arc_bridge_service_(arc_bridge_service),
       weak_factory_(this) {
   StartObservingSettingsChanges();
-  SyncRuntimeSettings();
+  SyncBootTimeSettings();
   DCHECK(ArcSessionManager::Get());
   ArcSessionManager::Get()->AddObserver(this);
+
+  if (arc_bridge_service_->app()->has_instance())
+    SyncAppTimeSettings();
+  else
+    arc_bridge_service_->app()->AddObserver(this);
 }
 
 ArcSettingsServiceImpl::~ArcSettingsServiceImpl() {
   StopObservingSettingsChanges();
 
+  if (arc_bridge_service_->app()->has_instance())
+    arc_bridge_service_->app()->RemoveObserver(this);
+
   ArcSessionManager* arc_session_manager = ArcSessionManager::Get();
   if (arc_session_manager)
     arc_session_manager->RemoveObserver(this);
@@ -323,13 +339,12 @@
   SyncLocationServiceEnabled();
 }
 
-void ArcSettingsServiceImpl::SyncRuntimeSettings() const {
+void ArcSettingsServiceImpl::SyncBootTimeSettings() const {
   // Keep these lines ordered lexicographically.
   SyncAccessibilityLargeMouseCursorEnabled();
   SyncAccessibilityVirtualKeyboardEnabled();
   SyncFocusHighlightEnabled();
   SyncFontSize();
-  SyncLocale();
   SyncProxySettings();
   SyncReportingConsent();
   SyncSpokenFeedbackEnabled();
@@ -343,6 +358,10 @@
     SyncLocationServiceEnabled();
 }
 
+void ArcSettingsServiceImpl::SyncAppTimeSettings() const {
+  SyncLocale();
+}
+
 bool ArcSettingsServiceImpl::ShouldSyncBackupEnabled() const {
   // Always sync the managed setting. Also sync when the pref is unset, which
   // normally happens once after the pref changes from the managed state to
@@ -602,6 +621,12 @@
                           extras_json);
 }
 
+// InstanceHolder<mojom::AppInstance>::Observer:
+void ArcSettingsServiceImpl::OnInstanceReady() {
+  arc_bridge_service_->app()->RemoveObserver(this);
+  SyncAppTimeSettings();
+}
+
 // static
 ArcSettingsService* ArcSettingsService::GetForBrowserContext(
     content::BrowserContext* context) {
diff --git a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
index 90a0abb..dbd804c 100644
--- a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
+++ b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.cc
@@ -183,8 +183,9 @@
   binding_.Bind(mojo::MakeRequest(&host_proxy));
   wallpaper_instance->Init(std::move(host_proxy));
   ash::WallpaperController* wc = GetWallpaperController();
-  DCHECK(wc);
-  wc->AddObserver(this);
+  // TODO(mash): Support this functionality without ash::Shell access in Chrome.
+  if (wc)
+    wc->AddObserver(this);
 }
 
 void ArcWallpaperService::OnInstanceClosed() {
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc b/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
index 89df91a..d100064 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
@@ -3,13 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
 #include "base/threading/platform_thread.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
@@ -25,16 +22,6 @@
 
 namespace policy {
 
-class CustomFakeCryptohomeClient : public chromeos::FakeCryptohomeClient {
- public:
-  void TpmAttestationIsEnrolled(
-      const chromeos::BoolDBusMethodCallback& callback) override {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(callback, chromeos::DBUS_METHOD_CALL_FAILURE, false));
-  }
-};
-
 class AttestationDevicePolicyTest
     : public DevicePolicyCrosBrowserTest,
       public chromeos::DeviceSettingsService::Observer {
@@ -89,7 +76,7 @@
  private:
   bool operation_complete_;
   PlatformVerificationFlow::Result result_;
-  CustomFakeCryptohomeClient fake_cryptohome_client_;
+  chromeos::FakeCryptohomeClient fake_cryptohome_client_;
 
   void WaitForAsyncOperation() {
     while (!operation_complete_) {
@@ -121,4 +108,4 @@
             SyncContentProtectionAttestation());
 }
 
-} // namespace policy
+}  // namespace policy
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
index 9e888a69..ee23961 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
@@ -6,13 +6,10 @@
 
 #include <algorithm>
 #include <string>
+#include <vector>
 
-#include "base/bind.h"
-#include "base/location.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/attestation/fake_certificate.h"
 #include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
@@ -96,43 +93,6 @@
   DISALLOW_COPY_AND_ASSIGN(FakeDelegate);
 };
 
-class CustomFakeCryptohomeClient : public FakeCryptohomeClient {
- public:
-  CustomFakeCryptohomeClient() : call_status_(DBUS_METHOD_CALL_SUCCESS),
-                                 attestation_enrolled_(true),
-                                 attestation_prepared_(true) {}
-  void TpmAttestationIsEnrolled(
-      const BoolDBusMethodCallback& callback) override {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(callback, call_status_, attestation_enrolled_));
-  }
-
-  void TpmAttestationIsPrepared(
-      const BoolDBusMethodCallback& callback) override {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(callback, call_status_, attestation_prepared_));
-  }
-
-  void set_call_status(DBusMethodCallStatus call_status) {
-    call_status_ = call_status;
-  }
-
-  void set_attestation_enrolled(bool attestation_enrolled) {
-    attestation_enrolled_ = attestation_enrolled;
-  }
-
-  void set_attestation_prepared(bool attestation_prepared) {
-    attestation_prepared_ = attestation_prepared;
-  }
-
- private:
-  DBusMethodCallStatus call_status_;
-  bool attestation_enrolled_;
-  bool attestation_prepared_;
-};
-
 }  // namespace
 
 class PlatformVerificationFlowTest : public ::testing::Test {
@@ -222,7 +182,7 @@
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
   StrictMock<MockAttestationFlow> mock_attestation_flow_;
   cryptohome::MockAsyncMethodCaller mock_async_caller_;
-  CustomFakeCryptohomeClient fake_cryptohome_client_;
+  chromeos::FakeCryptohomeClient fake_cryptohome_client_;
   FakeDelegate fake_delegate_;
   ScopedCrosSettingsTestHelper settings_helper_;
   scoped_refptr<PlatformVerificationFlow> verifier_;
@@ -284,7 +244,7 @@
 }
 
 TEST_F(PlatformVerificationFlowTest, DBusFailure) {
-  fake_cryptohome_client_.set_call_status(DBUS_METHOD_CALL_FAILURE);
+  fake_cryptohome_client_.SetServiceIsAvailable(false);
   verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_);
@@ -395,8 +355,8 @@
 }
 
 TEST_F(PlatformVerificationFlowTest, AttestationNotPrepared) {
-  fake_cryptohome_client_.set_attestation_enrolled(false);
-  fake_cryptohome_client_.set_attestation_prepared(false);
+  fake_cryptohome_client_.set_tpm_attestation_is_enrolled(false);
+  fake_cryptohome_client_.set_tpm_attestation_is_prepared(false);
   verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_);
diff --git a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
index b553932e..290439b5 100644
--- a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
@@ -120,19 +120,19 @@
 }
 
 // Disabled. http://crbug.com/758697
-IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, DISABLED_TypingTest) {
+IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, TypingTest) {
   RunTest(base::FilePath(FILE_PATH_LITERAL("typing_test.js")),
           VirtualKeyboardBrowserTestConfig());
 }
 
 // Disabled. http://crbug.com/758697
-IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, DISABLED_LayoutTest) {
+IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, LayoutTest) {
   RunTest(base::FilePath(FILE_PATH_LITERAL("layout_test.js")),
           VirtualKeyboardBrowserTestConfig());
 }
 
 // Disabled. http://crbug.com/758697
-IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, DISABLED_ModifierTest) {
+IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, ModifierTest) {
   RunTest(base::FilePath(FILE_PATH_LITERAL("modifier_test.js")),
           VirtualKeyboardBrowserTestConfig());
 }
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
index f86f60a..7c68282 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
@@ -173,9 +173,7 @@
   void TearDown() override;
 
  protected:
-  void SetUpMultiUserWindowManager(
-      const AccountId& active_account_id,
-      chrome::MultiUserWindowManager::MultiProfileMode mode);
+  void SetUpMultiUserWindowManager(const AccountId& active_account_id);
 
   void SwitchActiveUser(const AccountId& active_account_id);
 
@@ -203,13 +201,12 @@
 }
 
 void WallpaperPrivateApiMultiUserUnittest::SetUpMultiUserWindowManager(
-    const AccountId& active_account_id,
-    chrome::MultiUserWindowManager::MultiProfileMode mode) {
+    const AccountId& active_account_id) {
   multi_user_window_manager_ =
       new chrome::MultiUserWindowManagerChromeOS(active_account_id);
   multi_user_window_manager_->Init();
   chrome::MultiUserWindowManager::SetInstanceForTest(
-      multi_user_window_manager_, mode);
+      multi_user_window_manager_);
   // We do not want animations while the test is going on.
   multi_user_window_manager_->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED);
@@ -227,9 +224,7 @@
 // then switch to a different profile and open another wallpaper picker
 // without closing the first one.
 TEST_F(WallpaperPrivateApiMultiUserUnittest, HideAndRestoreWindowsTwoUsers) {
-  SetUpMultiUserWindowManager(
-      test_account_id1_,
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
+  SetUpMultiUserWindowManager(test_account_id1_);
 
   std::unique_ptr<aura::Window> window4(CreateTestWindowInShellWithId(4));
   std::unique_ptr<aura::Window> window3(CreateTestWindowInShellWithId(3));
@@ -320,9 +315,7 @@
 // In multi profile mode, user may teleport windows. Teleported window should
 // also be minimized when open wallpaper picker.
 TEST_F(WallpaperPrivateApiMultiUserUnittest, HideTeleportedWindow) {
-  SetUpMultiUserWindowManager(
-      AccountId::FromUserEmail(kTestAccount1),
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_MIXED);
+  SetUpMultiUserWindowManager(AccountId::FromUserEmail(kTestAccount1));
 
   std::unique_ptr<aura::Window> window3(CreateTestWindowInShellWithId(3));
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2));
diff --git a/chrome/browser/chromeos/external_protocol_dialog.cc b/chrome/browser/chromeos/external_protocol_dialog.cc
index e0c7f6d..fa2f2dd 100644
--- a/chrome/browser/chromeos/external_protocol_dialog.cc
+++ b/chrome/browser/chromeos/external_protocol_dialog.cc
@@ -72,14 +72,6 @@
   delete this;
 }
 
-bool ExternalProtocolDialog::Accept() {
-  ExternalProtocolHandler::RecordCheckboxStateMetrics(
-      message_box_view_->IsCheckBoxSelected());
-
-  // Returning true closes the dialog.
-  return true;
-}
-
 views::View* ExternalProtocolDialog::GetContentsView() {
   return message_box_view_;
 }
diff --git a/chrome/browser/chromeos/external_protocol_dialog.h b/chrome/browser/chromeos/external_protocol_dialog.h
index 830b9e7c..32ab3f7d 100644
--- a/chrome/browser/chromeos/external_protocol_dialog.h
+++ b/chrome/browser/chromeos/external_protocol_dialog.h
@@ -37,7 +37,6 @@
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   base::string16 GetWindowTitle() const override;
   void DeleteDelegate() override;
-  bool Accept() override;
   views::View* GetContentsView() override;
 
   // views::WidgetDelegate Methods:
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.cc b/chrome/browser/chromeos/hats/hats_notification_controller.cc
index f5eab12..0f40a3d 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller.cc
+++ b/chrome/browser/chromeos/hats/hats_notification_controller.cc
@@ -30,6 +30,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_style.h"
 #include "ui/message_center/notification_types.h"
 #include "ui/strings/grit/ui_strings.h"
 
@@ -274,7 +275,7 @@
   optional.buttons.push_back(message_center::ButtonInfo(
       l10n_util::GetStringUTF16(IDS_ASH_HATS_NOTIFICATION_TAKE_SURVEY_BUTTON)));
 
-  return new Notification(
+  Notification* notification = new Notification(
       message_center::NOTIFICATION_TYPE_SIMPLE,
       l10n_util::GetStringUTF16(IDS_ASH_HATS_NOTIFICATION_TITLE),
       l10n_util::GetStringUTF16(IDS_ASH_HATS_NOTIFICATION_BODY),
@@ -283,6 +284,9 @@
                                  ash::system_notifier::kNotifierHats),
       l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_NOTIFIER_HATS_NAME),
       GURL(kNotificationOriginUrl), kNotificationId, optional, this);
+  notification->set_accent_color(
+      message_center::kSystemNotificationColorNormal);
+  return notification;
 }
 
 void HatsNotificationController::UpdateLastInteractionTime() {
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
index 5b38541..b09f9eb9 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "ash/public/interfaces/constants.mojom.h"
+#include "ash/wm/window_animations.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -488,8 +489,14 @@
     if (focus_cycler_delegate_)
       focus_cycler_delegate_->UnregisterLockScreenAppFocusHandler();
 
-    if (close_window && note_app_window_->GetBaseWindow())
+    if (close_window && note_app_window_->GetBaseWindow()) {
+      // Whenever we close the window we want to immediately hide it without
+      // animating, as the underlying UI implements a special animation. If we
+      // also animate the window the animations will conflict.
+      ::wm::SetWindowVisibilityAnimationTransition(
+          note_app_window_->GetNativeWindow(), ::wm::ANIMATE_NONE);
       note_app_window_->GetBaseWindow()->Close();
+    }
     note_app_window_ = nullptr;
   }
 
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 41f04af..27e34e6 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -1063,15 +1063,19 @@
     case apu::EcryptfsMigrationAction::kMigrate:
       user_manager::known_user::SetUserHomeMinimalMigrationAttempted(
           user_context.GetAccountId(), false);
-      ShowEncryptionMigrationScreen(user_context,
-                                    EncryptionMigrationMode::START_MIGRATION);
+      user_manager::UserManager::Get()->GetLocalState()->CommitPendingWrite(
+          base::BindOnce(&ExistingUserController::ShowEncryptionMigrationScreen,
+                         weak_factory_.GetWeakPtr(), user_context,
+                         EncryptionMigrationMode::START_MIGRATION));
       break;
 
     case apu::EcryptfsMigrationAction::kAskUser:
       user_manager::known_user::SetUserHomeMinimalMigrationAttempted(
           user_context.GetAccountId(), false);
-      ShowEncryptionMigrationScreen(user_context,
-                                    EncryptionMigrationMode::ASK_USER);
+      user_manager::UserManager::Get()->GetLocalState()->CommitPendingWrite(
+          base::BindOnce(&ExistingUserController::ShowEncryptionMigrationScreen,
+                         weak_factory_.GetWeakPtr(), user_context,
+                         EncryptionMigrationMode::ASK_USER));
       break;
 
     case apu::EcryptfsMigrationAction::kWipe:
@@ -1089,8 +1093,10 @@
           user_context.GetAccountId());
       user_manager::known_user::SetUserHomeMinimalMigrationAttempted(
           user_context.GetAccountId(), true);
-      ShowEncryptionMigrationScreen(
-          user_context, EncryptionMigrationMode::START_MINIMAL_MIGRATION);
+      user_manager::UserManager::Get()->GetLocalState()->CommitPendingWrite(
+          base::BindOnce(&ExistingUserController::ShowEncryptionMigrationScreen,
+                         weak_factory_.GetWeakPtr(), user_context,
+                         EncryptionMigrationMode::START_MINIMAL_MIGRATION));
       break;
 
     case apu::EcryptfsMigrationAction::kAskForEcryptfsArcUsers:
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.cc b/chrome/browser/chromeos/login/screens/user_image_screen.cc
index 87f8ee2..5095f9e 100644
--- a/chrome/browser/chromeos/login/screens/user_image_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_image_screen.cc
@@ -51,6 +51,7 @@
 constexpr const char kContextKeyIsCameraPresent[] = "isCameraPresent";
 constexpr const char kContextKeyProfilePictureDataURL[] =
     "profilePictureDataURL";
+constexpr const char kContextKeySelectedImageIndex[] = "selectedImageIndex";
 constexpr const char kContextKeySelectedImageURL[] = "selectedImageURL";
 
 // Time histogram suffix for profile image download.
@@ -140,8 +141,7 @@
       uma_index = default_user_image::kHistogramImageFromProfile;
       break;
     default:
-      DCHECK(selected_image_ >= 0 &&
-             selected_image_ < default_user_image::kDefaultImagesCount);
+      DCHECK(default_user_image::IsValidIndex(selected_image_));
       image_manager->SaveUserDefaultImageIndex(selected_image_);
       uma_index =
           default_user_image::GetDefaultImageHistogramValue(selected_image_);
@@ -216,6 +216,7 @@
   view_->Show();
 
   selected_image_ = GetUser()->image_index();
+  GetContextEditor().SetInteger(kContextKeySelectedImageIndex, selected_image_);
   GetContextEditor().SetString(
       kContextKeySelectedImageURL,
       default_user_image::GetDefaultImageUrl(selected_image_));
@@ -250,6 +251,8 @@
 }
 
 void UserImageScreen::OnUserImageChanged(const user_manager::User& user) {
+  GetContextEditor().SetInteger(kContextKeySelectedImageIndex,
+                                GetUser()->image_index());
   GetContextEditor().SetString(
       kContextKeySelectedImageURL,
       default_user_image::GetDefaultImageUrl(GetUser()->image_index()));
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
index 567b68cb..34a8c8b6 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
@@ -491,8 +491,7 @@
       NOTREACHED() << "Supervised users have no profile pictures";
       break;
     default:
-      DCHECK(selected_image_ >= 0 &&
-             selected_image_ < default_user_image::kDefaultImagesCount);
+      DCHECK(default_user_image::IsValidIndex(selected_image_));
       image_manager->SaveUserDefaultImageIndex(selected_image_);
       break;
   }
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
index bf65020..67848ee5 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
@@ -324,8 +324,7 @@
   image_url_ = image_url;
   image_path_ = image_path;
 
-  if (image_index_ >= 0 &&
-      image_index_ < default_user_image::kDefaultImagesCount) {
+  if (default_user_image::IsValidIndex(image_index_)) {
     // Load one of the default images. This happens synchronously.
     std::unique_ptr<user_manager::UserImage> user_image(
         new user_manager::UserImage(
@@ -355,8 +354,7 @@
   DCHECK(!run_);
   run_ = true;
 
-  DCHECK_LE(0, default_image_index);
-  DCHECK_GT(default_user_image::kDefaultImagesCount, default_image_index);
+  DCHECK(default_user_image::IsValidIndex(default_image_index));
 
   image_index_ = default_image_index;
   std::unique_ptr<user_manager::UserImage> user_image(
@@ -599,8 +597,7 @@
 
   int image_index = user_manager::User::USER_IMAGE_INVALID;
   image_properties->GetInteger(kImageIndexNodeName, &image_index);
-  if (image_index >= 0 &&
-      image_index < default_user_image::kDefaultImagesCount) {
+  if (default_user_image::IsValidIndex(image_index)) {
     user->SetImage(base::MakeUnique<user_manager::UserImage>(
                        default_user_image::GetDefaultImage(image_index)),
                    image_index);
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc b/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
index 9ff0a70..8a84637 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.cc
@@ -31,7 +31,7 @@
 const char kImageIndex[] = "image_index";
 
 bool IsIndexSupported(int index) {
-  return default_user_image::IsInCurrentImageSet(index) ||
+  return default_user_image::IsValidIndex(index) ||
          (index == user_manager::User::USER_IMAGE_PROFILE);
 }
 
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 8f412c0..1b732dc2 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -1382,8 +1382,7 @@
 }
 
 bool ChromeUserManagerImpl::IsValidDefaultUserImageId(int image_index) const {
-  return image_index >= 0 &&
-         image_index < chromeos::default_user_image::kDefaultImagesCount;
+  return chromeos::default_user_image::IsValidIndex(image_index);
 }
 
 std::unique_ptr<user_manager::User>
diff --git a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc
index 96c0000..e2c4c9b 100644
--- a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc
+++ b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.cc
@@ -105,6 +105,11 @@
 
 const int kFirstDefaultImageIndex = 34;
 
+// Limit random default image index to prevent undesirable UI behavior when
+// selecting an image with a high index. E.g. automatic scrolling of picture
+// list that is used to present default images.
+const int kLastRandomDefaultImageIndex = 47;
+
 // The order and the values of these constants are important for histograms
 // of different Chrome OS versions to be merged smoothly.
 const int kHistogramImageFromCamera = 19;
@@ -322,9 +327,13 @@
 }
 
 int GetRandomDefaultImageIndex() {
-  int first, last;
-  GetFirstLastIndex(&first, &last);
-  return base::RandInt(first, last);
+  int first;
+  GetFirstLastIndex(&first, nullptr);
+  return base::RandInt(first, kLastRandomDefaultImageIndex);
+}
+
+bool IsValidIndex(int index) {
+  return index >= 0 && index < kDefaultImagesCount;
 }
 
 bool IsInCurrentImageSet(int index) {
diff --git a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h
index 2d4e936..41f7e378 100644
--- a/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h
+++ b/chrome/browser/chromeos/login/users/default_user_image/default_user_images.h
@@ -69,6 +69,9 @@
 // Returns a random default image index.
 CHROMEOS_EXPORT int GetRandomDefaultImageIndex();
 
+// Returns true if |index| is a valid default image index.
+CHROMEOS_EXPORT bool IsValidIndex(int index);
+
 // Returns true if |index| is a in the current set of default images.
 CHROMEOS_EXPORT bool IsInCurrentImageSet(int index);
 
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
index 4853dd11..7f9b57c 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.cc
@@ -352,10 +352,10 @@
   const base::Value* value = policies.GetValue(policy_name());
   int value_in_range;
   if (value && EnsureInRange(value, &value_in_range, NULL)) {
+    // The "type" is only used to enable or disable the feature as a whole.
+    // http://crbug.com/170850
     prefs->SetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled,
                       value_in_range != ash::MAGNIFIER_DISABLED);
-    prefs->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
-                      value_in_range);
   }
 }
 
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
index 1782188..dc21bb6 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
@@ -60,8 +60,6 @@
   handler_.ApplyPolicySettings(policy_, &prefs_);
   EXPECT_FALSE(
       prefs_.GetValue(ash::prefs::kAccessibilityScreenMagnifierEnabled, NULL));
-  EXPECT_FALSE(
-      prefs_.GetValue(ash::prefs::kAccessibilityScreenMagnifierType, NULL));
 }
 
 TEST_F(ScreenMagnifierPolicyHandlerTest, Disabled) {
@@ -75,12 +73,6 @@
                               &enabled));
   ASSERT_TRUE(enabled);
   EXPECT_TRUE(base::Value(false).Equals(enabled));
-
-  const base::Value* type = NULL;
-  EXPECT_TRUE(
-      prefs_.GetValue(ash::prefs::kAccessibilityScreenMagnifierType, &type));
-  ASSERT_TRUE(type);
-  EXPECT_TRUE(base::Value(0).Equals(type));
 }
 
 TEST_F(ScreenMagnifierPolicyHandlerTest, Enabled) {
@@ -94,12 +86,6 @@
                               &enabled));
   ASSERT_TRUE(enabled);
   EXPECT_TRUE(base::Value(true).Equals(enabled));
-
-  const base::Value* type = NULL;
-  EXPECT_TRUE(
-      prefs_.GetValue(ash::prefs::kAccessibilityScreenMagnifierType, &type));
-  ASSERT_TRUE(type);
-  EXPECT_TRUE(base::Value(1).Equals(type));
 }
 
 TEST(ExternalDataPolicyHandlerTest, Empty) {
diff --git a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
index ba14f38..e3ee8ddc 100644
--- a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
@@ -309,24 +309,22 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyLoginScreenBrowsertest,
-                       DeviceLoginScreenDefaultScreenMagnifierType) {
-  // Verifies that the default screen magnifier type enabled on the login screen
-  // can be controlled through device policy.
+                       DeviceLoginScreenDefaultScreenMagnifierEnabled) {
+  // Verifies that the screen magnifier enabled on the login screen can be
+  // controlled through device policy.
 
-  // Set the screen magnifier type through device policy and wait for the change
+  // Set the screen magnifier through device policy and wait for the change
   // to take effect.
   em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
   proto.mutable_accessibility_settings()->
       set_login_screen_default_screen_magnifier_type(kFullScreenMagnifier);
   RefreshDevicePolicyAndWaitForPrefChange(
-      ash::prefs::kAccessibilityScreenMagnifierType);
+      ash::prefs::kAccessibilityScreenMagnifierEnabled);
 
-  // Verify that the prefs which control the screen magnifier type have changed
+  // Verify that the prefs which control the screen magnifier have changed
   // to the policy-supplied default.
   VerifyPrefFollowsRecommendation(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, base::Value(true));
-  VerifyPrefFollowsRecommendation(ash::prefs::kAccessibilityScreenMagnifierType,
-                                  base::Value(ash::MAGNIFIER_FULL));
 
   // Verify that the full-screen magnifier is enabled.
   chromeos::MagnificationManager* magnification_manager =
@@ -411,22 +409,21 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LoginScreenDefaultPolicyInSessionBrowsertest,
-                       DeviceLoginScreenDefaultScreenMagnifierType) {
-  // Verifies that changing the default screen magnifier type enabled on the
-  // login screen through policy does not affect its state in a session.
+                       DeviceLoginScreenDefaultScreenMagnifierEnabled) {
+  // Verifies that changing the screen magnifier enabled on the login screen
+  // through policy does not affect its state in a session.
 
-  // Set the screen magnifier type through device policy and wait for the change
+  // Set the screen magnifier through device policy and wait for the change
   // to take effect.
   em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
   proto.mutable_accessibility_settings()->
       set_login_screen_default_screen_magnifier_type(kFullScreenMagnifier);
   RefreshDevicePolicyAndWaitForPrefChange(
-      ash::prefs::kAccessibilityScreenMagnifierType);
+      ash::prefs::kAccessibilityScreenMagnifierEnabled);
 
   // Verify that the prefs which control the screen magnifier in the session are
   // unchanged.
   VerifyPrefFollowsDefault(ash::prefs::kAccessibilityScreenMagnifierEnabled);
-  VerifyPrefFollowsDefault(ash::prefs::kAccessibilityScreenMagnifierType);
 
   // Verify that the screen magnifier is disabled.
   chromeos::MagnificationManager* magnification_manager =
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer.cc b/chrome/browser/chromeos/policy/recommendation_restorer.cc
index c9837b9..0e9b5da 100644
--- a/chrome/browser/chromeos/policy/recommendation_restorer.cc
+++ b/chrome/browser/chromeos/policy/recommendation_restorer.cc
@@ -45,9 +45,6 @@
   pref_change_registrar_.Add(ash::prefs::kAccessibilityScreenMagnifierEnabled,
                              base::Bind(&RecommendationRestorer::Restore,
                                         base::Unretained(this), true));
-  pref_change_registrar_.Add(ash::prefs::kAccessibilityScreenMagnifierType,
-                             base::Bind(&RecommendationRestorer::Restore,
-                                        base::Unretained(this), true));
   pref_change_registrar_.Add(ash::prefs::kAccessibilityVirtualKeyboardEnabled,
                              base::Bind(&RecommendationRestorer::Restore,
                                         base::Unretained(this), true));
@@ -119,7 +116,6 @@
   Restore(false, ash::prefs::kAccessibilitySpokenFeedbackEnabled);
   Restore(false, ash::prefs::kAccessibilityHighContrastEnabled);
   Restore(false, ash::prefs::kAccessibilityScreenMagnifierEnabled);
-  Restore(false, ash::prefs::kAccessibilityScreenMagnifierType);
   Restore(false, ash::prefs::kAccessibilityVirtualKeyboardEnabled);
 }
 
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer_unittest.cc b/chrome/browser/chromeos/policy/recommendation_restorer_unittest.cc
index e784442..7dcbe5e6 100644
--- a/chrome/browser/chromeos/policy/recommendation_restorer_unittest.cc
+++ b/chrome/browser/chromeos/policy/recommendation_restorer_unittest.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "ash/accessibility_types.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
@@ -127,8 +126,6 @@
                                  false);
   recommended_prefs_->SetBoolean(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, false);
-  recommended_prefs_->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
-                                 0);
   recommended_prefs_->SetBoolean(
       ash::prefs::kAccessibilityVirtualKeyboardEnabled, false);
 }
@@ -138,8 +135,6 @@
   prefs_->SetBoolean(ash::prefs::kAccessibilitySpokenFeedbackEnabled, true);
   prefs_->SetBoolean(ash::prefs::kAccessibilityHighContrastEnabled, true);
   prefs_->SetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled, true);
-  prefs_->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
-                     ash::MAGNIFIER_FULL);
   prefs_->SetBoolean(ash::prefs::kAccessibilityVirtualKeyboardEnabled, true);
 }
 
@@ -195,8 +190,6 @@
                         base::Value(true));
   VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierEnabled,
                         base::Value(true));
-  VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierType,
-                        base::Value(ash::MAGNIFIER_FULL));
   VerifyPrefFollowsUser(ash::prefs::kAccessibilityVirtualKeyboardEnabled,
                         base::Value(true));
 }
@@ -223,8 +216,6 @@
                                   base::Value(false));
   VerifyPrefFollowsRecommendation(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, base::Value(false));
-  VerifyPrefFollowsRecommendation(ash::prefs::kAccessibilityScreenMagnifierType,
-                                  base::Value(0));
   VerifyPrefFollowsRecommendation(
       ash::prefs::kAccessibilityVirtualKeyboardEnabled, base::Value(false));
 }
@@ -329,18 +320,12 @@
   VerifyTimerIsStopped();
   recommended_prefs_->SetBoolean(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, false);
-  recommended_prefs_->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
-                                 0);
   VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierEnabled,
                         base::Value(true));
-  VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierType,
-                        base::Value(ash::MAGNIFIER_FULL));
   VerifyTimerIsRunning();
   runner_->RunUntilIdle();
   VerifyPrefFollowsRecommendation(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, base::Value(false));
-  VerifyPrefFollowsRecommendation(ash::prefs::kAccessibilityScreenMagnifierType,
-                                  base::Value(0));
   VerifyTimerIsStopped();
   recommended_prefs_->SetBoolean(
       ash::prefs::kAccessibilityVirtualKeyboardEnabled, false);
@@ -388,17 +373,11 @@
 
   VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierEnabled,
                         base::Value(true));
-  VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierType,
-                        base::Value(ash::MAGNIFIER_FULL));
   recommended_prefs_->SetBoolean(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, false);
-  recommended_prefs_->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
-                                 0);
   VerifyTimerIsStopped();
   VerifyPrefFollowsRecommendation(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, base::Value(false));
-  VerifyPrefFollowsRecommendation(ash::prefs::kAccessibilityScreenMagnifierType,
-                                  base::Value(0));
 
   VerifyPrefFollowsUser(ash::prefs::kAccessibilityVirtualKeyboardEnabled,
                         base::Value(true));
@@ -437,12 +416,8 @@
   VerifyTimerIsStopped();
 
   prefs_->SetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled, true);
-  prefs_->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
-                     ash::MAGNIFIER_FULL);
   VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierEnabled,
                         base::Value(true));
-  VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierType,
-                        base::Value(ash::MAGNIFIER_FULL));
   VerifyTimerIsStopped();
 
   prefs_->SetBoolean(ash::prefs::kAccessibilityVirtualKeyboardEnabled, true);
@@ -489,18 +464,12 @@
 
   VerifyTimerIsStopped();
   prefs_->SetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled, true);
-  prefs_->SetInteger(ash::prefs::kAccessibilityScreenMagnifierType,
-                     ash::MAGNIFIER_FULL);
   VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierEnabled,
                         base::Value(true));
-  VerifyPrefFollowsUser(ash::prefs::kAccessibilityScreenMagnifierType,
-                        base::Value(ash::MAGNIFIER_FULL));
   VerifyTimerIsRunning();
   runner_->RunUntilIdle();
   VerifyPrefFollowsRecommendation(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, base::Value(false));
-  VerifyPrefFollowsRecommendation(ash::prefs::kAccessibilityScreenMagnifierType,
-                                  base::Value(0));
 
   VerifyTimerIsStopped();
   prefs_->SetBoolean(ash::prefs::kAccessibilityVirtualKeyboardEnabled, true);
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 78cd91a6..9471739 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -6,7 +6,6 @@
 
 #include <vector>
 
-#include "ash/accessibility_types.h"
 #include "ash/ash_constants.h"
 #include "ash/autoclick/autoclick_controller.h"
 #include "ash/public/cpp/ash_pref_names.h"
@@ -202,9 +201,6 @@
   registry->RegisterBooleanPref(
       ash::prefs::kAccessibilityScreenMagnifierEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
-  registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilityScreenMagnifierType, ash::MAGNIFIER_FULL,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterDoublePref(ash::prefs::kAccessibilityScreenMagnifierScale,
                                std::numeric_limits<double>::min());
   registry->RegisterBooleanPref(
diff --git a/chrome/browser/chromeos/printing/cups_print_job_notification.cc b/chrome/browser/chromeos/printing/cups_print_job_notification.cc
index 6216b8da..ceabbbfd 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_notification.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_notification.cc
@@ -22,6 +22,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/chromeos/resources/grit/ui_chromeos_resources.h"
 #include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_style.h"
 #include "ui/message_center/notification_types.h"
 
 namespace chromeos {
@@ -71,17 +72,19 @@
       profile_(profile) {
   // Create a notification for the print job. The title, body, icon and buttons
   // of the notification will be updated in UpdateNotification().
-  notification_.reset(new Notification(
+  notification_ = base::MakeUnique<Notification>(
       message_center::NOTIFICATION_TYPE_SIMPLE,
       base::string16(),  // title
       base::string16(),  // body
       gfx::Image(),      // icon
       message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
                                  kCupsPrintJobNotificationId),
-      base::string16(),  // display_source
+      l10n_util::GetStringUTF16(IDS_PRINT_JOB_NOTIFICATION_DISPLAY_SOURCE),
       GURL(kCupsPrintJobNotificationId),
       notification_id_,  // tag
-      message_center::RichNotificationData(), delegate_.get()));
+      message_center::RichNotificationData(), delegate_.get());
+  notification_->set_accent_color(
+      message_center::kSystemNotificationColorNormal);
   UpdateNotification();
 }
 
diff --git a/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc b/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc
new file mode 100644
index 0000000..b67a42b
--- /dev/null
+++ b/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc
@@ -0,0 +1,144 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/third_party_module_list_component_installer_win.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "chrome/browser/conflicts/module_database_win.h"
+#include "components/component_updater/component_updater_paths.h"
+#include "content/public/browser/browser_thread.h"
+
+using component_updater::ComponentUpdateService;
+
+namespace {
+
+// The relative path of the expected module list file inside of an installation
+// of this component.
+const wchar_t kRelativeModuleListPath[] = L"module_list_proto";
+
+}  // namespace
+
+namespace component_updater {
+
+// The SHA256 of the SubjectPublicKeyInfo used to sign the component.
+// The component id is: EHGIDPNDBLLACPJALKIIMKBADGJFNNMC
+const uint8_t kPublicKeySHA256[32] = {
+    0x47, 0x68, 0x3f, 0xd3, 0x1b, 0xb0, 0x2f, 0x90, 0xba, 0x88, 0xca,
+    0x10, 0x36, 0x95, 0xdd, 0xc2, 0x29, 0xd1, 0x4f, 0x38, 0xf2, 0x9d,
+    0x6c, 0x9c, 0x68, 0x6c, 0xa2, 0xa4, 0xa2, 0x8e, 0xa5, 0x5c};
+
+// The name of the component. This is used in the chrome://components page.
+const char kThirdPartyModuleListName[] = "Third Party Module List";
+
+ThirdPartyModuleListComponentInstallerTraits::
+    ThirdPartyModuleListComponentInstallerTraits(ModuleListManager* manager)
+    : manager_(manager) {}
+
+ThirdPartyModuleListComponentInstallerTraits::
+    ~ThirdPartyModuleListComponentInstallerTraits() {}
+
+bool ThirdPartyModuleListComponentInstallerTraits::
+    SupportsGroupPolicyEnabledComponentUpdates() const {
+  return false;
+}
+
+bool ThirdPartyModuleListComponentInstallerTraits::RequiresNetworkEncryption()
+    const {
+  // Public data is delivered via this component, no need for encryption.
+  return false;
+}
+
+update_client::CrxInstaller::Result
+ThirdPartyModuleListComponentInstallerTraits::OnCustomInstall(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) {
+  return update_client::CrxInstaller::Result(0);  // Nothing custom here.
+}
+
+// NOTE: This is always called on the main UI thread. It is called once every
+// startup to notify of an already installed component, and may be called
+// repeatedly after that every time a new component is ready.
+void ThirdPartyModuleListComponentInstallerTraits::ComponentReady(
+    const base::Version& version,
+    const base::FilePath& install_dir,
+    std::unique_ptr<base::DictionaryValue> manifest) {
+  // Forward the notification to the ModuleListManager on the current (UI)
+  // thread. The manager is responsible for the work of actually loading the
+  // module list, etc, on background threads.
+  manager_->LoadModuleList(version, GetModuleListPath(install_dir));
+}
+
+bool ThirdPartyModuleListComponentInstallerTraits::VerifyInstallation(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) const {
+  // This is called during startup and installation before ComponentReady().
+  // The component is considered valid if the expected file exists in the
+  // installation.
+  return base::PathExists(GetModuleListPath(install_dir));
+}
+
+base::FilePath
+ThirdPartyModuleListComponentInstallerTraits::GetRelativeInstallDir() const {
+  // The same path is used for installation and for the registry key to keep
+  // things consistent.
+  return base::FilePath(ModuleListManager::kModuleListRegistryKeyPath);
+}
+
+void ThirdPartyModuleListComponentInstallerTraits::GetHash(
+    std::vector<uint8_t>* hash) const {
+  hash->assign(std::begin(kPublicKeySHA256), std::end(kPublicKeySHA256));
+}
+
+std::string ThirdPartyModuleListComponentInstallerTraits::GetName() const {
+  return kThirdPartyModuleListName;
+}
+
+std::vector<std::string>
+ThirdPartyModuleListComponentInstallerTraits::GetMimeTypes() const {
+  return std::vector<std::string>();
+}
+
+update_client::InstallerAttributes
+ThirdPartyModuleListComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
+}
+
+// static
+base::FilePath ThirdPartyModuleListComponentInstallerTraits::GetModuleListPath(
+    const base::FilePath& install_dir) {
+  return install_dir.Append(kRelativeModuleListPath);
+}
+
+void RegisterThirdPartyModuleListComponent(ComponentUpdateService* cus) {
+  DVLOG(1) << "Registering Third Party Module List component.";
+
+  // Get a handle to the manager. This will only exist if the corresponding
+  // feature is enabled.
+  ModuleDatabase* database = ModuleDatabase::GetInstance();
+  if (!database)
+    return;
+  ModuleListManager* manager = &database->module_list_manager();
+
+  std::unique_ptr<ComponentInstallerTraits> traits(
+      new ThirdPartyModuleListComponentInstallerTraits(manager));
+
+  // |cus| will take ownership of |installer| during installer->Register(cus).
+  DefaultComponentInstaller* installer =
+      new DefaultComponentInstaller(std::move(traits));
+  installer->Register(cus, base::Closure());
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/third_party_module_list_component_installer_win.h b/chrome/browser/component_updater/third_party_module_list_component_installer_win.h
new file mode 100644
index 0000000..5001901
--- /dev/null
+++ b/chrome/browser/component_updater/third_party_module_list_component_installer_win.h
@@ -0,0 +1,77 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_THIRD_PARTY_MODULE_LIST_COMPONENT_INSTALLER_WIN_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_THIRD_PARTY_MODULE_LIST_COMPONENT_INSTALLER_WIN_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "components/component_updater/default_component_installer.h"
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+// Will receive notifications about a new module list being available.
+class ModuleListManager;
+
+namespace component_updater {
+
+class ComponentUpdateService;
+
+// Component for receiving Third Party Module Lists. The lists are in proto
+// format, corresponding to the proto definition in
+// chrome/browser/conflicts/proto/module_list.proto
+//
+// Notifications of a new version of the module list are sent to the
+// ModuleListManager.
+class ThirdPartyModuleListComponentInstallerTraits
+    : public ComponentInstallerTraits {
+ public:
+  // The |manager| will be notified each time a new module list is available,
+  // including once every startup when a component is already installed.
+  explicit ThirdPartyModuleListComponentInstallerTraits(
+      ModuleListManager* manager);
+  ~ThirdPartyModuleListComponentInstallerTraits() override;
+
+ private:
+  friend class ThirdPartyModuleListComponentInstallerTraitsTest;
+
+  // ComponentInstallerTraits implementation.
+  bool SupportsGroupPolicyEnabledComponentUpdates() const override;
+  bool RequiresNetworkEncryption() const override;
+  update_client::CrxInstaller::Result OnCustomInstall(
+      const base::DictionaryValue& manifest,
+      const base::FilePath& install_dir) override;
+  bool VerifyInstallation(const base::DictionaryValue& manifest,
+                          const base::FilePath& install_dir) const override;
+  void ComponentReady(const base::Version& version,
+                      const base::FilePath& install_dir,
+                      std::unique_ptr<base::DictionaryValue> manifest) override;
+  base::FilePath GetRelativeInstallDir() const override;
+  void GetHash(std::vector<uint8_t>* hash) const override;
+  std::string GetName() const override;
+  std::vector<std::string> GetMimeTypes() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
+
+  // Returns the path to the proto file for the given |install_dir|.
+  static base::FilePath GetModuleListPath(const base::FilePath& install_dir);
+
+  // The manager is not owned by this class, so the code creating it is
+  // expected to ensure the manager lives as long as this class does. Typically
+  // the manager provided will be a global singleton.
+  ModuleListManager* manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThirdPartyModuleListComponentInstallerTraits);
+};
+
+void RegisterThirdPartyModuleListComponent(ComponentUpdateService* cus);
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_THIRD_PARTY_MODULE_LIST_COMPONENT_INSTALLER_WIN_H_
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc
index 542d568..0ceb293a 100644
--- a/chrome/browser/conflicts/module_database_win.cc
+++ b/chrome/browser/conflicts/module_database_win.cc
@@ -31,13 +31,14 @@
 
 ModuleDatabase::ModuleDatabase(
     scoped_refptr<base::SequencedTaskRunner> task_runner)
-    : task_runner_(std::move(task_runner)),
+    : task_runner_(task_runner),
       shell_extensions_enumerated_(false),
       ime_enumerated_(false),
       // ModuleDatabase owns |module_inspector_|, so it is safe to use
       // base::Unretained().
       module_inspector_(base::Bind(&ModuleDatabase::OnModuleInspected,
                                    base::Unretained(this))),
+      module_list_manager_(std::move(task_runner)),
       third_party_metrics_(this),
       has_started_processing_(false),
       idle_timer_(
@@ -45,7 +46,9 @@
           kIdleTimeout,
           base::Bind(&ModuleDatabase::OnDelayExpired, base::Unretained(this)),
           false),
-      weak_ptr_factory_(this) {}
+      weak_ptr_factory_(this) {
+  // TODO(pmonette): Wire up the module list manager observer.
+}
 
 ModuleDatabase::~ModuleDatabase() {
   if (this == g_instance)
diff --git a/chrome/browser/conflicts/module_database_win.h b/chrome/browser/conflicts/module_database_win.h
index 90f2e6a..5c9ac811 100644
--- a/chrome/browser/conflicts/module_database_win.h
+++ b/chrome/browser/conflicts/module_database_win.h
@@ -16,6 +16,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/conflicts/module_info_win.h"
 #include "chrome/browser/conflicts/module_inspector_win.h"
+#include "chrome/browser/conflicts/module_list_manager_win.h"
 #include "chrome/browser/conflicts/third_party_metrics_recorder_win.h"
 #include "content/public/common/process_type.h"
 
@@ -106,6 +107,10 @@
   // ModuleDatabase becomes idle ASAP.
   void IncreaseInspectionPriority();
 
+  // Accessor for the module list manager. This is exposed so that the manager
+  // can be wired up to the ThirdPartyModuleListComponentInstaller.
+  ModuleListManager& module_list_manager() { return module_list_manager_; }
+
  private:
   friend class TestModuleDatabase;
   friend class ModuleDatabaseTest;
@@ -168,6 +173,9 @@
   // Inspects new modules on a blocking task runner.
   ModuleInspector module_inspector_;
 
+  // Keeps track of where the most recent module list is located on disk, and
+  // provides notifications when this changes.
+  ModuleListManager module_list_manager_;
   base::ObserverList<ModuleDatabaseObserver> observer_list_;
 
   ThirdPartyMetricsRecorder third_party_metrics_;
diff --git a/chrome/browser/conflicts/module_list_manager_win.cc b/chrome/browser/conflicts/module_list_manager_win.cc
new file mode 100644
index 0000000..1cdeebb
--- /dev/null
+++ b/chrome/browser/conflicts/module_list_manager_win.cc
@@ -0,0 +1,114 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/conflicts/module_list_manager_win.h"
+
+#include "base/files/file_path.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "chrome/install_static/install_util.h"
+
+const wchar_t ModuleListManager::kModuleListRegistryKeyPath[] =
+    L"ThirdPartyModuleList"
+#ifdef _WIN64
+    "64";
+#else
+    "32";
+#endif
+
+const wchar_t ModuleListManager::kModuleListPathKeyName[] = L"Path";
+
+const wchar_t ModuleListManager::kModuleListVersionKeyName[] = L"Version";
+
+ModuleListManager::Observer::Observer() = default;
+
+ModuleListManager::Observer::~Observer() = default;
+
+ModuleListManager::ModuleListManager(
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : registry_key_root_(GetRegistryPath()),
+      task_runner_(task_runner),
+      observer_(nullptr) {
+  // Read the cached path and version.
+  std::wstring path;
+  std::wstring version;
+  base::win::RegKey reg_key(GetRegistryHive(), registry_key_root_.c_str(),
+                            KEY_READ);
+  if (reg_key.Valid() &&
+      reg_key.ReadValue(kModuleListPathKeyName, &path) == ERROR_SUCCESS &&
+      reg_key.ReadValue(kModuleListVersionKeyName, &version)) {
+    base::Version parsed_version(base::WideToUTF8(version));
+    if (parsed_version.IsValid()) {
+      module_list_path_ = base::FilePath(path);
+      module_list_version_ = parsed_version;
+    }
+  }
+}
+
+ModuleListManager::~ModuleListManager() = default;
+
+base::FilePath ModuleListManager::module_list_path() {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  return module_list_path_;
+}
+
+base::Version ModuleListManager::module_list_version() {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  return module_list_version_;
+}
+
+void ModuleListManager::SetObserver(Observer* observer) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  observer_ = observer;
+}
+
+// static
+HKEY ModuleListManager::GetRegistryHive() {
+  return HKEY_CURRENT_USER;
+}
+
+// static
+std::wstring ModuleListManager::GetRegistryPath() {
+  std::wstring path = install_static::GetRegistryPath();
+  path.append(1, '\\');
+  path.append(kModuleListRegistryKeyPath);
+  return path;
+}
+
+void ModuleListManager::LoadModuleList(const base::Version& version,
+                                       const base::FilePath& path) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(version.IsValid());
+  DCHECK(!path.empty());
+
+  if (path == module_list_path_) {
+    // If the path hasn't changed the version should not have either.
+    DCHECK(version == module_list_version_);
+    return;
+  }
+
+  // If a new list is being provided and it's not more recent, then bail.
+  if (!module_list_path_.empty()) {
+    DCHECK(module_list_version_.IsValid());
+    if (module_list_version_ >= version)
+      return;
+  }
+
+  // Update the path and version.
+  module_list_path_ = path;
+  module_list_version_ = version;
+
+  // Cache the new path and version.
+  base::win::RegKey reg_key(GetRegistryHive(), registry_key_root_.c_str(),
+                            KEY_WRITE);
+  if (reg_key.Valid()) {
+    std::wstring version_wstr = base::UTF8ToWide(version.GetString());
+    reg_key.WriteValue(kModuleListPathKeyName, path.value().c_str());
+    reg_key.WriteValue(kModuleListVersionKeyName, version_wstr.c_str());
+  }
+
+  // Notify the observer if it exists.
+  if (observer_)
+    observer_->OnNewModuleList(version, path);
+}
diff --git a/chrome/browser/conflicts/module_list_manager_win.h b/chrome/browser/conflicts/module_list_manager_win.h
new file mode 100644
index 0000000..126ceb0
--- /dev/null
+++ b/chrome/browser/conflicts/module_list_manager_win.h
@@ -0,0 +1,116 @@
+// 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_CONFLICTS_MODULE_LIST_MANAGER_WIN_H_
+#define CHROME_BROWSER_CONFLICTS_MODULE_LIST_MANAGER_WIN_H_
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/sequenced_task_runner.h"
+#include "base/version.h"
+
+namespace component_updater {
+class ThirdPartyModuleListComponentInstallerTraits;
+}  // namespace component_updater
+
+// Declares a class that is responsible for knowing the location of the most
+// up-to-date module list (a whitelist of third party modules that are safe for
+// injection).
+//
+// Since the module list can change at runtime (a new component version can be
+// installed) this class provides an observer interface that can notify clients
+// of a new whitelist.
+//
+// This class binds to the sequence on which it is created, and expects
+// callbacks to arrive on that same sequence.
+class ModuleListManager {
+ public:
+  // The root of the module list registry information. This is relative to the
+  // root of the installation registry data, as returned by
+  // install_static::InstallDetails::GetClientStateKeyPath.
+  static const wchar_t kModuleListRegistryKeyPath[];
+
+  // The name of the key below registry_key_root_ that stores the path to the
+  // most recent module list, as a string.
+  static const wchar_t kModuleListPathKeyName[];
+
+  // The name of the key below registry_key_root_ that stores the version of the
+  // most recent module list, as a string.
+  static const wchar_t kModuleListVersionKeyName[];
+
+  // An observer of changes to the ModuleListManager. The observer will only
+  // be called if the module list installation location changes after the
+  // observer has been registered.
+  class Observer {
+   public:
+    Observer();
+    virtual ~Observer();
+
+    // This is invoked on the same sequence to which the ModuleListManager is
+    // bound.
+    virtual void OnNewModuleList(const base::Version& version,
+                                 const base::FilePath& path) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Observer);
+  };
+
+  // Creates a ModuleListManager bound to the provided |task_runner|. All calls
+  // to the manager are expected to be received on that task runner, and all
+  // outgoing callbacks will be on the same task runner.
+  explicit ModuleListManager(
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+
+  ~ModuleListManager();
+
+  // Returns the path to the current module list. This is empty if no module
+  // list is available.
+  base::FilePath module_list_path();
+
+  // Returns the version of the current module list. This is empty if no module
+  // list is available.
+  base::Version module_list_version();
+
+  // For adding and removing an observer. It is expected that there only be a
+  // single observer needed. The observer must outlive this class. Call
+  // SetObserver(nullptr) to clear the observer.
+  void SetObserver(Observer* observer);
+
+  // Generates the registry key where Path and Version information will be
+  // written. Exposed for testing.
+  static HKEY GetRegistryHive();
+  static std::wstring GetRegistryPath();
+
+ protected:
+  friend class component_updater::ThirdPartyModuleListComponentInstallerTraits;
+
+  // Called post-startup with information about the most recently available
+  // module list installation. Can potentially be called again much later when
+  // another (newer) version is installed.
+  void LoadModuleList(const base::Version& version, const base::FilePath& path);
+
+ private:
+  friend class ModuleListManagerTest;
+
+  // The hive and path to the registry key where the most recent module list
+  // path information is cached.
+  const std::wstring registry_key_root_;
+
+  // The task runner on which this class does its work.
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  // The path and version of the most recently installed module list. This is
+  // retrieved from the registry at creation of ModuleListManager, and
+  // potentially updated at runtime via calls to LoadModuleList.
+  base::FilePath module_list_path_;
+  base::Version module_list_version_;
+
+  // The observer of this object.
+  Observer* observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(ModuleListManager);
+};
+
+#endif  // CHROME_BROWSER_CONFLICTS_MODULE_LIST_MANAGER_WIN_H_
diff --git a/chrome/browser/conflicts/module_list_manager_win_unittest.cc b/chrome/browser/conflicts/module_list_manager_win_unittest.cc
new file mode 100644
index 0000000..d758be9
--- /dev/null
+++ b/chrome/browser/conflicts/module_list_manager_win_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/conflicts/module_list_manager_win.h"
+
+#include "base/test/scoped_task_environment.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/win/registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MockObserver : public ModuleListManager::Observer {
+ public:
+  MockObserver() : called_(false) {}
+  ~MockObserver() override = default;
+
+  // ModuleListManager::Observer implementation:
+  void OnNewModuleList(const base::Version& version,
+                       const base::FilePath& path) override {
+    called_ = true;
+    version_ = version;
+    path_ = path;
+  }
+
+  bool called() const { return called_; }
+  base::Version version() const { return version_; }
+  base::FilePath path() const { return path_; }
+
+ private:
+  bool called_;
+  base::Version version_;
+  base::FilePath path_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockObserver);
+};
+
+}  // namespace
+
+// This is not in the anonymous namespace as it is friends with the class being
+// tested.
+class ModuleListManagerTest : public ::testing::Test {
+ public:
+  ModuleListManagerTest() = default;
+  ~ModuleListManagerTest() override = default;
+
+  void SetUp() override {
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+  }
+
+  void NotifyNewModuleList(ModuleListManager* mlm) {
+    // Add an observer.
+    MockObserver observer;
+    mlm->SetObserver(&observer);
+    ASSERT_FALSE(observer.called());
+    ASSERT_FALSE(observer.version().IsValid());
+    ASSERT_TRUE(observer.path().empty());
+
+    // Notify the manager of a new module list and expect it to be updated.
+    // Also expect the observer to be called.
+    base::Version version("1.2.3.4");
+    base::FilePath path(L"C:\\foo\\bar.txt");
+    mlm->LoadModuleList(version, path);
+    EXPECT_EQ(version, mlm->module_list_version());
+    EXPECT_EQ(path, mlm->module_list_path());
+    EXPECT_TRUE(observer.called());
+    EXPECT_EQ(version, observer.version());
+    EXPECT_EQ(path, observer.path());
+    mlm->SetObserver(nullptr);
+
+    // Expect the registry to be updated too.
+    base::win::RegKey reg_key(ModuleListManager::GetRegistryHive(),
+                              ModuleListManager::GetRegistryPath().c_str(),
+                              KEY_READ);
+    ASSERT_TRUE(reg_key.Valid());
+    std::wstring s;
+    ASSERT_EQ(ERROR_SUCCESS,
+              reg_key.ReadValue(ModuleListManager::kModuleListPathKeyName, &s));
+    EXPECT_EQ(path.value(), s);
+    ASSERT_EQ(
+        ERROR_SUCCESS,
+        reg_key.ReadValue(ModuleListManager::kModuleListVersionKeyName, &s));
+    EXPECT_EQ(L"1.2.3.4", s);
+  }
+
+ private:
+  base::test::ScopedTaskEnvironment task_environment_;
+  registry_util::RegistryOverrideManager registry_override_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(ModuleListManagerTest);
+};
+
+TEST_F(ModuleListManagerTest, FindsNoPathInRegistry) {
+  ModuleListManager mlm(base::SequencedTaskRunnerHandle::Get());
+  EXPECT_TRUE(mlm.module_list_path().empty());
+  EXPECT_FALSE(mlm.module_list_version().IsValid());
+
+  ASSERT_NO_FATAL_FAILURE(NotifyNewModuleList(&mlm));
+}
+
+TEST_F(ModuleListManagerTest, FindsInvalidVersionInRegistry) {
+  base::win::RegKey reg_key(ModuleListManager::GetRegistryHive(),
+                            ModuleListManager::GetRegistryPath().c_str(),
+                            KEY_WRITE);
+  ASSERT_TRUE(reg_key.Valid());
+  ASSERT_EQ(ERROR_SUCCESS,
+            reg_key.WriteValue(ModuleListManager::kModuleListPathKeyName,
+                               L"C:\\foo\\bar.txt"));
+  ASSERT_EQ(ERROR_SUCCESS,
+            reg_key.WriteValue(ModuleListManager::kModuleListVersionKeyName,
+                               L"invalid-version-string"));
+
+  ModuleListManager mlm(base::SequencedTaskRunnerHandle::Get());
+  EXPECT_TRUE(mlm.module_list_path().empty());
+  EXPECT_FALSE(mlm.module_list_version().IsValid());
+
+  ASSERT_NO_FATAL_FAILURE(NotifyNewModuleList(&mlm));
+}
+
+TEST_F(ModuleListManagerTest, FindsExistingPathInRegistry) {
+  base::win::RegKey reg_key(ModuleListManager::GetRegistryHive(),
+                            ModuleListManager::GetRegistryPath().c_str(),
+                            KEY_WRITE);
+  ASSERT_TRUE(reg_key.Valid());
+  ASSERT_EQ(ERROR_SUCCESS,
+            reg_key.WriteValue(ModuleListManager::kModuleListPathKeyName,
+                               L"C:\\foo\\bar.txt"));
+  ASSERT_EQ(ERROR_SUCCESS,
+            reg_key.WriteValue(ModuleListManager::kModuleListVersionKeyName,
+                               L"1.0.0.0"));
+
+  ModuleListManager mlm(base::SequencedTaskRunnerHandle::Get());
+  EXPECT_TRUE(mlm.module_list_path().empty());
+  EXPECT_FALSE(mlm.module_list_version().IsValid());
+
+  ASSERT_NO_FATAL_FAILURE(NotifyNewModuleList(&mlm));
+}
diff --git a/chrome/browser/conflicts/proto/module_list.proto b/chrome/browser/conflicts/proto/module_list.proto
index 6f40844..8063627 100644
--- a/chrome/browser/conflicts/proto/module_list.proto
+++ b/chrome/browser/conflicts/proto/module_list.proto
@@ -11,28 +11,36 @@
 // Describes a version tuple. Versions are matched exactly, so missing fields
 // will not match zero value fields. For example, "4" will not match "4.0" or
 // "4.0.0.0".
-message ModlchrueVersion {
-  required uint32 major = 1;
-  optional uint32 minor = 2;
+// Next id: 5
+message ModuleVersion {
+  required uint32 major_version = 1;
+  optional uint32 minor_version = 2;
   // Can only be specified if |minor| is specified.
-  optional uint32 patch = 3;
+  optional uint32 patch_version = 3;
   // Can only be specified if |patch| is specified.
-  optional uint32 revision = 4;
+  optional uint32 revision_version = 4;
 }
 
 // Describes a module. A module is valid only if at least one of |basename| or
 // |code_id| is specified, although both may be specified. A module must exactly
 // match all specified fields in order to be considered a match.
+// Next id: 7
 message Module {
   // The basename of the module. This is case insensitive. If this is not
-  // specified then |code_id| must be specified.
+  // specified then |code_id| must be specified. On the client this actually
+  // corresponds to the SHA1 hash of the basename, which has been first made
+  // lowercase.
   optional string basename = 1;
+  optional bytes basename_hash = 5;
 
   // Code ID. This is equivalent to the string generated by formatting
   // the FileHeader.TimeDateStamp and OptionalHeader.SizeOfImage with the
   // formatting string %08X%x. Comparison is case insensitive. If this is not
-  // specified then |basename| must be specified.
+  // specified then |basename| must be specified. On the client this actually
+  // corresponds to the SHA1 hash of the code id, which has first been made
+  // lowercase.
   optional string code_id = 2;
+  optional bytes code_id_hash = 6;
 
   // Version matching. Specifying both a minimum and a maximum provides an
   // exact matching mechanism. Both versions are inclusive.
@@ -42,16 +50,22 @@
 
 // A module group is a collection of one or more modules with shared publisher
 // and/or installation directory information.
+// Next id: 6
 message ModuleGroup {
   // Publisher information. If specified then the modules in this group will
   // only match if they are signed by the specified publisher. This corresponds
-  // to the Organizational Unit (OU) specified in the signature.
+  // to the OU specified in the signature. On the client this actually
+  // corresponds to the SHA1 of the case-sensitive publisher information.
   optional string publisher = 1;
+  optional bytes publisher_hash = 4;
 
   // The directory in which the modules are found. This may use environment
   // variables such as %LOCALAPPDATA%, %SYSTEMROOT%, etc. This is case
-  // insensitive. If not specified then any path will be accepted.
+  // insensitive. If not specified then any path will be accepted. On the
+  // client this actually corresponds to the SHA1 of the case-sensitive
+  // publisher information.
   optional string directory = 2;
+  optional bytes directory_hash = 5;
 
   // A list of modules.
   repeated Module modules = 3;
@@ -59,6 +73,7 @@
 
 // Describes a whitelist of modules that will always be allowed to load, and for
 // which there is no associated user messaging.
+// Next id: 2
 message ModuleWhitelist {
   // A collection of modules, grouped by publisher/installation path
   // information.
@@ -66,6 +81,7 @@
 }
 
 // The user message to display when a blacklisted module is matched at runtime.
+// Next id: 3
 enum BlacklistMessageType {
   // The user will be presented with a message to uninstall the software. This
   // message will only be displayed if a matching software entry with
@@ -88,6 +104,7 @@
 };
 
 // The actions to take when a blacklisted module is encountered.
+// Next id: 4
 message BlacklistAction {
   // Indicates whether or not this module should be allowed to load. This can be
   // used to explicitly allow modules to load that when blocked cause problems,
@@ -103,26 +120,29 @@
 // Describes a group in the module blacklist. Modules not whitelisted are
 // blacklisted by default, but fine-grained control over the user messaging is
 // possible using an explicit blacklist entry.
+// Next id: 3
 message BlacklistModuleGroup {
   // The action to take when modules in this group are encountered.
   required BlacklistAction action = 1;
 
   // The group of modules itself.
-  required ModuleGroup modules;
+  required ModuleGroup modules = 2;
 }
 
 // Describes a blacklist of modules that are to be handled specially when
 // encountered.
+// Next id: 2
 message ModuleBlacklist {
-  repeated BlacklistModuleGroup modules_groups = 1;
+  repeated BlacklistModuleGroup module_groups = 1;
 }
 
 // The entire module list itself consists of a whitelist and a blacklist.
+// Next id: 3
 message ModuleList {
   // The whitelisted modules.
-  required ModuleWhitelist whitelist;
+  required ModuleWhitelist whitelist = 1;
 
   // The blacklisted modules, and the associated actions to take upon
   // encountering them.
-  required ModuleBlacklist blacklist;
+  required ModuleBlacklist blacklist = 2;
 }
diff --git a/chrome/browser/download/download_request_infobar_delegate_android.cc b/chrome/browser/download/download_request_infobar_delegate_android.cc
deleted file mode 100644
index f0f7004..0000000
--- a/chrome/browser/download/download_request_infobar_delegate_android.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/download/download_request_infobar_delegate_android.h"
-
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/infobars/core/infobar.h"
-#include "ui/base/l10n/l10n_util.h"
-
-DownloadRequestInfoBarDelegateAndroid::FakeCreateCallback*
-    DownloadRequestInfoBarDelegateAndroid::callback_ = NULL;
-
-DownloadRequestInfoBarDelegateAndroid::
-    ~DownloadRequestInfoBarDelegateAndroid() {
-  if (!responded_ && host_)
-    host_->CancelOnce();
-}
-
-// static
-void DownloadRequestInfoBarDelegateAndroid::Create(
-    InfoBarService* infobar_service,
-    base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host) {
-  if (DownloadRequestInfoBarDelegateAndroid::callback_ &&
-      !DownloadRequestInfoBarDelegateAndroid::callback_->is_null()) {
-    DownloadRequestInfoBarDelegateAndroid::callback_->Run(infobar_service,
-                                                          host);
-  } else if (!infobar_service) {
-    // |web_contents| may not have a InfoBarService if it's actually a
-    // WebContents like those used for extension popups/bubbles and hosted apps
-    // etc.
-    // TODO(benjhayden): If this is an automatic download from an extension,
-    // it would be convenient for the extension author if we send a message to
-    // the extension's DevTools console (as we do for CSP) about how
-    // extensions should use chrome.downloads.download() (requires the
-    // "downloads" permission) to automatically download >1 files.
-    host->Cancel();
-  } else {
-    infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
-        std::unique_ptr<ConfirmInfoBarDelegate>(
-            new DownloadRequestInfoBarDelegateAndroid(host))));
-  }
-}
-
-// static
-void DownloadRequestInfoBarDelegateAndroid::SetCallbackForTesting(
-    FakeCreateCallback* callback) {
-  DownloadRequestInfoBarDelegateAndroid::callback_ = callback;
-}
-
-DownloadRequestInfoBarDelegateAndroid::DownloadRequestInfoBarDelegateAndroid(
-    base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host)
-    : ConfirmInfoBarDelegate(), responded_(false), host_(host) {}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-DownloadRequestInfoBarDelegateAndroid::GetIdentifier() const {
-  return DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID;
-}
-
-int DownloadRequestInfoBarDelegateAndroid::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_MULTIPLE_DOWNLOADS;
-}
-
-base::string16 DownloadRequestInfoBarDelegateAndroid::GetMessageText() const {
-  return l10n_util::GetStringUTF16(IDS_MULTI_DOWNLOAD_WARNING);
-}
-
-base::string16 DownloadRequestInfoBarDelegateAndroid::GetButtonLabel(
-    InfoBarButton button) const {
-  return l10n_util::GetStringUTF16((button == BUTTON_OK)
-                                       ? IDS_MULTI_DOWNLOAD_WARNING_ALLOW
-                                       : IDS_MULTI_DOWNLOAD_WARNING_BLOCK);
-}
-
-bool DownloadRequestInfoBarDelegateAndroid::Accept() {
-  DCHECK(!responded_);
-  responded_ = true;
-  if (host_) {
-    // This may invalidate |host_|.
-    host_->Accept();
-  }
-  return !host_;
-}
-
-bool DownloadRequestInfoBarDelegateAndroid::Cancel() {
-  DCHECK(!responded_);
-  responded_ = true;
-  if (host_) {
-    // This may invalidate |host_|.
-    host_->Cancel();
-  }
-  return !host_;
-}
diff --git a/chrome/browser/download/download_request_infobar_delegate_android.h b/chrome/browser/download/download_request_infobar_delegate_android.h
deleted file mode 100644
index bf2c4446..0000000
--- a/chrome/browser/download/download_request_infobar_delegate_android.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID_H_
-#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID_H_
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/download/download_request_limiter.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-
-class InfoBarService;
-
-// An infobar delegate that presents the user with a choice to allow or deny
-// multiple downloads from the same site. This confirmation step protects
-// against "carpet-bombing", where a malicious site forces multiple downloads
-// on an unsuspecting user.
-class DownloadRequestInfoBarDelegateAndroid : public ConfirmInfoBarDelegate {
- public:
-  typedef base::Callback<void(
-      InfoBarService* infobar_service,
-      base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host)>
-      FakeCreateCallback;
-
-  ~DownloadRequestInfoBarDelegateAndroid() override;
-
-  // Creates a download request delegate and adds it to |infobar_service|.
-  static void Create(
-      InfoBarService* infobar_service,
-      base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host);
-
-#if defined(UNIT_TEST)
-  static std::unique_ptr<DownloadRequestInfoBarDelegateAndroid> Create(
-      base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host) {
-    return std::unique_ptr<DownloadRequestInfoBarDelegateAndroid>(
-        new DownloadRequestInfoBarDelegateAndroid(host));
-  }
-#endif
-
-  static void SetCallbackForTesting(FakeCreateCallback* callback);
-
- private:
-  static FakeCreateCallback* callback_;
-
-  explicit DownloadRequestInfoBarDelegateAndroid(
-      base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host);
-
-  // ConfirmInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  base::string16 GetMessageText() const override;
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  bool Accept() override;
-  bool Cancel() override;
-
-  bool responded_;
-  base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host_;
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadRequestInfoBarDelegateAndroid);
-};
-
-#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/download/download_request_infobar_delegate_unittest.cc b/chrome/browser/download/download_request_infobar_delegate_unittest.cc
deleted file mode 100644
index 63df351..0000000
--- a/chrome/browser/download/download_request_infobar_delegate_unittest.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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.
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/download/download_request_infobar_delegate_android.h"
-#include "chrome/browser/download/download_request_limiter.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// MockTabDownloadState -------------------------------------------------------
-
-class MockTabDownloadState : public DownloadRequestLimiter::TabDownloadState {
- public:
-  MockTabDownloadState();
-  ~MockTabDownloadState() override;
-
-  // DownloadRequestLimiter::TabDownloadState:
-  void Cancel() override;
-  void Accept() override;
-  void CancelOnce() override;
-
-  ConfirmInfoBarDelegate* infobar_delegate() { return infobar_delegate_.get(); }
-  void delete_infobar_delegate() { infobar_delegate_.reset(); }
-  bool responded() const { return responded_; }
-  bool accepted() const { return accepted_; }
-
- private:
-  // The actual infobar delegate we're listening to.
-  std::unique_ptr<DownloadRequestInfoBarDelegateAndroid> infobar_delegate_;
-
-  // True if we have gotten some sort of response.
-  bool responded_;
-
-  // True if we have gotten a Accept response. Meaningless if |responded_| is
-  // not true.
-  bool accepted_;
-
-  // To produce weak pointers for infobar_ construction.
-  base::WeakPtrFactory<MockTabDownloadState> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockTabDownloadState);
-};
-
-MockTabDownloadState::MockTabDownloadState()
-    : responded_(false),
-      accepted_(false),
-      weak_ptr_factory_(this) {
-  infobar_delegate_ = DownloadRequestInfoBarDelegateAndroid::Create(
-      weak_ptr_factory_.GetWeakPtr());
-}
-
-MockTabDownloadState::~MockTabDownloadState() {
-  EXPECT_TRUE(responded_);
-}
-
-void MockTabDownloadState::Cancel() {
-  EXPECT_FALSE(responded_);
-  responded_ = true;
-  accepted_ = false;
-}
-
-void MockTabDownloadState::Accept() {
-  EXPECT_FALSE(responded_);
-  responded_ = true;
-  accepted_ = true;
-  weak_ptr_factory_.InvalidateWeakPtrs();
-}
-
-void MockTabDownloadState::CancelOnce() {
-  Cancel();
-}
-
-
-// Tests ----------------------------------------------------------------------
-
-TEST(DownloadRequestInfoBarDelegateAndroid, AcceptTest) {
-  MockTabDownloadState state;
-  if (state.infobar_delegate()->Accept())
-    state.delete_infobar_delegate();
-  EXPECT_TRUE(state.accepted());
-}
-
-TEST(DownloadRequestInfoBarDelegateAndroid, CancelTest) {
-  MockTabDownloadState state;
-  if (state.infobar_delegate()->Cancel())
-    state.delete_infobar_delegate();
-  EXPECT_FALSE(state.accepted());
-}
-
-TEST(DownloadRequestInfoBarDelegateAndroid, CloseTest) {
-  MockTabDownloadState state;
-  state.delete_infobar_delegate();
-  EXPECT_FALSE(state.accepted());
-}
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc
index dcf5f613..11721ee 100644
--- a/chrome/browser/download/download_request_limiter.cc
+++ b/chrome/browser/download/download_request_limiter.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/download/download_permission_request.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/tab_contents/tab_util.h"
@@ -28,10 +27,6 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "url/gurl.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/download/download_request_infobar_delegate_android.h"
-#endif
-
 using content::BrowserThread;
 using content::NavigationController;
 using content::NavigationEntry;
@@ -174,15 +169,10 @@
     return;
   }
 
-  bool promptable;
-  if (PermissionRequestManager::IsEnabled()) {
-    promptable =
-        PermissionRequestManager::FromWebContents(web_contents()) != nullptr;
-  } else {
-    promptable = InfoBarService::FromWebContents(web_contents()) != nullptr;
-  }
+  bool promptable =
+      PermissionRequestManager::FromWebContents(web_contents()) != nullptr;
 
-  // See PromptUserForDownload(): if there's no InfoBarService, then
+  // See PromptUserForDownload(): if there's no PermissionRequestManager, then
   // DOWNLOADS_NOT_ALLOWED is functionally equivalent to PROMPT_BEFORE_DOWNLOAD.
   if ((status_ != DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS) &&
       (!promptable ||
@@ -219,20 +209,13 @@
     return;
   }
 
-  if (PermissionRequestManager::IsEnabled()) {
-    PermissionRequestManager* permission_request_manager =
-        PermissionRequestManager::FromWebContents(web_contents_);
-    if (permission_request_manager) {
-      permission_request_manager->AddRequest(
-          new DownloadPermissionRequest(factory_.GetWeakPtr()));
-    } else {
-      Cancel();
-    }
+  PermissionRequestManager* permission_request_manager =
+      PermissionRequestManager::FromWebContents(web_contents_);
+  if (permission_request_manager) {
+    permission_request_manager->AddRequest(
+        new DownloadPermissionRequest(factory_.GetWeakPtr()));
   } else {
-#if defined(OS_ANDROID)
-    DownloadRequestInfoBarDelegateAndroid::Create(
-        InfoBarService::FromWebContents(web_contents_), factory_.GetWeakPtr());
-#endif
+    Cancel();
   }
 }
 
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc
index eced0932..72be1110 100644
--- a/chrome/browser/download/download_request_limiter_unittest.cc
+++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -28,12 +28,6 @@
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/download/download_request_infobar_delegate_android.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#else
-#endif
-
 using content::WebContents;
 
 namespace {
@@ -49,39 +43,20 @@
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
 
-    use_permission_request_manager_ = PermissionRequestManager::IsEnabled();
-
-    if (use_permission_request_manager_) {
-      PermissionRequestManager::CreateForWebContents(web_contents());
-      PermissionRequestManager* manager =
-          PermissionRequestManager::FromWebContents(web_contents());
-      mock_permission_prompt_factory_.reset(
-          new MockPermissionPromptFactory(manager));
-      manager->DisplayPendingRequests();
-    } else {
-#if defined(OS_ANDROID)
-      InfoBarService::CreateForWebContents(web_contents());
-      fake_create_callback_ = base::Bind(
-          &DownloadRequestLimiterTest::FakeCreate, base::Unretained(this));
-      DownloadRequestInfoBarDelegateAndroid::SetCallbackForTesting(
-          &fake_create_callback_);
-#endif
-    }
+    PermissionRequestManager::CreateForWebContents(web_contents());
+    PermissionRequestManager* manager =
+        PermissionRequestManager::FromWebContents(web_contents());
+    mock_permission_prompt_factory_.reset(
+        new MockPermissionPromptFactory(manager));
+    manager->DisplayPendingRequests();
 
     UpdateExpectations(ACCEPT);
-    ask_allow_count_ = cancel_count_ = continue_count_ = 0;
+    cancel_count_ = continue_count_ = 0;
     download_request_limiter_ = new DownloadRequestLimiter();
   }
 
   void TearDown() override {
-    if (use_permission_request_manager_) {
-      mock_permission_prompt_factory_.reset();
-    } else {
-#if defined(OS_ANDROID)
-      UnsetInfobarDelegate();
-#endif
-    }
-
+    mock_permission_prompt_factory_.reset();
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -120,10 +95,7 @@
     EXPECT_EQ(expect_cancels, cancel_count_) << "line " << line;
     EXPECT_EQ(expect_asks, AskAllowCount()) << "line " << line;
     continue_count_ = cancel_count_ = 0;
-    if (use_permission_request_manager_)
-      mock_permission_prompt_factory_->ResetCounts();
-    else
-      ask_allow_count_ = 0;
+    mock_permission_prompt_factory_->ResetCounts();
   }
 
   void UpdateContentSettings(WebContents* web_contents,
@@ -151,61 +123,29 @@
   }
 
   void LoadCompleted() {
-    if (use_permission_request_manager_)
-      mock_permission_prompt_factory_->DocumentOnLoadCompletedInMainFrame();
+    mock_permission_prompt_factory_->DocumentOnLoadCompletedInMainFrame();
   }
 
-  int AskAllowCount() {
-    if (use_permission_request_manager_)
-      return mock_permission_prompt_factory_->show_count();
-    return ask_allow_count_;
-  }
+  int AskAllowCount() { return mock_permission_prompt_factory_->show_count(); }
 
   void UpdateExpectations(TestingAction action) {
-    if (use_permission_request_manager_) {
-      // Set expectations for PermissionRequestManager.
-      PermissionRequestManager::AutoResponseType response_type =
-          PermissionRequestManager::DISMISS;
-      switch (action) {
-        case ACCEPT:
-          response_type = PermissionRequestManager::ACCEPT_ALL;
-          break;
-        case CANCEL:
-          response_type = PermissionRequestManager::DENY_ALL;
-          break;
-        case WAIT:
-          response_type = PermissionRequestManager::NONE;
-          break;
-      }
-      mock_permission_prompt_factory_->set_response_type(response_type);
-    } else {
-      testing_action_ = action;
-    }
-  }
-
-#if defined(OS_ANDROID)
-  void FakeCreate(
-      InfoBarService* infobar_service,
-      base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host) {
-    ask_allow_count_++;
-    switch (testing_action_) {
+    // Set expectations for PermissionRequestManager.
+    PermissionRequestManager::AutoResponseType response_type =
+        PermissionRequestManager::DISMISS;
+    switch (action) {
       case ACCEPT:
-        host->Accept();
+        response_type = PermissionRequestManager::ACCEPT_ALL;
         break;
       case CANCEL:
-        host->Cancel();
+        response_type = PermissionRequestManager::DENY_ALL;
         break;
       case WAIT:
+        response_type = PermissionRequestManager::NONE;
         break;
     }
+    mock_permission_prompt_factory_->set_response_type(response_type);
   }
 
-  void UnsetInfobarDelegate() {
-    if (!use_permission_request_manager_)
-      DownloadRequestInfoBarDelegateAndroid::SetCallbackForTesting(nullptr);
-  }
-#endif
-
   scoped_refptr<DownloadRequestLimiter> download_request_limiter_;
 
   // Number of times ContinueDownload was invoked.
@@ -215,19 +155,6 @@
   int cancel_count_;
 
   std::unique_ptr<MockPermissionPromptFactory> mock_permission_prompt_factory_;
-
-  // TODO(timloh): Remove the members below here after crbug.com/606138 is done.
-
-  bool use_permission_request_manager_;
-
-  // Number of times ShouldAllowDownload was invoked.
-  int ask_allow_count_;
-  // The action that FakeCreate() should take.
-  TestingAction testing_action_;
-#if defined(OS_ANDROID)
-  DownloadRequestInfoBarDelegateAndroid::FakeCreateCallback
-      fake_create_callback_;
-#endif
 };
 
 TEST_F(DownloadRequestLimiterTest, Allow) {
@@ -570,12 +497,9 @@
   web_contents->GetController().LoadURL(
       url, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
 
-// DownloadRequestLimiter won't try to make a permission request or infobar
-// if there is no PermissionRequestManager/InfoBarService, and we want to
-// test that it will Cancel() instead of prompting.
-#if defined(OS_ANDROID)
-  UnsetInfobarDelegate();
-#endif
+  // DownloadRequestLimiter won't try to make a permission request or infobar
+  // if there is no PermissionRequestManager, and we want to test that it will
+  // Cancel() instead of prompting.
   ExpectAndResetCounts(0, 0, 0, __LINE__);
   EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
             download_request_limiter_->GetDownloadStatus(web_contents.get()));
diff --git a/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc b/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc
index 8dbdcf8..59fb5e4b 100644
--- a/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc
+++ b/chrome/browser/extensions/api/tab_capture/offscreen_tab.cc
@@ -5,10 +5,13 @@
 #include "chrome/browser/extensions/api/tab_capture/offscreen_tab.h"
 
 #include <algorithm>
+#include <vector>
 
 #include "base/bind.h"
+#include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
 #include "chrome/browser/media/router/receiver_presentation_service_delegate_impl.h"  // nogncheck
 #include "chrome/browser/profiles/profile.h"
@@ -37,6 +40,10 @@
 const int kMaxSecondsToWaitForCapture = 60;
 const int kPollIntervalInSeconds = 1;
 
+typedef std::vector<content::BrowserContext*> BrowserContextList;
+static base::LazyInstance<BrowserContextList>::Leaky g_offscreen_profiles =
+    LAZY_INSTANCE_INITIALIZER;
+
 }  // namespace
 
 namespace extensions {
@@ -56,6 +63,13 @@
   return FromWebContents(extension_web_contents);
 }
 
+// static
+bool OffscreenTabsOwner::IsOffscreenProfile(const Profile* profile) {
+  const BrowserContextList& offscreen_profiles = g_offscreen_profiles.Get();
+  return std::find(offscreen_profiles.begin(), offscreen_profiles.end(),
+                   profile) != offscreen_profiles.end();
+}
+
 OffscreenTab* OffscreenTabsOwner::OpenNewTab(
     const GURL& start_url,
     const gfx::Size& initial_size,
@@ -120,9 +134,11 @@
       content_capture_was_detected_(false),
       navigation_policy_(new NavigationPolicy) {
   DCHECK(profile_);
+  g_offscreen_profiles.Get().push_back(profile_.get());
 }
 
 OffscreenTab::~OffscreenTab() {
+  base::Erase(g_offscreen_profiles.Get(), profile_.get());
   DVLOG(1) << "Destroying OffscreenTab for start_url=" << start_url_.spec();
 }
 
diff --git a/chrome/browser/extensions/api/tab_capture/offscreen_tab.h b/chrome/browser/extensions/api/tab_capture/offscreen_tab.h
index 75ad96e..9e31324 100644
--- a/chrome/browser/extensions/api/tab_capture/offscreen_tab.h
+++ b/chrome/browser/extensions/api/tab_capture/offscreen_tab.h
@@ -44,6 +44,10 @@
   // background page's WebContents.  Never returns nullptr.
   static OffscreenTabsOwner* Get(content::WebContents* extension_web_contents);
 
+  // Returns |true| if |profile| is associated with an offscreen tab, false
+  // otherwise.
+  static bool IsOffscreenProfile(const Profile* profile);
+
   // Instantiate a new offscreen tab and navigate it to |start_url|.  The new
   // tab's main frame will start out with the given |initial_size| in DIP
   // coordinates.  If too many offscreen tabs are already running, nothing
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
index 4933e36..28b4d8a 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -202,6 +202,8 @@
   AddExtensionToCommandLineWhitelist();
   ASSERT_TRUE(RunExtensionSubtest("tab_capture", "offscreen_end_to_end.html"))
       << message_;
+  // Verify that offscreen profile has been destroyed.
+  ASSERT_FALSE(profile()->HasOffTheRecordProfile());
 }
 
 // Tests that off-screen tabs can't do evil things (e.g., access local files).
@@ -213,6 +215,8 @@
   AddExtensionToCommandLineWhitelist();
   ASSERT_TRUE(RunExtensionSubtest("tab_capture", "offscreen_evil_tests.html"))
       << message_;
+  // Verify that offscreen profile has been destroyed.
+  ASSERT_FALSE(profile()->HasOffTheRecordProfile());
 }
 
 // http://crbug.com/177163
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 4398370d..f00f274 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -109,8 +109,15 @@
 bool ChromeExtensionsBrowserClient::IsSameContext(
     content::BrowserContext* first,
     content::BrowserContext* second) {
-  return static_cast<Profile*>(first)->IsSameProfile(
-      static_cast<Profile*>(second));
+  Profile* first_profile = Profile::FromBrowserContext(first);
+  Profile* second_profile = Profile::FromBrowserContext(second);
+  // TODO(crbug.com/727487): We need to check both ways because of offscreen
+  // presentation profiles, which are not registered with the original profile.
+  // This can be reverted to check just first->IsSameProfile(second) when Bug
+  // 727487 is fixed and presentations have a proper profile type.  See Bug
+  // 664351 for background.
+  return first_profile->IsSameProfile(second_profile) ||
+         second_profile->IsSameProfile(first_profile);
 }
 
 bool ChromeExtensionsBrowserClient::HasOffTheRecordContext(
diff --git a/chrome/browser/extensions/extension_bindings_apitest.cc b/chrome/browser/extensions/extension_bindings_apitest.cc
index 1bb1f6f..be3c484 100644
--- a/chrome/browser/extensions/extension_bindings_apitest.cc
+++ b/chrome/browser/extensions/extension_bindings_apitest.cc
@@ -5,7 +5,6 @@
 // Contains holistic tests of the bindings infrastructure
 
 #include "base/run_loop.h"
-#include "build/build_config.h"
 #include "chrome/browser/extensions/api/permissions/permissions_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/net/url_request_mock_util.h"
@@ -241,16 +240,7 @@
 // messages ("receiver") and one which we'll try first faking messages from in
 // the web page's iframe, as well as actually send a message from later
 // ("sender").
-
-// This test is currently flaking on Linux and Mac builders
-// https://crbug.com/761368
-#if defined(OS_LINUX) || defined(OS_MACOSX)
-#define MAYBE_FramesBeforeNavigation DISABLED_FramesBeforeNavigation
-#else
-#define MAYBE_FramesBeforeNavigation FramesBeforeNavigation
-#endif
-IN_PROC_BROWSER_TEST_P(FramesExtensionBindingsApiTest,
-                       MAYBE_FramesBeforeNavigation) {
+IN_PROC_BROWSER_TEST_P(FramesExtensionBindingsApiTest, FramesBeforeNavigation) {
   // Load the sender and receiver extensions, and make sure they are ready.
   ExtensionTestMessageListener sender_ready("sender_ready", true);
   const Extension* sender = LoadExtension(
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc
index 36b9fdc5..96fd356e 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.cc
+++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -134,8 +134,6 @@
 
 }  // namespace
 
-const char ExternalProtocolHandler::kRememberCheckboxMetric[] =
-    "BrowserDialogs.ExternalProtocol.RememberCheckbox";
 const char ExternalProtocolHandler::kHandleStateMetric[] =
     "BrowserDialogs.ExternalProtocol.HandleState";
 
@@ -318,11 +316,6 @@
 }
 
 // static
-void ExternalProtocolHandler::RecordCheckboxStateMetrics(bool selected) {
-  UMA_HISTOGRAM_BOOLEAN(kRememberCheckboxMetric, selected);
-}
-
-// static
 void ExternalProtocolHandler::RecordHandleStateMetrics(bool checkbox_selected,
                                                        BlockState block_state) {
   HandleState handle_state = DONT_LAUNCH;
@@ -331,12 +324,14 @@
       handle_state = checkbox_selected ? CHECKED_LAUNCH : LAUNCH;
       break;
     case BLOCK:
-      handle_state = checkbox_selected ? CHECKED_DONT_LAUNCH : DONT_LAUNCH;
+      handle_state =
+          checkbox_selected ? CHECKED_DONT_LAUNCH_DEPRECATED : DONT_LAUNCH;
       break;
     case UNKNOWN:
       NOTREACHED();
       return;
   }
+  DCHECK_NE(CHECKED_DONT_LAUNCH_DEPRECATED, handle_state);
   UMA_HISTOGRAM_ENUMERATION(kHandleStateMetric, handle_state,
                             HANDLE_STATE_LAST);
 }
diff --git a/chrome/browser/external_protocol/external_protocol_handler.h b/chrome/browser/external_protocol/external_protocol_handler.h
index 671626f..fca8176 100644
--- a/chrome/browser/external_protocol/external_protocol_handler.h
+++ b/chrome/browser/external_protocol/external_protocol_handler.h
@@ -35,7 +35,7 @@
     LAUNCH,
     CHECKED_LAUNCH,
     DONT_LAUNCH,
-    CHECKED_DONT_LAUNCH,
+    CHECKED_DONT_LAUNCH_DEPRECATED,
     HANDLE_STATE_LAST
   };
 
@@ -63,7 +63,6 @@
   };
 
   // UMA histogram metric names.
-  static const char kRememberCheckboxMetric[];
   static const char kHandleStateMetric[];
 
   // Returns whether we should block a given scheme.
@@ -110,10 +109,6 @@
   // preferences for them do not already exist.
   static void PrepopulateDictionary(base::DictionaryValue* win_pref);
 
-  // Records an UMA metric for the state of the checkbox in the dialog, i.e.
-  // whether |selected| is true (checked) or false (unchecked).
-  static void RecordCheckboxStateMetrics(bool selected);
-
   // Records an UMA metric for the external protocol HandleState selected, based
   // on if the check box is selected / not and block / Dont block is picked.
   static void RecordHandleStateMetrics(bool checkbox_selected,
diff --git a/chrome/browser/feature_engagement/bookmark/bookmark_tracker.cc b/chrome/browser/feature_engagement/bookmark/bookmark_tracker.cc
new file mode 100644
index 0000000..3cce2c6
--- /dev/null
+++ b/chrome/browser/feature_engagement/bookmark/bookmark_tracker.cc
@@ -0,0 +1,70 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/feature_engagement/bookmark/bookmark_tracker.h"
+
+#include "base/feature_list.h"
+#include "base/time/time.h"
+#include "chrome/browser/feature_engagement/session_duration_updater.h"
+#include "chrome/browser/feature_engagement/session_duration_updater_factory.h"
+#include "chrome/browser/feature_engagement/tracker_factory.h"
+#include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "components/feature_engagement/public/event_constants.h"
+#include "components/feature_engagement/public/feature_constants.h"
+#include "components/feature_engagement/public/tracker.h"
+
+namespace {
+
+const int kFiveHoursInMinutes = 300;
+
+}  // namespace
+
+namespace feature_engagement {
+
+BookmarkTracker::BookmarkTracker(
+    Profile* profile,
+    SessionDurationUpdater* session_duration_updater)
+    : FeatureTracker(profile, session_duration_updater) {}
+
+BookmarkTracker::BookmarkTracker(
+    SessionDurationUpdater* session_duration_updater)
+    : BookmarkTracker(nullptr, session_duration_updater) {}
+
+BookmarkTracker::~BookmarkTracker() = default;
+
+void BookmarkTracker::OnPromoClosed() {
+  GetTracker()->Dismissed(kIPHBookmarkFeature);
+}
+
+void BookmarkTracker::OnBookmarkAdded() {
+  GetTracker()->NotifyEvent(events::kBookmarkAdded);
+}
+
+void BookmarkTracker::OnVisitedKnownURL() {
+  if (ShouldShowPromo())
+    ShowPromo();
+}
+
+bool BookmarkTracker::ShouldShowPromo() {
+  return GetTracker()->ShouldTriggerHelpUI(kIPHBookmarkFeature);
+}
+
+void BookmarkTracker::OnSessionTimeMet() {
+  GetTracker()->NotifyEvent(events::kBookmarkSessionTimeMet);
+}
+
+int BookmarkTracker::GetSessionTimeRequiredToShowInMinutes() {
+  return kFiveHoursInMinutes;
+}
+
+void BookmarkTracker::ShowPromo() {
+  // TODO: Call the promo.
+
+  // Clears the flag for whether there is any in-product help being displayed.
+  GetTracker()->Dismissed(kIPHBookmarkFeature);
+}
+
+}  // namespace feature_engagement
diff --git a/chrome/browser/feature_engagement/bookmark/bookmark_tracker.h b/chrome/browser/feature_engagement/bookmark/bookmark_tracker.h
new file mode 100644
index 0000000..1adca30
--- /dev/null
+++ b/chrome/browser/feature_engagement/bookmark/bookmark_tracker.h
@@ -0,0 +1,63 @@
+// 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_FEATURE_ENGAGEMENT_BOOKMARK_BOOKMARK_TRACKER_H_
+#define CHROME_BROWSER_FEATURE_ENGAGEMENT_BOOKMARK_BOOKMARK_TRACKER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/feature_engagement/feature_tracker.h"
+
+class Profile;
+class SessionDurationUpdater;
+
+namespace feature_engagement {
+
+// The BookmarkTracker provides a backend for displaying in-product help for the
+// bookmarks. BookmarkTracker is the interface through which the event
+// constants for the Bookmark feature can be be altered. Once all of the event
+// constants are met, BookmarkTracker calls for the BookmarkPromo to be shown,
+// along with recording when the BookmarkPromo is dismissed. The requirements to
+// show the BookmarkPromo are as follows:
+//
+// - At least five hours of observed session time have elapsed.
+// - The user has never added another bookmark through any means.
+// - The user has navigated to a URL that they have visited at least 3 times.
+// - This URL cannot be the home page or new tab page.
+class BookmarkTracker : public FeatureTracker {
+ public:
+  BookmarkTracker(Profile* profile,
+                  SessionDurationUpdater* session_duration_updater);
+
+  // Alerts the bookmark tracker that a bookmark was added.
+  void OnBookmarkAdded();
+  // Checks if the promo should be displayed since a known URL has been visited.
+  void OnVisitedKnownURL();
+  // Clears the flag for whether there is any in-product help being displayed.
+  void OnPromoClosed();
+  // Returns whether or not the promo should be displayed.
+  bool ShouldShowPromo();
+
+ protected:
+  // Alternate constructor to support unit testing.
+  explicit BookmarkTracker(SessionDurationUpdater* session_duration_updater);
+  ~BookmarkTracker() override;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(BookmarkTrackerEventTest, TestOnSessionTimeMet);
+  FRIEND_TEST_ALL_PREFIXES(BookmarkTrackerTest, TestShouldNotShowPromo);
+  FRIEND_TEST_ALL_PREFIXES(BookmarkTrackerTest, TestShouldShowPromo);
+
+  // FeatureTracker:
+  int GetSessionTimeRequiredToShowInMinutes() override;
+  void OnSessionTimeMet() override;
+
+  // Sets the BookmarkInProductHelp pref to true and calls the Bookmark Promo.
+  void ShowPromo();
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkTracker);
+};
+
+}  // namespace feature_engagement
+
+#endif  // CHROME_BROWSER_FEATURE_ENGAGEMENT_BOOKMARK_BOOKMARK_TRACKER_H_
diff --git a/chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.cc b/chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.cc
new file mode 100644
index 0000000..312bb24
--- /dev/null
+++ b/chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.cc
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/feature_engagement/bookmark/bookmark_tracker.h"
+#include "chrome/browser/feature_engagement/session_duration_updater.h"
+#include "chrome/browser/feature_engagement/session_duration_updater_factory.h"
+#include "chrome/browser/feature_engagement/tracker_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace feature_engagement {
+
+// static
+BookmarkTrackerFactory* BookmarkTrackerFactory::GetInstance() {
+  return base::Singleton<BookmarkTrackerFactory>::get();
+}
+
+BookmarkTracker* BookmarkTrackerFactory::GetForProfile(Profile* profile) {
+  return static_cast<BookmarkTracker*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+BookmarkTrackerFactory::BookmarkTrackerFactory()
+    : BrowserContextKeyedServiceFactory(
+          "BookmarkTracker",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(SessionDurationUpdaterFactory::GetInstance());
+  DependsOn(TrackerFactory::GetInstance());
+}
+
+BookmarkTrackerFactory::~BookmarkTrackerFactory() = default;
+
+KeyedService* BookmarkTrackerFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new BookmarkTracker(
+      Profile::FromBrowserContext(context),
+      feature_engagement::SessionDurationUpdaterFactory::GetInstance()
+          ->GetForProfile(Profile::FromBrowserContext(context)));
+}
+
+content::BrowserContext* BookmarkTrackerFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+}  // namespace feature_engagement
diff --git a/chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.h b/chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.h
new file mode 100644
index 0000000..3e954d4
--- /dev/null
+++ b/chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.h
@@ -0,0 +1,52 @@
+// 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_FEATURE_ENGAGEMENT_BOOKMARK_BOOKMARK_TRACKER_FACTORY_H_
+#define CHROME_BROWSER_FEATURE_ENGAGEMENT_BOOKMARK_BOOKMARK_TRACKER_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace feature_engagement {
+class BookmarkTracker;
+
+// BookmarkTrackerFactory is the main client class for interaction with the
+// BookmarkTracker component.
+class BookmarkTrackerFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns singleton instance of BookmarkTrackerFactory.
+  static BookmarkTrackerFactory* GetInstance();
+
+  // Returns the FeatureEngagementTracker associated with the profile.
+  BookmarkTracker* GetForProfile(Profile* profile);
+
+ private:
+  friend struct base::DefaultSingletonTraits<BookmarkTrackerFactory>;
+
+  BookmarkTrackerFactory();
+  ~BookmarkTrackerFactory() override;
+
+  // BrowserContextKeyedServiceFactory overrides:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkTrackerFactory);
+};
+
+}  // namespace feature_engagement
+
+#endif  // CHROME_BROWSER_FEATURE_ENGAGEMENT_BOOKMARK_BOOKMARK_TRACKER_FACTORY_H_
diff --git a/chrome/browser/feature_engagement/bookmark/bookmark_tracker_unittest.cc b/chrome/browser/feature_engagement/bookmark/bookmark_tracker_unittest.cc
new file mode 100644
index 0000000..3ef1473
--- /dev/null
+++ b/chrome/browser/feature_engagement/bookmark/bookmark_tracker_unittest.cc
@@ -0,0 +1,237 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/feature_engagement/bookmark/bookmark_tracker.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_param_associator.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/feature_engagement/feature_tracker.h"
+#include "chrome/browser/feature_engagement/session_duration_updater.h"
+#include "chrome/browser/feature_engagement/session_duration_updater_factory.h"
+#include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "components/feature_engagement/public/event_constants.h"
+#include "components/feature_engagement/public/feature_constants.h"
+#include "components/feature_engagement/public/tracker.h"
+#include "components/feature_engagement/test/test_tracker.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/variations/variations_params_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feature_engagement {
+
+namespace {
+
+const char kBookmarkTrialName[] = "BookmarkTrial";
+const char kGroupName[] = "Enabled";
+const char kTestProfileName[] = "test-profile";
+
+class MockTracker : public Tracker {
+ public:
+  MockTracker() = default;
+  MOCK_METHOD1(NotifyEvent, void(const std::string& event));
+  MOCK_METHOD1(ShouldTriggerHelpUI, bool(const base::Feature& feature));
+  MOCK_METHOD1(GetTriggerState,
+               Tracker::TriggerState(const base::Feature& feature));
+  MOCK_METHOD1(Dismissed, void(const base::Feature& feature));
+  MOCK_METHOD0(IsInitialized, bool());
+  MOCK_METHOD1(AddOnInitializedCallback, void(OnInitializedCallback callback));
+};
+
+class FakeBookmarkTracker : public BookmarkTracker {
+ public:
+  FakeBookmarkTracker(Tracker* feature_tracker, Profile* profile)
+      : BookmarkTracker(
+            feature_engagement::SessionDurationUpdaterFactory::GetInstance()
+                ->GetForProfile(profile)),
+        feature_tracker_(feature_tracker),
+        pref_service_(
+            base::MakeUnique<sync_preferences::TestingPrefServiceSyncable>()) {
+    SessionDurationUpdater::RegisterProfilePrefs(pref_service_->registry());
+  }
+
+  PrefService* GetPrefs() { return pref_service_.get(); }
+
+  // feature_engagement::NewTabTracker:
+  Tracker* GetTracker() const override { return feature_tracker_; }
+
+ private:
+  Tracker* const feature_tracker_;
+  const std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
+      pref_service_;
+};
+
+class BookmarkTrackerEventTest : public testing::Test {
+ public:
+  BookmarkTrackerEventTest() = default;
+  ~BookmarkTrackerEventTest() override = default;
+
+  void SetUp() override {
+    // Start the DesktopSessionDurationTracker to track active session time.
+    metrics::DesktopSessionDurationTracker::Initialize();
+    testing_profile_manager_ = base::MakeUnique<TestingProfileManager>(
+        TestingBrowserProcess::GetGlobal());
+    ASSERT_TRUE(testing_profile_manager_->SetUp());
+    mock_tracker_ = base::MakeUnique<testing::StrictMock<MockTracker>>();
+    bookmark_tracker_ = base::MakeUnique<FakeBookmarkTracker>(
+        mock_tracker_.get(),
+        testing_profile_manager_->CreateTestingProfile(kTestProfileName));
+  }
+
+  void TearDown() override {
+    bookmark_tracker_->RemoveSessionDurationObserver();
+    metrics::DesktopSessionDurationTracker::CleanupForTesting();
+    testing_profile_manager_.reset();
+  }
+
+ protected:
+  std::unique_ptr<TestingProfileManager> testing_profile_manager_;
+  std::unique_ptr<MockTracker> mock_tracker_;
+  std::unique_ptr<FakeBookmarkTracker> bookmark_tracker_;
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkTrackerEventTest);
+};
+
+}  // namespace
+
+// Tests to verify FeatureEngagementTracker API boundary expectations:
+
+// If OnBookmarkAdded() is called, the FeatureEngagementTracker
+// receives the kBookmarkAddedEvent.
+TEST_F(BookmarkTrackerEventTest, TestOnBookmarkAdded) {
+  EXPECT_CALL(*mock_tracker_, NotifyEvent(events::kBookmarkAdded));
+  bookmark_tracker_->OnBookmarkAdded();
+}
+
+// If OnSessionTimeMet() is called, the FeatureEngagementTracker
+// receives the kSessionTime event.
+TEST_F(BookmarkTrackerEventTest, TestOnSessionTimeMet) {
+  EXPECT_CALL(*mock_tracker_, NotifyEvent(events::kBookmarkSessionTimeMet));
+  bookmark_tracker_->OnSessionTimeMet();
+}
+
+namespace {
+
+class BookmarkTrackerTest : public testing::Test {
+ public:
+  BookmarkTrackerTest() = default;
+  ~BookmarkTrackerTest() override = default;
+
+  void SetUp() override {
+    // Set up the kBookmarkTrialName field trial.
+    base::FieldTrial* bookmark_trial =
+        base::FieldTrialList::CreateFieldTrial(kBookmarkTrialName, kGroupName);
+    trials_[kIPHBookmarkFeature.name] = bookmark_trial;
+
+    std::unique_ptr<base::FeatureList> feature_list =
+        base::MakeUnique<base::FeatureList>();
+    feature_list->RegisterFieldTrialOverride(
+        kIPHBookmarkFeature.name, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+        bookmark_trial);
+
+    scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
+    ASSERT_EQ(bookmark_trial,
+              base::FeatureList::GetFieldTrial(kIPHBookmarkFeature));
+
+    std::map<std::string, std::string> bookmark_params;
+    bookmark_params["event_bookmark_added"] =
+        "name:bookmark_added;comparator:==0;window:3650;storage:3650";
+    bookmark_params["event_bookmark_session_time_met"] =
+        "name:bookmark_session_time_met;comparator:>=1;window:3650;storage:"
+        "3650";
+    bookmark_params["event_trigger"] =
+        "name:bookmark_trigger;comparator:any;window:3650;storage:3650";
+    bookmark_params["event_used"] =
+        "name:bookmark_clicked;comparator:any;window:3650;storage:3650";
+    bookmark_params["session_rate"] = "<=3";
+    bookmark_params["availability"] = "any";
+
+    SetFeatureParams(kIPHBookmarkFeature, bookmark_params);
+
+    // Start the DesktopSessionDurationTracker to track active session time.
+    metrics::DesktopSessionDurationTracker::Initialize();
+
+    testing_profile_manager_ = base::MakeUnique<TestingProfileManager>(
+        TestingBrowserProcess::GetGlobal());
+    ASSERT_TRUE(testing_profile_manager_->SetUp());
+
+    feature_engagement_tracker_ = CreateTestTracker();
+
+    bookmark_tracker_ = base::MakeUnique<FakeBookmarkTracker>(
+        feature_engagement_tracker_.get(),
+        testing_profile_manager_->CreateTestingProfile(kTestProfileName));
+
+    // The feature engagement tracker does async initialization.
+    base::RunLoop().RunUntilIdle();
+    ASSERT_TRUE(feature_engagement_tracker_->IsInitialized());
+  }
+
+  void TearDown() override {
+    bookmark_tracker_->RemoveSessionDurationObserver();
+    testing_profile_manager_->DeleteTestingProfile(kTestProfileName);
+    testing_profile_manager_.reset();
+    metrics::DesktopSessionDurationTracker::CleanupForTesting();
+
+    // This is required to ensure each test can define its own params.
+    base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+  }
+
+  void SetFeatureParams(const base::Feature& feature,
+                        std::map<std::string, std::string> params) {
+    ASSERT_TRUE(
+        base::FieldTrialParamAssociator::GetInstance()
+            ->AssociateFieldTrialParams(trials_[feature.name]->trial_name(),
+                                        kGroupName, params));
+
+    std::map<std::string, std::string> actualParams;
+    EXPECT_TRUE(base::GetFieldTrialParamsByFeature(feature, &actualParams));
+    EXPECT_EQ(params, actualParams);
+  }
+
+ protected:
+  std::unique_ptr<FakeBookmarkTracker> bookmark_tracker_;
+  std::unique_ptr<Tracker> feature_engagement_tracker_;
+  variations::testing::VariationParamsManager params_manager_;
+
+ private:
+  std::unique_ptr<TestingProfileManager> testing_profile_manager_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+  content::TestBrowserThreadBundle thread_bundle_;
+  std::map<std::string, base::FieldTrial*> trials_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkTrackerTest);
+};
+
+}  // namespace
+
+// Tests to verify BookmarkFeatureEngagementTracker functional expectations:
+
+// Test that a promo is not shown if the user has a Bookmark. If
+// OnBookmarkAdded() is called, the ShouldShowPromo() should return false.
+TEST_F(BookmarkTrackerTest, TestShouldShowPromo) {
+  EXPECT_FALSE(bookmark_tracker_->ShouldShowPromo());
+
+  bookmark_tracker_->OnSessionTimeMet();
+
+  EXPECT_TRUE(bookmark_tracker_->ShouldShowPromo());
+
+  bookmark_tracker_->OnBookmarkAdded();
+
+  EXPECT_FALSE(bookmark_tracker_->ShouldShowPromo());
+}
+
+}  // namespace feature_engagement
diff --git a/chrome/browser/first_run/try_chrome_dialog_browsertest.cc b/chrome/browser/first_run/try_chrome_dialog_browsertest.cc
index 6cddc5ad..8434f4486 100644
--- a/chrome/browser/first_run/try_chrome_dialog_browsertest.cc
+++ b/chrome/browser/first_run/try_chrome_dialog_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/callback.h"
 #include "base/command_line.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -65,13 +66,15 @@
   // Provide a way to test flavors other than 0.
   TryChromeDialogTest() : dialog_(0) {}
 
-  static void DialogHandler(gfx::NativeWindow active_dialog) {}
+  // A noop listener for process singleton notifications.
+  static void SetProcessNotificationHandler(base::Closure handler) {}
 
   // DialogBrowserTest:
   void ShowDialog(const std::string& name) override {
-    dialog_.ShowDialog(base::Bind(&TryChromeDialogTest::DialogHandler),
-                       TryChromeDialog::DialogType::MODELESS_FOR_TEST,
-                       TryChromeDialog::UsageType::FOR_TESTING);
+    dialog_.ShowDialog(
+        base::Bind(&TryChromeDialogTest::SetProcessNotificationHandler),
+        TryChromeDialog::DialogType::MODELESS_FOR_TEST,
+        TryChromeDialog::UsageType::FOR_TESTING);
   }
 
   // content::BrowserTestBase:
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 487b1279..79533ad9 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -356,12 +356,6 @@
     "Attaches a warning UI to any password or credit card fields detected when "
     "the top-level page is not HTTPS";
 
-const char kEnableIdleTimeSpellCheckingName[] =
-    "Enable idle time spell checker";
-const char kEnableIdleTimeSpellCheckingDescription[] =
-    "Make spell-checking code run only when the browser is idle, so that input "
-    "latency is reduced, especially when editing long articles, emails, etc.";
-
 const char kEnableManualFallbacksFillingName[] =
     "Manual fallbacks for password manager forms filling";
 const char kEnableManualFallbacksFillingDescription[] =
@@ -716,6 +710,12 @@
     "conflict with the latest JavaScript features. This flag allows disabling "
     "support of those features for compatibility with such pages.";
 
+const char kKeepAliveRendererForKeepaliveRequestsName[] =
+    "Keep a renderer alive for keepalive fetch requests";
+const char kKeepAliveRendererForKeepaliveRequestsDescription[] =
+    "Keep a render process alive when the process has a pending fetch request "
+    "with `keepalive' specified.";
+
 const char kLcdTextName[] = "LCD text antialiasing";
 const char kLcdTextDescription[] =
     "If disabled, text is rendered with grayscale antialiasing instead of LCD "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 627c85b646..a5df45fa 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -238,9 +238,6 @@
 extern const char kEnableHttpFormWarningName[];
 extern const char kEnableHttpFormWarningDescription[];
 
-extern const char kEnableIdleTimeSpellCheckingName[];
-extern const char kEnableIdleTimeSpellCheckingDescription[];
-
 extern const char kEnableManualFallbacksFillingName[];
 extern const char kEnableManualFallbacksFillingDescription[];
 
@@ -450,6 +447,9 @@
 extern const char kJavascriptHarmonyShippingName[];
 extern const char kJavascriptHarmonyShippingDescription[];
 
+extern const char kKeepAliveRendererForKeepaliveRequestsName[];
+extern const char kKeepAliveRendererForKeepaliveRequestsDescription[];
+
 extern const char kLcdTextName[];
 extern const char kLcdTextDescription[];
 
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc b/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
deleted file mode 100644
index 5fc4c43f..0000000
--- a/chrome/browser/geolocation/geolocation_infobar_delegate_android.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/geolocation/geolocation_infobar_delegate_android.h"
-
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/grit/generated_resources.h"
-
-GeolocationInfoBarDelegateAndroid::GeolocationInfoBarDelegateAndroid(
-    const GURL& requesting_frame,
-    bool user_gesture,
-    Profile* profile,
-    const PermissionSetCallback& callback)
-    : PermissionInfoBarDelegate(requesting_frame,
-                                CONTENT_SETTINGS_TYPE_GEOLOCATION,
-                                user_gesture,
-                                profile,
-                                callback) {}
-
-GeolocationInfoBarDelegateAndroid::~GeolocationInfoBarDelegateAndroid() {}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-GeolocationInfoBarDelegateAndroid::GetIdentifier() const {
-  return GEOLOCATION_INFOBAR_DELEGATE_ANDROID;
-}
-
-int GeolocationInfoBarDelegateAndroid::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_GEOLOCATION;
-}
-
-int GeolocationInfoBarDelegateAndroid::GetMessageResourceId() const {
-  return IDS_GEOLOCATION_INFOBAR_QUESTION;
-}
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate_android.h b/chrome/browser/geolocation/geolocation_infobar_delegate_android.h
deleted file mode 100644
index 571a334..0000000
--- a/chrome/browser/geolocation/geolocation_infobar_delegate_android.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_GEOLOCATION_GEOLOCATION_INFOBAR_DELEGATE_ANDROID_H_
-#define CHROME_BROWSER_GEOLOCATION_GEOLOCATION_INFOBAR_DELEGATE_ANDROID_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
-
-// GeolocationInfoBarDelegateAndroids are created by the
-// PermissionQueueController to control the display
-// and handling of geolocation permission infobars to the user.
-class GeolocationInfoBarDelegateAndroid : public PermissionInfoBarDelegate {
- public:
-  GeolocationInfoBarDelegateAndroid(const GURL& requesting_frame,
-                                    bool user_gesture,
-                                    Profile* profile,
-                                    const PermissionSetCallback& callback);
-
- private:
-  ~GeolocationInfoBarDelegateAndroid() override;
-
-  // PermissionInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  int GetMessageResourceId() const override;
-
-  DISALLOW_COPY_AND_ASSIGN(GeolocationInfoBarDelegateAndroid);
-};
-
-#endif  // CHROME_BROWSER_GEOLOCATION_GEOLOCATION_INFOBAR_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/geolocation/geolocation_permission_context_android.cc b/chrome/browser/geolocation/geolocation_permission_context_android.cc
index 085f54401..e8ca06a 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_android.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_android.cc
@@ -85,6 +85,7 @@
     : GeolocationPermissionContext(profile),
       location_settings_(new LocationSettingsImpl()),
       permission_update_infobar_(nullptr),
+      location_settings_dialog_request_id_(0, 0, 0),
       weak_factory_(this) {}
 
 GeolocationPermissionContextAndroid::~GeolocationPermissionContextAndroid() {
@@ -184,11 +185,17 @@
 void GeolocationPermissionContextAndroid::CancelPermissionRequest(
     content::WebContents* web_contents,
     const PermissionRequestID& id) {
+  // TODO(timloh): This could cancel a infobar from an unrelated request.
   if (permission_update_infobar_) {
     permission_update_infobar_->RemoveSelf();
     permission_update_infobar_ = nullptr;
   }
 
+  if (id == location_settings_dialog_request_id_) {
+    location_settings_dialog_request_id_ = PermissionRequestID(0, 0, 0);
+    location_settings_dialog_callback_.Reset();
+  }
+
   GeolocationPermissionContext::CancelPermissionRequest(web_contents, id);
 }
 
@@ -239,9 +246,11 @@
 
     // Only show the location settings dialog if the tab for |web_contents| is
     // user-interactable (i.e. is the current tab, and Chrome is active and not
-    // in tab-switching mode).
+    // in tab-switching mode) and we're not already showing the LSD. The latter
+    // case can occur in split-screen multi-window.
     TabAndroid* tab = TabAndroid::FromWebContents(web_contents);
-    if (tab && !tab->IsUserInteractable()) {
+    if ((tab && !tab->IsUserInteractable()) ||
+        !location_settings_dialog_callback_.is_null()) {
       FinishNotifyPermissionSet(id, requesting_origin, embedding_origin,
                                 callback, false /* persist */,
                                 CONTENT_SETTING_BLOCK);
@@ -253,12 +262,14 @@
       return;
     }
 
+    location_settings_dialog_request_id_ = id;
+    location_settings_dialog_callback_ = callback;
     location_settings_->PromptToEnableSystemLocationSetting(
         is_default_search ? SEARCH : DEFAULT, web_contents,
         base::BindOnce(
             &GeolocationPermissionContextAndroid::OnLocationSettingsDialogShown,
-            weak_factory_.GetWeakPtr(), id, requesting_origin, embedding_origin,
-            callback, persist, content_setting));
+            weak_factory_.GetWeakPtr(), requesting_origin, embedding_origin,
+            persist, content_setting));
     return;
   }
 
@@ -448,10 +459,8 @@
 }
 
 void GeolocationPermissionContextAndroid::OnLocationSettingsDialogShown(
-    const PermissionRequestID& id,
     const GURL& requesting_origin,
     const GURL& embedding_origin,
-    const BrowserPermissionCallback& callback,
     bool persist,
     ContentSetting content_setting,
     LocationSettingsDialogOutcome prompt_outcome) {
@@ -470,8 +479,17 @@
     persist = false;
   }
 
-  FinishNotifyPermissionSet(id, requesting_origin, embedding_origin, callback,
-                            persist, content_setting);
+  // If the permission was cancelled while the LSD was up, the callback has
+  // already been dropped.
+  if (location_settings_dialog_callback_.is_null())
+    return;
+
+  FinishNotifyPermissionSet(
+      location_settings_dialog_request_id_, requesting_origin, embedding_origin,
+      location_settings_dialog_callback_, persist, content_setting);
+
+  location_settings_dialog_request_id_ = PermissionRequestID(0, 0, 0);
+  location_settings_dialog_callback_.Reset();
 }
 
 void GeolocationPermissionContextAndroid::FinishNotifyPermissionSet(
diff --git a/chrome/browser/geolocation/geolocation_permission_context_android.h b/chrome/browser/geolocation/geolocation_permission_context_android.h
index 74d2dac..563eef1 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_android.h
+++ b/chrome/browser/geolocation/geolocation_permission_context_android.h
@@ -27,6 +27,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/android/location_settings.h"
 #include "chrome/browser/geolocation/geolocation_permission_context.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "components/location/android/location_settings_dialog_context.h"
 #include "components/location/android/location_settings_dialog_outcome.h"
 
@@ -39,7 +40,6 @@
 }
 
 class GURL;
-class PermissionRequestID;
 class PrefRegistrySimple;
 
 class GeolocationPermissionContextAndroid
@@ -131,10 +131,8 @@
                                      bool ignore_backoff) const;
 
   void OnLocationSettingsDialogShown(
-      const PermissionRequestID& id,
       const GURL& requesting_origin,
       const GURL& embedding_origin,
-      const BrowserPermissionCallback& callback,
       bool persist,
       ContentSetting content_setting,
       LocationSettingsDialogOutcome prompt_outcome);
@@ -153,9 +151,16 @@
 
   std::unique_ptr<LocationSettings> location_settings_;
 
+  // We need to be able to clean up upon cancel requests for permissions
+  // currently showing a permission update infobars or location settings
+  // dialog, as the callback is invalid after a cancel.
+
   // This is owned by the InfoBarService (owner of the InfoBar).
   infobars::InfoBar* permission_update_infobar_;
 
+  PermissionRequestID location_settings_dialog_request_id_;
+  BrowserPermissionCallback location_settings_dialog_callback_;
+
   // Must be the last member, to ensure that it will be destroyed first, which
   // will invalidate weak pointers.
   base::WeakPtrFactory<GeolocationPermissionContextAndroid> weak_factory_;
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index 129efb8f..6acd3cb 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/containers/id_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/histogram_tester.h"
@@ -102,6 +103,9 @@
                                     const GURL& requesting_frame,
                                     bool user_gesture);
 
+  void CancelGeolocationPermission(content::WebContents* web_contents,
+                                   const PermissionRequestID& id);
+
   void PermissionResponse(const PermissionRequestID& id,
                           ContentSetting content_setting);
   void CheckPermissionMessageSent(int request_id, bool allowed);
@@ -173,6 +177,13 @@
   content::RunAllBlockingPoolTasksUntilIdle();
 }
 
+void GeolocationPermissionContextTests::CancelGeolocationPermission(
+    content::WebContents* web_contents,
+    const PermissionRequestID& id) {
+  geolocation_permission_context_->CancelPermissionRequest(web_contents, id);
+  content::RunAllBlockingPoolTasksUntilIdle();
+}
+
 void GeolocationPermissionContextTests::PermissionResponse(
     const PermissionRequestID& id,
     ContentSetting content_setting) {
@@ -812,6 +823,31 @@
   AddDayOffsetForTesting(7);
   EXPECT_TRUE(RequestPermissionIsLSDShown(requesting_frame));
 }
+
+TEST_F(GeolocationPermissionContextTests, CancelWithLSDOpen) {
+  GURL requesting_frame("https://www.example.com/geolocation");
+  NavigateAndCommit(requesting_frame);
+  RequestManagerDocumentLoadCompleted();
+  MockLocationSettings::SetLocationStatus(true /* android */,
+                                          false /* system */);
+  MockLocationSettings::SetLocationSettingsDialogStatus(true /* enabled */,
+                                                        GRANTED);
+  MockLocationSettings::SetAsyncLocationSettingsDialog();
+  EXPECT_FALSE(HasActivePrompt());
+  RequestGeolocationPermission(web_contents(), RequestID(0), requesting_frame,
+                               true);
+  ASSERT_TRUE(HasActivePrompt());
+  AcceptPrompt();
+
+  EXPECT_TRUE(MockLocationSettings::HasShownLocationSettingsDialog());
+
+  CancelGeolocationPermission(web_contents(), RequestID(0));
+  ASSERT_TRUE(responses_.empty());
+
+  MockLocationSettings::ResolveAsyncLocationSettingsDialog();
+  ASSERT_TRUE(responses_.empty());
+}
+
 #endif
 
 TEST_F(GeolocationPermissionContextTests, QueuedPermission) {
diff --git a/chrome/browser/history/web_history_service_factory.cc b/chrome/browser/history/web_history_service_factory.cc
index a63cedc..703aca7 100644
--- a/chrome/browser/history/web_history_service_factory.cc
+++ b/chrome/browser/history/web_history_service_factory.cc
@@ -7,19 +7,20 @@
 #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"
-#include "components/browser_sync/profile_sync_service.h"
 #include "components/history/core/browser/web_history_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
+#include "components/sync/driver/sync_service.h"
 #include "net/url_request/url_request_context_getter.h"
 
 namespace {
 // Returns true if the user is signed in and full history sync is enabled,
 // and false otherwise.
 bool IsHistorySyncEnabled(Profile* profile) {
-  browser_sync::ProfileSyncService* sync =
-      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
+  syncer::SyncService* sync =
+      ProfileSyncServiceFactory::GetInstance()->GetSyncServiceForBrowserContext(
+          profile);
   return sync && sync->IsSyncActive() && !sync->IsLocalSyncEnabled() &&
          sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES);
 }
diff --git a/chrome/browser/media/cdm_storage_id.cc b/chrome/browser/media/cdm_storage_id.cc
new file mode 100644
index 0000000..b88c801
--- /dev/null
+++ b/chrome/browser/media/cdm_storage_id.cc
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/cdm_storage_id.h"
+
+#include "base/callback.h"
+
+namespace cdm_storage_id {
+
+void ComputeStorageId(const std::vector<uint8_t>& salt,
+                      const url::Origin& origin,
+                      CdmStorageIdCallback callback) {
+  // Not implemented by default.
+  std::move(callback).Run(std::vector<uint8_t>());
+}
+
+}  // namespace cdm_storage_id
diff --git a/chrome/browser/media/cdm_storage_id.h b/chrome/browser/media/cdm_storage_id.h
new file mode 100644
index 0000000..3065c41e
--- /dev/null
+++ b/chrome/browser/media/cdm_storage_id.h
@@ -0,0 +1,31 @@
+// 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_MEDIA_CDM_STORAGE_ID_H_
+#define CHROME_BROWSER_MEDIA_CDM_STORAGE_ID_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "url/origin.h"
+
+// This handles computing the Storage Id for platform verification.
+namespace cdm_storage_id {
+
+using CdmStorageIdCallback =
+    base::OnceCallback<void(const std::vector<uint8_t>& storage_id)>;
+
+// Compute the Storage Id based on |salt| and |origin|. This may be
+// asynchronous, so call |callback| with the result. If Storage Id is not
+// supported on the current platform, an empty string will be passed to
+// |callback|.
+void ComputeStorageId(const std::vector<uint8_t>& salt,
+                      const url::Origin& origin,
+                      CdmStorageIdCallback callback);
+
+}  // namespace cdm_storage_id
+
+#endif  // CHROME_BROWSER_MEDIA_CDM_STORAGE_ID_H_
diff --git a/chrome/browser/media/media_storage_id_salt.cc b/chrome/browser/media/media_storage_id_salt.cc
new file mode 100644
index 0000000..4d51884e
--- /dev/null
+++ b/chrome/browser/media/media_storage_id_salt.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/media_storage_id_salt.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "crypto/random.h"
+
+namespace {
+
+const char kMediaStorageIdSalt[] = "media.storage_id_salt";
+
+}  // namespace
+
+std::vector<uint8_t> MediaStorageIdSalt::GetSalt(PrefService* pref_service) {
+  // Salt is stored as hex-encoded string.
+  std::string encoded_salt = pref_service->GetString(kMediaStorageIdSalt);
+  std::vector<uint8_t> salt;
+  if (encoded_salt.length() != kSaltLength * 2 ||
+      !base::HexStringToBytes(encoded_salt, &salt)) {
+    // If the salt is not the proper format log an error.
+    if (encoded_salt.length() > 0) {
+      DLOG(ERROR) << "Saved value for " << kMediaStorageIdSalt
+                  << " is not valid: " << encoded_salt;
+      // Continue on to generate a new one.
+    }
+
+    // If the salt doesn't exist, generate a new one.
+    salt.resize(kSaltLength);
+    crypto::RandBytes(salt.data(), salt.size());
+    encoded_salt = base::HexEncode(salt.data(), salt.size());
+    pref_service->SetString(kMediaStorageIdSalt, encoded_salt);
+  }
+
+  return salt;
+}
+
+void MediaStorageIdSalt::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(kMediaStorageIdSalt, std::string());
+}
diff --git a/chrome/browser/media/media_storage_id_salt.h b/chrome/browser/media/media_storage_id_salt.h
new file mode 100644
index 0000000..7b7e1dd8
--- /dev/null
+++ b/chrome/browser/media/media_storage_id_salt.h
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_MEDIA_STORAGE_ID_SALT_H_
+#define CHROME_BROWSER_MEDIA_MEDIA_STORAGE_ID_SALT_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+// MediaStorageIDSalt is responsible for creating and retrieving a salt string
+// that is used when creating Storage IDs.
+class MediaStorageIdSalt {
+ public:
+  enum { kSaltLength = 32 };
+
+  // Retrieves the current salt. If one does not currently exist it is created.
+  static std::vector<uint8_t> GetSalt(PrefService* pref_service);
+
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MediaStorageIdSalt);
+};
+
+#endif  // CHROME_BROWSER_MEDIA_MEDIA_STORAGE_ID_SALT_H_
diff --git a/chrome/browser/media/media_storage_id_salt_unittest.cc b/chrome/browser/media/media_storage_id_salt_unittest.cc
new file mode 100644
index 0000000..e644a2b6
--- /dev/null
+++ b/chrome/browser/media/media_storage_id_salt_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/media_storage_id_salt.h"
+
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const char kPrefsName[] = "media.storage_id_salt";
+
+TEST(MediaStorageIdSalt, Register) {
+  TestingPrefServiceSimple prefs;
+
+  MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
+}
+
+TEST(MediaStorageIdSalt, Create) {
+  TestingPrefServiceSimple prefs;
+
+  MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
+  std::vector<uint8_t> salt = MediaStorageIdSalt::GetSalt(&prefs);
+  EXPECT_EQ(MediaStorageIdSalt::kSaltLength, salt.size());
+}
+
+TEST(MediaStorageIdSalt, Recreate) {
+  TestingPrefServiceSimple prefs;
+
+  MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
+  std::vector<uint8_t> original_salt = MediaStorageIdSalt::GetSalt(&prefs);
+  EXPECT_EQ(MediaStorageIdSalt::kSaltLength, original_salt.size());
+
+  // Now that the salt is created, mess it up and then try fetching it again
+  // (should generate a new salt and log an error).
+  prefs.SetString(kPrefsName, "123");
+  std::vector<uint8_t> new_salt = MediaStorageIdSalt::GetSalt(&prefs);
+  EXPECT_EQ(MediaStorageIdSalt::kSaltLength, new_salt.size());
+  EXPECT_NE(original_salt, new_salt);
+}
+
+TEST(MediaStorageIdSalt, FetchTwice) {
+  TestingPrefServiceSimple prefs;
+
+  MediaStorageIdSalt::RegisterProfilePrefs(prefs.registry());
+  std::vector<uint8_t> salt1 = MediaStorageIdSalt::GetSalt(&prefs);
+  EXPECT_EQ(MediaStorageIdSalt::kSaltLength, salt1.size());
+
+  // Fetch the salt again. Should be the same value.
+  std::vector<uint8_t> salt2 = MediaStorageIdSalt::GetSalt(&prefs);
+  EXPECT_EQ(MediaStorageIdSalt::kSaltLength, salt2.size());
+  EXPECT_EQ(salt1, salt2);
+}
diff --git a/chrome/browser/media/midi_permission_infobar_delegate_android.cc b/chrome/browser/media/midi_permission_infobar_delegate_android.cc
deleted file mode 100644
index bf33bd7..0000000
--- a/chrome/browser/media/midi_permission_infobar_delegate_android.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/midi_permission_infobar_delegate_android.h"
-
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/grit/generated_resources.h"
-
-MidiPermissionInfoBarDelegateAndroid::MidiPermissionInfoBarDelegateAndroid(
-    const GURL& requesting_frame,
-    bool user_gesture,
-    Profile* profile,
-    const PermissionSetCallback& callback)
-    : PermissionInfoBarDelegate(requesting_frame,
-                                CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
-                                user_gesture,
-                                profile,
-                                callback) {}
-
-MidiPermissionInfoBarDelegateAndroid::~MidiPermissionInfoBarDelegateAndroid() {}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-MidiPermissionInfoBarDelegateAndroid::GetIdentifier() const {
-  return MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID;
-}
-
-int MidiPermissionInfoBarDelegateAndroid::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_MIDI;
-}
-
-int MidiPermissionInfoBarDelegateAndroid::GetMessageResourceId() const {
-  return IDS_MIDI_SYSEX_INFOBAR_QUESTION;
-}
diff --git a/chrome/browser/media/midi_permission_infobar_delegate_android.h b/chrome/browser/media/midi_permission_infobar_delegate_android.h
deleted file mode 100644
index 0eac2db..0000000
--- a/chrome/browser/media/midi_permission_infobar_delegate_android.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID_H_
-#define CHROME_BROWSER_MEDIA_MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
-
-// MidiPermissionInfoBarDelegateAndroids are created by the
-// MidiPermissionContext to control the display and handling of MIDI permission
-// infobars to the user.
-class MidiPermissionInfoBarDelegateAndroid : public PermissionInfoBarDelegate {
- public:
-  MidiPermissionInfoBarDelegateAndroid(const GURL& requesting_frame,
-                                       bool user_gesture,
-                                       Profile* profile,
-                                       const PermissionSetCallback& callback);
-
- private:
-  ~MidiPermissionInfoBarDelegateAndroid() override;
-
-  // ConfirmInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  int GetMessageResourceId() const override;
-
-  DISALLOW_COPY_AND_ASSIGN(MidiPermissionInfoBarDelegateAndroid);
-};
-
-#endif  // CHROME_BROWSER_MEDIA_MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/media/protected_media_identifier_infobar_delegate_android.cc b/chrome/browser/media/protected_media_identifier_infobar_delegate_android.cc
deleted file mode 100644
index 6720d7a..0000000
--- a/chrome/browser/media/protected_media_identifier_infobar_delegate_android.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/protected_media_identifier_infobar_delegate_android.h"
-
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/strings/grit/components_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-
-ProtectedMediaIdentifierInfoBarDelegateAndroid::
-    ProtectedMediaIdentifierInfoBarDelegateAndroid(
-        const GURL& requesting_frame,
-        bool user_gesture,
-        Profile* profile,
-        const PermissionSetCallback& callback)
-    : PermissionInfoBarDelegate(
-          requesting_frame,
-          CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
-          user_gesture,
-          profile,
-          callback) {}
-
-ProtectedMediaIdentifierInfoBarDelegateAndroid::
-    ~ProtectedMediaIdentifierInfoBarDelegateAndroid() {}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-ProtectedMediaIdentifierInfoBarDelegateAndroid::GetIdentifier() const {
-  return PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID;
-}
-
-int ProtectedMediaIdentifierInfoBarDelegateAndroid::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_PROTECTED_MEDIA_IDENTIFIER;
-}
-
-base::string16 ProtectedMediaIdentifierInfoBarDelegateAndroid::GetLinkText()
-    const {
-  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
-}
-
-GURL ProtectedMediaIdentifierInfoBarDelegateAndroid::GetLinkURL() const {
-  return GURL(chrome::kEnhancedPlaybackNotificationLearnMoreURL);
-}
-
-int ProtectedMediaIdentifierInfoBarDelegateAndroid::GetMessageResourceId()
-    const {
-  return IDS_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_QUESTION;
-}
diff --git a/chrome/browser/media/protected_media_identifier_infobar_delegate_android.h b/chrome/browser/media/protected_media_identifier_infobar_delegate_android.h
deleted file mode 100644
index db8983f..0000000
--- a/chrome/browser/media/protected_media_identifier_infobar_delegate_android.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID_H_
-#define CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
-
-class ProtectedMediaIdentifierInfoBarDelegateAndroid
-    : public PermissionInfoBarDelegate {
- public:
-  ProtectedMediaIdentifierInfoBarDelegateAndroid(
-      const GURL& requesting_frame,
-      bool user_gesture,
-      Profile* profile,
-      const PermissionSetCallback& callback);
-
- private:
-  ~ProtectedMediaIdentifierInfoBarDelegateAndroid() override;
-
-  // PermissionInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  base::string16 GetLinkText() const override;
-  GURL GetLinkURL() const override;
-  int GetMessageResourceId() const override;
-
-  DISALLOW_COPY_AND_ASSIGN(ProtectedMediaIdentifierInfoBarDelegateAndroid);
-};
-
-#endif  // CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/media/webrtc/media_stream_device_permission_context.cc b/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
index 477fa62..835265f 100644
--- a/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
+++ b/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
@@ -3,10 +3,8 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/media/webrtc/media_stream_device_permission_context.h"
-#include "base/feature_list.h"
 #include "chrome/browser/media/webrtc/media_stream_device_permissions.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
@@ -47,8 +45,6 @@
     const GURL& embedding_origin,
     bool user_gesture,
     const BrowserPermissionCallback& callback) {
-  DCHECK(base::FeatureList::IsEnabled(
-      features::kUsePermissionManagerForMediaRequests));
   PermissionContextBase::DecidePermission(web_contents, id, requesting_origin,
                                           embedding_origin, user_gesture,
                                           callback);
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
index 272e5cbb8..cc59ecc6f 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/callback_helpers.h"
@@ -12,7 +13,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
@@ -24,10 +24,8 @@
 #include "chrome/browser/permissions/permission_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -46,7 +44,6 @@
 
 #include "chrome/browser/android/android_theme_resources.h"
 #include "chrome/browser/android/preferences/pref_service_bridge.h"
-#include "chrome/browser/media/webrtc/media_stream_infobar_delegate_android.h"
 #include "chrome/browser/permissions/permission_dialog_delegate.h"
 #include "chrome/browser/permissions/permission_update_infobar_delegate_android.h"
 #include "ui/android/window_android.h"
@@ -74,32 +71,6 @@
   return false;
 }
 
-using PermissionActionCallback =
-    base::Callback<void(ContentSettingsType,
-                        PermissionRequestGestureType,
-                        const GURL&,
-                        Profile*)>;
-
-// Calls |action_callback| for each permission requested.
-void RecordPermissionAction(bool is_asking_for_audio,
-                            bool is_asking_for_video,
-                            const GURL& security_origin,
-                            Profile* profile,
-                            PermissionActionCallback action_callback) {
-  // TODO(stefanocs): Pass the actual |gesture_type| once this file has been
-  // refactored into PermissionContext.
-  if (is_asking_for_audio) {
-    action_callback.Run(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
-                        PermissionRequestGestureType::UNKNOWN, security_origin,
-                        profile);
-  }
-  if (is_asking_for_video) {
-    action_callback.Run(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
-                        PermissionRequestGestureType::UNKNOWN, security_origin,
-                        profile);
-  }
-}
-
 bool HasAvailableDevices(ContentSettingsType content_type,
                          const std::string& device_id) {
   const content::MediaStreamDevices* devices = nullptr;
@@ -124,159 +95,86 @@
   // Note: we check device_id before dereferencing devices. If the requested
   // device id is non-empty, then the corresponding device list must not be
   // NULL.
-  if (!device_id.empty() && !devices->FindById(device_id))
-    return false;
+  if (!device_id.empty()) {
+    auto it =
+        std::find_if(devices->begin(), devices->end(),
+                     [device_id](const content::MediaStreamDevice& device) {
+                       return device.id == device_id;
+                     });
+    if (it == devices->end())
+      return false;
+  }
 
   return true;
 }
 
 }  // namespace
 
-MediaStreamDevicesController::Request::Request(
-    Profile* profile,
-    bool is_asking_for_audio,
-    bool is_asking_for_video,
-    const GURL& security_origin,
-    PromptAnsweredCallback prompt_answered_callback)
-    : profile_(profile),
-      is_asking_for_audio_(is_asking_for_audio),
-      is_asking_for_video_(is_asking_for_video),
-      security_origin_(security_origin),
-      prompt_answered_callback_(prompt_answered_callback),
-      responded_(false) {}
-
-MediaStreamDevicesController::Request::~Request() {
-  if (!responded_) {
-    RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
-                           security_origin_, profile_,
-                           base::Bind(PermissionUmaUtil::PermissionIgnored));
-  }
-}
-
-bool MediaStreamDevicesController::Request::IsAskingForAudio() const {
-  return is_asking_for_audio_;
-}
-
-bool MediaStreamDevicesController::Request::IsAskingForVideo() const {
-  return is_asking_for_video_;
-}
-
-PermissionRequest::IconId MediaStreamDevicesController::Request::GetIconId()
-    const {
-#if defined(OS_ANDROID)
-  return IsAskingForVideo() ? IDR_ANDROID_INFOBAR_MEDIA_STREAM_CAMERA
-                            : IDR_ANDROID_INFOBAR_MEDIA_STREAM_MIC;
-#else
-  return IsAskingForVideo() ? vector_icons::kVideocamIcon
-                            : vector_icons::kMicrophoneIcon;
-#endif
-}
-
-#if defined(OS_ANDROID)
-base::string16 MediaStreamDevicesController::Request::GetMessageText() const {
-  int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO;
-  if (!IsAskingForAudio())
-    message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY;
-  else if (!IsAskingForVideo())
-    message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY;
-  return l10n_util::GetStringFUTF16(
-      message_id,
-      url_formatter::FormatUrlForSecurityDisplay(
-          GetOrigin(), url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
-}
-#endif
-
-base::string16 MediaStreamDevicesController::Request::GetMessageTextFragment()
-    const {
-  int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_PERMISSION_FRAGMENT;
-  if (!IsAskingForAudio())
-    message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT;
-  else if (!IsAskingForVideo())
-    message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT;
-  return l10n_util::GetStringUTF16(message_id);
-}
-
-GURL MediaStreamDevicesController::Request::GetOrigin() const {
-  return security_origin_;
-}
-
-void MediaStreamDevicesController::Request::PermissionGranted() {
-  RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
-                         security_origin_, profile_,
-                         base::Bind(PermissionUmaUtil::PermissionGranted));
-  responded_ = true;
-  prompt_answered_callback_.Run(CONTENT_SETTING_ALLOW, persist());
-}
-
-void MediaStreamDevicesController::Request::PermissionDenied() {
-  RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
-                         security_origin_, profile_,
-                         base::Bind(PermissionUmaUtil::PermissionDenied));
-  responded_ = true;
-  prompt_answered_callback_.Run(CONTENT_SETTING_BLOCK, persist());
-}
-
-void MediaStreamDevicesController::Request::Cancelled() {
-  RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
-                         security_origin_, profile_,
-                         base::Bind(PermissionUmaUtil::PermissionDismissed));
-  responded_ = true;
-  prompt_answered_callback_.Run(CONTENT_SETTING_ASK, false /* persist */);
-}
-
-void MediaStreamDevicesController::Request::RequestFinished() {
-  delete this;
-}
-
-PermissionRequestType
-MediaStreamDevicesController::Request::GetPermissionRequestType() const {
-  return PermissionRequestType::MEDIA_STREAM;
-}
-
-bool MediaStreamDevicesController::Request::ShouldShowPersistenceToggle()
-    const {
-  // Camera and Mic are handled the same w.r.t. showing the persistence toggle,
-  // just check camera here for simplicity (this class will be removed once the
-  // Android and media refactorings are finished).
-  return PermissionUtil::ShouldShowPersistenceToggle(
-      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
-}
-
-// Implementation of PermissionPromptDelegate which actually shows a permission
-// prompt.
-class MediaStreamDevicesController::PermissionPromptDelegateImpl
-    : public MediaStreamDevicesController::PermissionPromptDelegate {
- public:
-  void ShowPrompt(
-      bool user_gesture,
-      content::WebContents* web_contents,
-      std::unique_ptr<MediaStreamDevicesController::Request> request) override {
-#if defined(OS_ANDROID)
-    PermissionUmaUtil::RecordPermissionPromptShown(
-        request->GetPermissionRequestType(),
-        PermissionUtil::GetGestureType(user_gesture));
-    if (PermissionDialogDelegate::ShouldShowDialog()) {
-      PermissionDialogDelegate::CreateMediaStreamDialog(
-          web_contents, user_gesture, std::move(request));
-    } else {
-      MediaStreamInfoBarDelegateAndroid::Create(web_contents, user_gesture,
-                                                std::move(request));
-    }
-#else
-    PermissionRequestManager* permission_request_manager =
-        PermissionRequestManager::FromWebContents(web_contents);
-    if (permission_request_manager)
-      permission_request_manager->AddRequest(request.release());
-#endif
-  }
-};
-
 // static
 void MediaStreamDevicesController::RequestPermissions(
     const content::MediaStreamRequest& request,
     const content::MediaResponseCallback& callback) {
-  PermissionPromptDelegateImpl delegate;
-  RequestPermissionsWithDelegate(request, callback, &delegate);
+  content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
+      request.render_process_id, request.render_frame_id);
+  // The RFH may have been destroyed by the time the request is processed.
+  if (!rfh) {
+    callback.Run(content::MediaStreamDevices(),
+                 content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
+                 std::unique_ptr<content::MediaStreamUI>());
+    return;
+  }
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(rfh);
+  std::unique_ptr<MediaStreamDevicesController> controller(
+      new MediaStreamDevicesController(web_contents, request, callback));
+
+  // Show a prompt if needed.
+  bool is_asking_for_audio = controller->IsAskingForAudio();
+  bool is_asking_for_video = controller->IsAskingForVideo();
+  if (is_asking_for_audio || is_asking_for_video) {
+    Profile* profile =
+        Profile::FromBrowserContext(web_contents->GetBrowserContext());
+    std::vector<ContentSettingsType> content_settings_types;
+
+    if (is_asking_for_audio)
+      content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+    if (is_asking_for_video) {
+      content_settings_types.push_back(
+          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+    }
+
+    PermissionManager::Get(profile)->RequestPermissions(
+        content_settings_types, rfh, request.security_origin,
+        request.user_gesture,
+        base::Bind(&MediaStreamDevicesController::PromptAnsweredGroupedRequest,
+                   base::Passed(&controller)));
+    return;
+  }
+
+#if defined(OS_ANDROID)
+  // If either audio or video was previously allowed and Chrome no longer has
+  // the necessary permissions, show a infobar to attempt to address this
+  // mismatch.
+  std::vector<ContentSettingsType> content_settings_types;
+  if (controller->IsAllowedForAudio())
+    content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+
+  if (controller->IsAllowedForVideo()) {
+    content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+  }
+  if (!content_settings_types.empty() &&
+      PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar(
+          web_contents, content_settings_types)) {
+    PermissionUpdateInfoBarDelegate::Create(
+        web_contents, content_settings_types,
+        base::Bind(&MediaStreamDevicesController::AndroidOSPromptAnswered,
+                   base::Passed(&controller)));
+    return;
+  }
+#endif
+
+  // If we reach here, no prompt needed to be shown.
+  controller->RequestFinishedNoPrompt();
 }
 
 // static
@@ -304,38 +202,6 @@
   return video_setting_ == CONTENT_SETTING_ASK;
 }
 
-void MediaStreamDevicesController::PromptAnswered(ContentSetting setting,
-                                                  bool persist) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  HostContentSettingsMap* host_content_settings_map =
-      HostContentSettingsMapFactory::GetForProfile(profile_);
-  if (audio_setting_ == CONTENT_SETTING_ASK) {
-    if (persist && setting != CONTENT_SETTING_ASK) {
-      host_content_settings_map->SetContentSettingDefaultScope(
-          request_.security_origin, GURL(),
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting);
-    }
-    audio_setting_ = setting;
-  }
-
-  if (video_setting_ == CONTENT_SETTING_ASK) {
-    if (persist && setting != CONTENT_SETTING_ASK) {
-      host_content_settings_map->SetContentSettingDefaultScope(
-          request_.security_origin, GURL(),
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting);
-    }
-    video_setting_ = setting;
-  }
-
-  if (setting == CONTENT_SETTING_BLOCK)
-    denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED;
-  else if (setting == CONTENT_SETTING_ASK)
-    denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DISMISSED;
-
-  RunCallback();
-}
-
 void MediaStreamDevicesController::PromptAnsweredGroupedRequest(
     const std::vector<ContentSetting>& responses) {
   DCHECK(responses.size() == 1 || responses.size() == 2);
@@ -382,87 +248,6 @@
   RunCallback();
 }
 
-// static
-void MediaStreamDevicesController::RequestPermissionsWithDelegate(
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback,
-    PermissionPromptDelegate* delegate) {
-  content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
-      request.render_process_id, request.render_frame_id);
-  // The RFH may have been destroyed by the time the request is processed.
-  if (!rfh) {
-    callback.Run(content::MediaStreamDevices(),
-                 content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
-                 std::unique_ptr<content::MediaStreamUI>());
-    return;
-  }
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(rfh);
-  std::unique_ptr<MediaStreamDevicesController> controller(
-      new MediaStreamDevicesController(web_contents, request, callback));
-
-  // Show a prompt if needed.
-  bool is_asking_for_audio = controller->IsAskingForAudio();
-  bool is_asking_for_video = controller->IsAskingForVideo();
-  if (is_asking_for_audio || is_asking_for_video) {
-    Profile* profile =
-        Profile::FromBrowserContext(web_contents->GetBrowserContext());
-    if (base::FeatureList::IsEnabled(
-            features::kUsePermissionManagerForMediaRequests) &&
-        PermissionRequestManager::IsEnabled()) {
-      std::vector<ContentSettingsType> content_settings_types;
-
-      if (is_asking_for_audio)
-        content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
-      if (is_asking_for_video) {
-        content_settings_types.push_back(
-            CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
-      }
-
-      PermissionManager::Get(profile)->RequestPermissions(
-          content_settings_types, rfh, request.security_origin,
-          request.user_gesture,
-          base::Bind(
-              &MediaStreamDevicesController::PromptAnsweredGroupedRequest,
-              base::Passed(&controller)));
-    } else {
-      delegate->ShowPrompt(
-          request.user_gesture, web_contents,
-          base::MakeUnique<Request>(
-              profile, is_asking_for_audio, is_asking_for_video,
-              request.security_origin,
-              base::Bind(&MediaStreamDevicesController::PromptAnswered,
-                         base::Passed(&controller))));
-    }
-    return;
-  }
-
-#if defined(OS_ANDROID)
-  // If either audio or video was previously allowed and Chrome no longer has
-  // the necessary permissions, show a infobar to attempt to address this
-  // mismatch.
-  std::vector<ContentSettingsType> content_settings_types;
-  if (controller->IsAllowedForAudio())
-    content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
-
-  if (controller->IsAllowedForVideo()) {
-    content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
-  }
-  if (!content_settings_types.empty() &&
-      PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar(
-          web_contents, content_settings_types)) {
-    PermissionUpdateInfoBarDelegate::Create(
-        web_contents, content_settings_types,
-        base::Bind(&MediaStreamDevicesController::AndroidOSPromptAnswered,
-                   base::Passed(&controller)));
-    return;
-  }
-#endif
-
-  // If we reach here, no prompt needed to be shown.
-  controller->RequestFinishedNoPrompt();
-}
-
 MediaStreamDevicesController::MediaStreamDevicesController(
     content::WebContents* web_contents,
     const content::MediaStreamRequest& request,
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.h b/chrome/browser/media/webrtc/media_stream_devices_controller.h
index 74013cb..034a830 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller.h
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller.h
@@ -8,10 +8,10 @@
 #include <map>
 #include <string>
 
+#include "base/callback.h"
 #include "base/macros.h"
-#include "chrome/browser/permissions/permission_request.h"
 #include "components/content_settings/core/common/content_settings.h"
-#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/common/media_stream_request.h"
 
 class MediaStreamDevicesController;
 class Profile;
@@ -35,67 +35,6 @@
 
 class MediaStreamDevicesController {
  public:
-  // This class is only needed until we unify the codepaths for permission
-  // requests. It can be removed once crbug.com/606138 is fixed.
-  class Request : public PermissionRequest {
-   public:
-    using PromptAnsweredCallback =
-        base::Callback<void(ContentSetting, bool /* persist */)>;
-
-    Request(Profile* profile,
-            bool is_asking_for_audio,
-            bool is_asking_for_video,
-            const GURL& security_origin,
-            PromptAnsweredCallback prompt_answered_callback);
-
-    ~Request() override;
-
-    bool IsAskingForAudio() const;
-    bool IsAskingForVideo() const;
-
-    // PermissionRequest:
-    IconId GetIconId() const override;
-#if defined(OS_ANDROID)
-    base::string16 GetMessageText() const override;
-#endif
-    base::string16 GetMessageTextFragment() const override;
-    GURL GetOrigin() const override;
-    void PermissionGranted() override;
-    void PermissionDenied() override;
-    void Cancelled() override;
-    void RequestFinished() override;
-    PermissionRequestType GetPermissionRequestType() const override;
-    bool ShouldShowPersistenceToggle() const override;
-
-   private:
-    Profile* profile_;
-
-    bool is_asking_for_audio_;
-    bool is_asking_for_video_;
-
-    GURL security_origin_;
-
-    PromptAnsweredCallback prompt_answered_callback_;
-
-    // Whether the prompt has been answered.
-    bool responded_;
-
-    DISALLOW_COPY_AND_ASSIGN(Request);
-  };
-
-  // This class is only needed interally and for tests. It can be removed once
-  // crbug.com/606138 is fixed. Delegate for showing permission prompts. It's
-  // only public because subclassing from a friend class doesn't work in gcc
-  // (see https://codereview.chromium.org/2768923003).
-  class PermissionPromptDelegate {
-   public:
-    virtual void ShowPrompt(
-        bool user_gesture,
-        content::WebContents* web_contents,
-        std::unique_ptr<MediaStreamDevicesController::Request> request) = 0;
-    virtual ~PermissionPromptDelegate() {}
-  };
-
   static void RequestPermissions(
       const content::MediaStreamRequest& request,
       const content::MediaResponseCallback& callback);
@@ -108,11 +47,6 @@
   bool IsAskingForAudio() const;
   bool IsAskingForVideo() const;
 
-  // Called when a permission prompt has been answered, with the |response| and
-  // whether the choice should be persisted.
-  // TODO(raymes): Remove this once crbug.com/606138 is fixed.
-  void PromptAnswered(ContentSetting response, bool persist);
-
   // Called when a permission prompt is answered through the PermissionManager.
   void PromptAnsweredGroupedRequest(
       const std::vector<ContentSetting>& responses);
@@ -130,13 +64,6 @@
   friend class test::MediaStreamDevicesControllerTestApi;
   friend class policy::MediaStreamDevicesControllerBrowserTest;
 
-  class PermissionPromptDelegateImpl;
-
-  static void RequestPermissionsWithDelegate(
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback,
-      PermissionPromptDelegate* delegate);
-
   MediaStreamDevicesController(content::WebContents* web_contents,
                                const content::MediaStreamRequest& request,
                                const content::MediaResponseCallback& callback);
@@ -192,8 +119,6 @@
   // audio/video devices was granted or not.
   content::MediaResponseCallback callback_;
 
-  std::unique_ptr<PermissionPromptDelegate> delegate_;
-
   DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesController);
 };
 
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
index 071684c..71c2a04 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
@@ -25,68 +24,18 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/prefs/pref_service.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/media_stream_request.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-enum class TestType {
-  DEFAULT,
-  TEST_WITH_GROUPED_MEDIA_REQUESTS,
-};
-
-class MediaStreamDevicesControllerTest
-    : public WebRtcTestBase,
-      public ::testing::WithParamInterface<TestType> {
+class MediaStreamDevicesControllerTest : public WebRtcTestBase {
  public:
-  // TODO(raymes): When crbug.com/606138 is finished and the
-  // PermissionRequestManager is used to show all prompts on Android/Desktop
-  // we should remove PermissionPromptDelegate and just use
-  // MockPermissionPromptFactory instead. The APIs are the same.
-  class TestPermissionPromptDelegate
-      : public MediaStreamDevicesController::PermissionPromptDelegate {
-   public:
-    void ShowPrompt(bool user_gesture,
-                    content::WebContents* web_contents,
-                    std::unique_ptr<MediaStreamDevicesController::Request>
-                        request) override {
-      if (request->IsAskingForAudio())
-        last_requests_.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
-      if (request->IsAskingForVideo())
-        last_requests_.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
-
-      if (response_type_ == PermissionRequestManager::ACCEPT_ALL)
-        request->PermissionGranted();
-      else if (response_type_ == PermissionRequestManager::DENY_ALL)
-        request->PermissionDenied();
-    }
-
-    void set_response_type(
-        PermissionRequestManager::AutoResponseType response_type) {
-      response_type_ = response_type;
-    }
-
-    size_t TotalRequestCount() { return last_requests_.size(); }
-
-    bool WasRequested(ContentSettingsType type) {
-      return base::ContainsValue(last_requests_, type);
-    }
-
-    void Reset() { last_requests_.clear(); }
-
-   private:
-    PermissionRequestManager::AutoResponseType response_type_ =
-        PermissionRequestManager::NONE;
-    std::vector<ContentSettingsType> last_requests_;
-  };
-
   MediaStreamDevicesControllerTest()
       : example_audio_id_("fake_audio_dev"),
         example_video_id_("fake_video_dev"),
@@ -125,8 +74,7 @@
     base::RunLoop run_loop;
     ASSERT_TRUE(quit_closure_.is_null());
     quit_closure_ = run_loop.QuitClosure();
-    MediaStreamDevicesController::RequestPermissionsWithDelegate(
-        request, callback, &prompt_delegate_);
+    MediaStreamDevicesController::RequestPermissions(request, callback);
     run_loop.Run();
   }
 
@@ -211,68 +159,19 @@
               GetContentSettings()->GetMicrophoneCameraState());
   }
 
-  void SetPromptResponseType(
-      PermissionRequestManager::AutoResponseType response_type) {
-    if (base::FeatureList::IsEnabled(
-            features::kUsePermissionManagerForMediaRequests)) {
-      prompt_factory_->set_response_type(response_type);
-    } else {
-      prompt_delegate_.set_response_type(response_type);
-    }
-  }
-
-  size_t TotalPromptRequestCount() {
-    if (base::FeatureList::IsEnabled(
-            features::kUsePermissionManagerForMediaRequests)) {
-      return prompt_factory_->TotalRequestCount();
-    } else {
-      return prompt_delegate_.TotalRequestCount();
-    }
-  }
-
-  bool WasPermissionShown(ContentSettingsType type) {
-    if (base::FeatureList::IsEnabled(
-            features::kUsePermissionManagerForMediaRequests)) {
-      if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
-        return prompt_factory_->RequestTypeSeen(
-            PermissionRequestType::PERMISSION_MEDIASTREAM_MIC);
-      } else if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
-        return prompt_factory_->RequestTypeSeen(
-            PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA);
-      } else {
-        NOTREACHED();
-        return false;
-      }
-    } else {
-      return prompt_delegate_.WasRequested(type);
-    }
-  }
-
-  void ResetPromptCounters() {
-    if (base::FeatureList::IsEnabled(
-            features::kUsePermissionManagerForMediaRequests)) {
-      prompt_factory_->ResetCounts();
-    } else {
-      prompt_delegate_.Reset();
-    }
+  MockPermissionPromptFactory* prompt_factory() {
+    return prompt_factory_.get();
   }
 
  private:
   void SetUpOnMainThread() override {
     WebRtcTestBase::SetUpOnMainThread();
 
-    if (GetParam() == TestType::TEST_WITH_GROUPED_MEDIA_REQUESTS) {
-      scoped_feature_list_.InitAndEnableFeature(
-          features::kUsePermissionManagerForMediaRequests);
-      PermissionRequestManager* manager =
-          PermissionRequestManager::FromWebContents(
-              browser()->tab_strip_model()->GetActiveWebContents());
-      prompt_factory_.reset(new MockPermissionPromptFactory(manager));
-      manager->DisplayPendingRequests();
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          features::kUsePermissionManagerForMediaRequests);
-    }
+    PermissionRequestManager* manager =
+        PermissionRequestManager::FromWebContents(
+            browser()->tab_strip_model()->GetActiveWebContents());
+    prompt_factory_.reset(new MockPermissionPromptFactory(manager));
+    manager->DisplayPendingRequests();
 
     // Cleanup.
     media_stream_devices_.clear();
@@ -310,19 +209,16 @@
 
   base::Closure quit_closure_;
 
-  TestPermissionPromptDelegate prompt_delegate_;
   std::unique_ptr<MockPermissionPromptFactory> prompt_factory_;
-
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 // Request and allow microphone access.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest, RequestAndAllowMic) {
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, RequestAndAllowMic) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_ALLOWED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), std::string()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -345,12 +241,12 @@
 }
 
 // Request and allow camera access.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest, RequestAndAllowCam) {
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, RequestAndAllowCam) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_ALLOWED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(std::string(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -373,12 +269,12 @@
 }
 
 // Request and block microphone access.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest, RequestAndBlockMic) {
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, RequestAndBlockMic) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_DENIED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), std::string()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -402,12 +298,12 @@
 }
 
 // Request and block camera access.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest, RequestAndBlockCam) {
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, RequestAndBlockCam) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_DENIED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(std::string(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -431,14 +327,14 @@
 }
 
 // Request and allow microphone and camera access.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        RequestAndAllowMicCam) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_ALLOWED);
   SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_ALLOWED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -466,14 +362,14 @@
 }
 
 // Request and block microphone and camera access.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        RequestAndBlockMicCam) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_DENIED);
   SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_DENIED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -503,14 +399,14 @@
 }
 
 // Request microphone and camera access. Allow microphone, block camera.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        RequestMicCamBlockCam) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_ALLOWED);
   SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_DENIED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -539,14 +435,14 @@
 }
 
 // Request microphone and camera access. Block microphone, allow camera.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        RequestMicCamBlockMic) {
   InitWithUrl(GURL("https://www.example.com"));
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_DENIED);
   SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_ALLOWED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -576,14 +472,14 @@
 
 // Request microphone access. Requesting camera should not change microphone
 // state.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        RequestCamDoesNotChangeMic) {
   InitWithUrl(GURL("https://www.example.com"));
   // Request mic and deny.
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_DENIED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), std::string()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -624,14 +520,14 @@
 }
 
 // Denying mic access after camera access should still show the camera as state.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        DenyMicDoesNotChangeCam) {
   InitWithUrl(GURL("https://www.example.com"));
   // Request cam and allow
   SetDevicePolicy(DEVICE_TYPE_VIDEO, ACCESS_ALLOWED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(std::string(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -648,10 +544,10 @@
             GetContentSettings()->GetMicrophoneCameraState());
 
   // Simulate that an a video stream is now being captured.
-  content::MediaStreamDevice fake_video_device(
-      content::MEDIA_DEVICE_VIDEO_CAPTURE, example_video_id(),
-      example_video_id());
-  content::MediaStreamDevices video_devices(1, fake_video_device);
+  content::MediaStreamDevices video_devices(1);
+  video_devices[0] =
+      content::MediaStreamDevice(content::MEDIA_DEVICE_VIDEO_CAPTURE,
+                                 example_video_id(), example_video_id());
   MediaCaptureDevicesDispatcher* dispatcher =
       MediaCaptureDevicesDispatcher::GetInstance();
   dispatcher->SetTestVideoCaptureDevices(video_devices);
@@ -664,7 +560,7 @@
   SetDevicePolicy(DEVICE_TYPE_AUDIO, ACCESS_DENIED);
   // Ensure the prompt is accepted if necessary such that tab specific content
   // settings are updated.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), std::string()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
@@ -736,7 +632,7 @@
 
 // Test all combinations of cam/mic content settings. Then tests the result of
 // clicking both accept/deny on the infobar. Both cam/mic are requested.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest, ContentSettings) {
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, ContentSettings) {
   InitWithUrl(GURL("https://www.example.com"));
   static const ContentSettingsTestData tests[] = {
       // Settings that won't result in an infobar.
@@ -765,28 +661,31 @@
   for (auto& test : tests) {
     SetContentSettings(test.mic, test.cam);
 
-    ResetPromptCounters();
+    prompt_factory()->ResetCounts();
 
     // Accept or deny the infobar if it's showing.
     if (test.ExpectMicInfobar() || test.ExpectCamInfobar()) {
       if (test.accept_infobar) {
-        SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+        prompt_factory()->set_response_type(
+            PermissionRequestManager::ACCEPT_ALL);
       } else {
-        SetPromptResponseType(PermissionRequestManager::DENY_ALL);
+        prompt_factory()->set_response_type(PermissionRequestManager::DENY_ALL);
       }
     } else {
-      SetPromptResponseType(PermissionRequestManager::NONE);
+      prompt_factory()->set_response_type(PermissionRequestManager::NONE);
     }
     RequestPermissions(
         GetWebContents(), CreateRequest(example_audio_id(), example_video_id()),
         base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
                    base::Unretained(this)));
 
-    ASSERT_LE(TotalPromptRequestCount(), 2u);
+    ASSERT_LE(prompt_factory()->TotalRequestCount(), 2);
     ASSERT_EQ(test.ExpectMicInfobar(),
-              WasPermissionShown(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+              prompt_factory()->RequestTypeSeen(
+                  PermissionRequestType::PERMISSION_MEDIASTREAM_MIC));
     ASSERT_EQ(test.ExpectCamInfobar(),
-              WasPermissionShown(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+              prompt_factory()->RequestTypeSeen(
+                  PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA));
 
     // Check the media stream result is expected and the devices returned are
     // expected;
@@ -799,7 +698,7 @@
 }
 
 // Request and allow camera access on WebUI pages without prompting.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        WebUIRequestAndAllowCam) {
   InitWithUrl(GURL("chrome://test-page"));
   RequestPermissions(
@@ -807,25 +706,27 @@
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
                  base::Unretained(this)));
 
-  ASSERT_EQ(0u, TotalPromptRequestCount());
+  ASSERT_EQ(0, prompt_factory()->TotalRequestCount());
 
   ASSERT_EQ(content::MEDIA_DEVICE_OK, media_stream_result());
   ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
   ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        ExtensionRequestMicCam) {
   InitWithUrl(GURL("chrome-extension://test-page"));
   // Test that a prompt is required.
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
                  base::Unretained(this)));
-  ASSERT_EQ(2u, TotalPromptRequestCount());
-  ASSERT_TRUE(WasPermissionShown(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
-  ASSERT_TRUE(WasPermissionShown(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_EQ(2, prompt_factory()->TotalRequestCount());
+  ASSERT_TRUE(prompt_factory()->RequestTypeSeen(
+      PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA));
+  ASSERT_TRUE(prompt_factory()->RequestTypeSeen(
+      PermissionRequestType::PERMISSION_MEDIASTREAM_MIC));
 
   // Accept the prompt.
   ASSERT_EQ(content::MEDIA_DEVICE_OK, media_stream_result());
@@ -833,44 +734,41 @@
   ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 
   // Check that re-requesting allows without prompting.
-  ResetPromptCounters();
+  prompt_factory()->ResetCounts();
   RequestPermissions(
       GetWebContents(), CreateRequest(example_audio_id(), example_video_id()),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
                  base::Unretained(this)));
-  ASSERT_EQ(0u, TotalPromptRequestCount());
+  ASSERT_EQ(0, prompt_factory()->TotalRequestCount());
 
   ASSERT_EQ(content::MEDIA_DEVICE_OK, media_stream_result());
   ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
   ASSERT_TRUE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        PepperRequestInsecure) {
   InitWithUrl(GURL("http://www.example.com"));
 
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
 
-  ResetPromptCounters();
   RequestPermissions(
       GetWebContents(),
       CreateRequestWithType(example_audio_id(), example_video_id(),
                             content::MEDIA_OPEN_DEVICE_PEPPER_ONLY),
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
                  base::Unretained(this)));
-  ASSERT_EQ(0u, TotalPromptRequestCount());
+  ASSERT_EQ(0, prompt_factory()->TotalRequestCount());
 
   ASSERT_EQ(content::MEDIA_DEVICE_PERMISSION_DENIED, media_stream_result());
   ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
   ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest, WebContentsDestroyed) {
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, WebContentsDestroyed) {
   InitWithUrl(GURL("http://www.example.com"));
 
-  SetPromptResponseType(PermissionRequestManager::ACCEPT_ALL);
-
-  ResetPromptCounters();
+  prompt_factory()->set_response_type(PermissionRequestManager::ACCEPT_ALL);
 
   content::MediaStreamRequest request =
       CreateRequest(example_audio_id(), example_video_id());
@@ -882,7 +780,7 @@
       nullptr, request,
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
                  base::Unretained(this)));
-  ASSERT_EQ(0u, TotalPromptRequestCount());
+  ASSERT_EQ(0, prompt_factory()->TotalRequestCount());
 
   ASSERT_EQ(content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
             media_stream_result());
@@ -891,7 +789,7 @@
 }
 
 // Request and block microphone and camera access with kill switch.
-IN_PROC_BROWSER_TEST_P(MediaStreamDevicesControllerTest,
+IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
                        RequestAndKillSwitchMicCam) {
   std::map<std::string, std::string> params;
   params[PermissionUtil::GetPermissionString(
@@ -914,15 +812,9 @@
       base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse,
                  base::Unretained(this)));
 
-  ASSERT_EQ(0u, TotalPromptRequestCount());
+  ASSERT_EQ(0, prompt_factory()->TotalRequestCount());
 
   ASSERT_EQ(content::MEDIA_DEVICE_KILL_SWITCH_ON, media_stream_result());
   ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE));
   ASSERT_FALSE(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE));
 }
-
-INSTANTIATE_TEST_CASE_P(
-    MediaStreamDevicesControllerTestInstance,
-    MediaStreamDevicesControllerTest,
-    ::testing::Values(TestType::DEFAULT,
-                      TestType::TEST_WITH_GROUPED_MEDIA_REQUESTS));
diff --git a/chrome/browser/media/webrtc/media_stream_infobar_delegate_android.cc b/chrome/browser/media/webrtc/media_stream_infobar_delegate_android.cc
deleted file mode 100644
index 6b1d84d..0000000
--- a/chrome/browser/media/webrtc/media_stream_infobar_delegate_android.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/webrtc/media_stream_infobar_delegate_android.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/permissions/permission_uma_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/content_settings/core/common/content_settings_types.h"
-#include "components/google/core/browser/google_util.h"
-#include "components/infobars/core/infobar.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/origin_util.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-
-namespace {
-
-void DoNothing(bool update_content_setting, PermissionAction decision) {}
-
-}  // namespace
-
-// static
-bool MediaStreamInfoBarDelegateAndroid::Create(
-    content::WebContents* web_contents,
-    bool user_gesture,
-    std::unique_ptr<MediaStreamDevicesController::Request> request) {
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents);
-  if (!infobar_service) {
-    // Deny the request if there is no place to show the infobar, e.g. when
-    // the request comes from a background extension page.
-    request->Cancelled();
-    return false;
-  }
-
-  std::unique_ptr<infobars::InfoBar> infobar(
-      CreatePermissionInfoBar(std::unique_ptr<PermissionInfoBarDelegate>(
-          new MediaStreamInfoBarDelegateAndroid(
-              Profile::FromBrowserContext(web_contents->GetBrowserContext()),
-              user_gesture, std::move(request)))));
-  for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
-    infobars::InfoBar* old_infobar = infobar_service->infobar_at(i);
-    if (old_infobar->delegate()->AsMediaStreamInfoBarDelegateAndroid()) {
-      infobar_service->ReplaceInfoBar(old_infobar, std::move(infobar));
-      return true;
-    }
-  }
-  infobar_service->AddInfoBar(std::move(infobar));
-  return true;
-}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-MediaStreamInfoBarDelegateAndroid::GetIdentifier() const {
-  return MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID;
-}
-
-infobars::InfoBarDelegate::Type
-MediaStreamInfoBarDelegateAndroid::GetInfoBarType() const {
-  return PAGE_ACTION_TYPE;
-}
-
-int MediaStreamInfoBarDelegateAndroid::GetIconId() const {
-  return request_->IsAskingForVideo() ? IDR_ANDROID_INFOBAR_MEDIA_STREAM_CAMERA
-                                      : IDR_ANDROID_INFOBAR_MEDIA_STREAM_MIC;
-}
-
-MediaStreamInfoBarDelegateAndroid::MediaStreamInfoBarDelegateAndroid(
-    Profile* profile,
-    bool user_gesture,
-    std::unique_ptr<MediaStreamDevicesController::Request> request)
-    : PermissionInfoBarDelegate(
-          request->GetOrigin(),
-          // The content setting type and permission type here are only passed
-          // in to fit into PermissionInfoBarDelegate, even though media infobar
-          // controls both mic and camera. This is a temporary state for easy
-          // refactoring.
-          // TODO(lshang): Merge MediaStreamInfoBarDelegateAndroid into
-          // GroupedPermissionInfoBarDelegate. See crbug.com/606138.
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
-          user_gesture,
-          profile,
-          // This is only passed in to fit into PermissionInfoBarDelegate.
-          // Infobar accepted/denied/dismissed is handled by |request|, not via
-          // callbacks.
-          base::Bind(&DoNothing)),
-      request_(std::move(request)) {
-  DCHECK(request_.get());
-  DCHECK(request_->IsAskingForAudio() || request_->IsAskingForVideo());
-}
-
-MediaStreamInfoBarDelegateAndroid::~MediaStreamInfoBarDelegateAndroid() {}
-
-void MediaStreamInfoBarDelegateAndroid::InfoBarDismissed() {
-  // Deny the request if the infobar was closed with the 'x' button, since
-  // we don't want WebRTC to be waiting for an answer that will never come.
-  request_->Cancelled();
-}
-
-MediaStreamInfoBarDelegateAndroid*
-MediaStreamInfoBarDelegateAndroid::AsMediaStreamInfoBarDelegateAndroid() {
-  return this;
-}
-
-base::string16 MediaStreamInfoBarDelegateAndroid::GetMessageText() const {
-  return request_->GetMessageText();
-}
-
-base::string16 MediaStreamInfoBarDelegateAndroid::GetButtonLabel(
-    InfoBarButton button) const {
-  switch (button) {
-    case BUTTON_OK:
-      return l10n_util::GetStringUTF16(IDS_MEDIA_CAPTURE_ALLOW);
-    case BUTTON_CANCEL:
-      return l10n_util::GetStringUTF16(IDS_MEDIA_CAPTURE_BLOCK);
-    default:
-      NOTREACHED();
-      return base::string16();
-  }
-}
-
-int MediaStreamInfoBarDelegateAndroid::GetMessageResourceId() const {
-  if (!request_->IsAskingForAudio())
-    return IDS_MEDIA_CAPTURE_VIDEO_ONLY;
-  else if (!request_->IsAskingForVideo())
-    return IDS_MEDIA_CAPTURE_AUDIO_ONLY;
-  return IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO;
-}
-
-bool MediaStreamInfoBarDelegateAndroid::Accept() {
-  // TODO(dominickn): fold these metrics calls into
-  // PermissionUmaUtil::PermissionGranted. See crbug.com/638076.
-  PermissionUmaUtil::RecordPermissionPromptAccepted(
-      request_->GetPermissionRequestType(),
-      PermissionUtil::GetGestureType(user_gesture()));
-
-  bool persist_permission = true;
-  if (ShouldShowPersistenceToggle()) {
-    persist_permission = persist();
-
-    if (request_->IsAskingForAudio()) {
-      PermissionUmaUtil::PermissionPromptAcceptedWithPersistenceToggle(
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, persist_permission);
-    }
-    if (request_->IsAskingForVideo()) {
-      PermissionUmaUtil::PermissionPromptAcceptedWithPersistenceToggle(
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, persist_permission);
-    }
-  }
-
-  request_->set_persist(persist_permission);
-  request_->PermissionGranted();
-  return true;
-}
-
-bool MediaStreamInfoBarDelegateAndroid::Cancel() {
-  // TODO(dominickn): fold these metrics calls into
-  // PermissionUmaUtil::PermissionDenied. See crbug.com/638076.
-  PermissionUmaUtil::RecordPermissionPromptDenied(
-      request_->GetPermissionRequestType(),
-      PermissionUtil::GetGestureType(user_gesture()));
-
-  bool persist_permission = true;
-  if (ShouldShowPersistenceToggle()) {
-    persist_permission = persist();
-
-    if (request_->IsAskingForAudio()) {
-      PermissionUmaUtil::PermissionPromptDeniedWithPersistenceToggle(
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, persist_permission);
-    }
-    if (request_->IsAskingForVideo()) {
-      PermissionUmaUtil::PermissionPromptDeniedWithPersistenceToggle(
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, persist_permission);
-    }
-  }
-  request_->set_persist(persist_permission);
-  request_->PermissionDenied();
-  return true;
-}
-
-base::string16 MediaStreamInfoBarDelegateAndroid::GetLinkText() const {
-  return base::string16();
-}
-
-GURL MediaStreamInfoBarDelegateAndroid::GetLinkURL() const {
-  return GURL(chrome::kMediaAccessLearnMoreUrl);
-}
-
-std::vector<int> MediaStreamInfoBarDelegateAndroid::content_settings_types()
-    const {
-  std::vector<int> types;
-  if (request_->IsAskingForAudio())
-    types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
-  if (request_->IsAskingForVideo())
-    types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
-  return types;
-}
diff --git a/chrome/browser/media/webrtc/media_stream_infobar_delegate_android.h b/chrome/browser/media/webrtc/media_stream_infobar_delegate_android.h
deleted file mode 100644
index 3caaa7b..0000000
--- a/chrome/browser/media/webrtc/media_stream_infobar_delegate_android.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID_H_
-#define CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "chrome/browser/media/webrtc/media_stream_devices_controller.h"
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
-
-// This class configures an infobar shown when a page requests access to a
-// user's microphone and/or video camera.  The user is shown a message asking
-// which audio and/or video devices they wish to use with the current page, and
-// buttons to give access to the selected devices to the page, or to deny access
-// to them.
-class MediaStreamInfoBarDelegateAndroid : public PermissionInfoBarDelegate {
- public:
-  // Prompts the user by creating a media stream infobar and delegate,
-  // then checks for an existing infobar for |web_contents| and replaces it if
-  // found, or just adds the new infobar otherwise.  Returns whether an infobar
-  // was created.
-  static bool Create(
-      content::WebContents* web_contents,
-      bool user_gesture,
-      std::unique_ptr<MediaStreamDevicesController::Request> request);
-
-  MediaStreamInfoBarDelegateAndroid(
-      Profile* profile,
-      bool user_gesture,
-      std::unique_ptr<MediaStreamDevicesController::Request> request);
-
- private:
-  friend class WebRtcTestBase;
-
-  ~MediaStreamInfoBarDelegateAndroid() override;
-
-  // PermissionInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  Type GetInfoBarType() const override;
-  int GetIconId() const override;
-  void InfoBarDismissed() override;
-  MediaStreamInfoBarDelegateAndroid* AsMediaStreamInfoBarDelegateAndroid()
-      override;
-  base::string16 GetMessageText() const override;
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  bool Accept() override;
-  bool Cancel() override;
-  base::string16 GetLinkText() const override;
-  GURL GetLinkURL() const override;
-  int GetMessageResourceId() const override;
-  std::vector<int> content_settings_types() const override;
-
-  std::unique_ptr<MediaStreamDevicesController::Request> request_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaStreamInfoBarDelegateAndroid);
-};
-
-#endif  // CHROME_BROWSER_MEDIA_WEBRTC_MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
index 808f0a6..2d47bb36 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_browsertest.cc
@@ -381,3 +381,11 @@
   EXPECT_EQ("ok",
             ExecuteJavascript("switchRemoteStreamAndBackAgain()", left_tab_));
 }
+
+IN_PROC_BROWSER_TEST_F(WebRtcRtpBrowserTest,
+                       SwitchRemoteStreamWithoutWaitingForPromisesToResolve) {
+  StartServerAndOpenTabs();
+  EXPECT_EQ("ok", ExecuteJavascript(
+                      "switchRemoteStreamWithoutWaitingForPromisesToResolve()",
+                      left_tab_));
+}
diff --git a/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
index 73c34930..9b449e13a 100644
--- a/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
+++ b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
@@ -14,7 +14,11 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_constants.h"
 #include "content/public/browser/browser_thread.h"
@@ -29,7 +33,7 @@
 
 #if defined(OS_WIN)
 base::File::Error ScanFile(const base::FilePath& dest_platform_path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::win::ScopedComPtr<IAttachmentExecute> attachment_services;
   HRESULT hr = ::CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_ALL,
@@ -65,11 +69,11 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
 #if defined(OS_WIN)
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE,
-      FROM_HERE,
-      base::Bind(&ScanFile, dest_platform_path),
-      result_callback);
+  base::PostTaskAndReplyWithResult(
+      base::CreateCOMSTATaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE})
+          .get(),
+      FROM_HERE, base::Bind(&ScanFile, dest_platform_path), result_callback);
 #else
   result_callback.Run(base::File::FILE_OK);
 #endif
diff --git a/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc b/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc
index 908095bf..e880ce5 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_validator_browsertest.cc
@@ -14,10 +14,11 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_utils.h"
 #include "storage/browser/fileapi/copy_or_move_file_validator.h"
@@ -77,23 +78,13 @@
 
   ~MediaFileValidatorTest() override {}
 
-  void TearDownOnMainThread() override {
-    // Release our ref to |file_system_context_| before the test framework winds
-    // down, otherwise releasing it in the destructor posts a destruction task
-    // to the FILE thread after it has been shutdown (which base/task_scheduler
-    // guards against in the RedirectNonUINonIOBrowserThreads experiment per the
-    // FILE thread's tasks being marked as shutdown blocking for legacy
-    // reasons).
-    file_system_context_ = nullptr;
-  }
-
   // Write |content| into |filename| in a test file system and try to move
   // it into a media file system.  The result is compared to |expected_result|.
   void MoveTest(const std::string& filename, const std::string& content,
                 bool expected_result) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&MediaFileValidatorTest::SetupOnFileThread,
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::MayBlock()},
+        base::BindOnce(&MediaFileValidatorTest::SetupBlocking,
                        base::Unretained(this), filename, content,
                        expected_result));
     loop_runner_ = new content::MessageLoopRunner;
@@ -104,9 +95,9 @@
   // into a media file system.  The result is compared to |expected_result|.
   void MoveTestFromFile(const std::string& filename,
                         const base::FilePath& source, bool expected_result) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&MediaFileValidatorTest::SetupFromFileOnFileThread,
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::MayBlock()},
+        base::BindOnce(&MediaFileValidatorTest::SetupFromFileBlocking,
                        base::Unretained(this), filename, source,
                        expected_result));
     loop_runner_ = new content::MessageLoopRunner;
@@ -115,9 +106,9 @@
 
  private:
   // Create the test files, filesystem objects, etc.
-  void SetupOnFileThread(const std::string& filename,
-                         const std::string& content,
-                         bool expected_result) {
+  void SetupBlocking(const std::string& filename,
+                     const std::string& content,
+                     bool expected_result) {
     ASSERT_TRUE(base_dir_.CreateUniqueTempDir());
     base::FilePath base = base_dir_.GetPath();
     base::FilePath src_path = base.AppendASCII("src_fs");
@@ -125,14 +116,20 @@
 
     std::vector<std::unique_ptr<storage::FileSystemBackend>>
         additional_providers;
+    file_system_runner_ =
+        base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
     additional_providers.push_back(
         base::MakeUnique<content::TestFileSystemBackend>(
-            base::ThreadTaskRunnerHandle::Get().get(), src_path));
+            file_system_runner_.get(), src_path));
     additional_providers.push_back(
         base::MakeUnique<MediaFileSystemBackend>(base));
     file_system_context_ =
         content::CreateFileSystemContextWithAdditionalProvidersForTesting(
-            NULL, std::move(additional_providers), base);
+            content::BrowserThread::GetTaskRunnerForThread(
+                content::BrowserThread::IO)
+                .get(),
+            file_system_runner_.get(), NULL, std::move(additional_providers),
+            base);
 
     move_src_ = file_system_context_->CreateCrackedFileSystemURL(
         GURL(kOrigin),
@@ -169,12 +166,12 @@
                                   base::Unretained(this), expected_result)));
   }
 
-  void SetupFromFileOnFileThread(const std::string& filename,
-                                 const base::FilePath& source,
-                                 bool expected_result) {
+  void SetupFromFileBlocking(const std::string& filename,
+                             const base::FilePath& source,
+                             bool expected_result) {
     std::string content;
     ASSERT_TRUE(base::ReadFileToString(source, &content));
-    SetupOnFileThread(filename, content, expected_result);
+    SetupBlocking(filename, content, expected_result);
   }
 
   // Check that exactly one of |move_src_| and |move_dest_| exists.
@@ -258,6 +255,7 @@
   storage::FileSystemURL move_dest_;
 
   scoped_refptr<content::MessageLoopRunner> loop_runner_;
+  scoped_refptr<base::SequencedTaskRunner> file_system_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaFileValidatorTest);
 };
diff --git a/chrome/browser/media_galleries/fileapi/supported_audio_video_checker.cc b/chrome/browser/media_galleries/fileapi/supported_audio_video_checker.cc
index 98111ed1..5e22bd43 100644
--- a/chrome/browser/media_galleries/fileapi/supported_audio_video_checker.cc
+++ b/chrome/browser/media_galleries/fileapi/supported_audio_video_checker.cc
@@ -16,6 +16,9 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/media_galleries/fileapi/safe_audio_video_checker.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/mime_util.h"
@@ -52,8 +55,8 @@
 base::LazyInstance<SupportedAudioVideoExtensions>::DestructorAtExit
     g_audio_video_extensions = LAZY_INSTANCE_INITIALIZER;
 
-base::File OpenOnFileThread(const base::FilePath& path) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+base::File OpenBlocking(const base::FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
   return base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
 }
 
@@ -72,12 +75,11 @@
   DCHECK(callback_.is_null());
   callback_ = result_callback;
 
-  content::BrowserThread::PostTaskAndReplyWithResult(
-      content::BrowserThread::FILE,
-      FROM_HERE,
-      base::Bind(&OpenOnFileThread, path_),
-      base::Bind(&SupportedAudioVideoChecker::OnFileOpen,
-                 weak_factory_.GetWeakPtr()));
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+      base::BindOnce(&OpenBlocking, path_),
+      base::BindOnce(&SupportedAudioVideoChecker::OnFileOpen,
+                     weak_factory_.GetWeakPtr()));
 }
 
 SupportedAudioVideoChecker::SupportedAudioVideoChecker(
diff --git a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
index d433a58..7b2afbc 100644
--- a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
+++ b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
@@ -15,6 +15,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/stl_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/image_decoder.h"
 #include "content/public/browser/browser_thread.h"
@@ -105,9 +107,8 @@
   DCHECK(callback_.is_null());
   callback_ = result_callback;
 
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE,
-      FROM_HERE,
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
       base::Bind(&ReadOnFileThread, path_),
       base::Bind(&SupportedImageTypeValidator::OnFileOpen,
                  weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
index 5fcd59e..f7c16d2a 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/features/features.h"
 #include "net/dns/mock_host_resolver.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
@@ -44,7 +45,7 @@
 using extensions::TestExtensionDir;
 #endif
 
-static const char UkmEventName[] = "Memory.Experimental";
+using UkmEntry = ukm::builders::Memory_Experimental;
 
 void RequestGlobalDumpCallback(base::Closure quit_closure,
                                bool success,
@@ -215,57 +216,69 @@
   std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
 
   void CheckAllUkmSources(size_t metric_count = 1u) {
-    const std::map<ukm::SourceId, std::unique_ptr<ukm::UkmSource>>& sources =
-        test_ukm_recorder_->GetSources();
-    for (auto& pair : sources) {
-      const ukm::UkmSource* source = pair.second.get();
-      if (ProcessHasTypeForSource(source, ProcessType::BROWSER)) {
-        CheckUkmBrowserSource(source, metric_count);
-      } else if (ProcessHasTypeForSource(source, ProcessType::RENDERER)) {
-        CheckUkmRendererSource(source, metric_count);
+    std::set<ukm::SourceId> source_ids = test_ukm_recorder_->GetSourceIds();
+    for (auto source_id : source_ids) {
+      if (ProcessHasTypeForSource(source_id, ProcessType::BROWSER)) {
+        CheckUkmBrowserSource(source_id, 1);
+      } else if (ProcessHasTypeForSource(source_id, ProcessType::RENDERER)) {
+        // Renderer metrics associate with navigation's source, instead of
+        // creating a new one.
+        CheckUkmRendererSource(source_id, metric_count);
+      } else if (ProcessHasTypeForSource(source_id, ProcessType::GPU)) {
+        // Not checked yet.
       } else {
         // This must be Total2.
-        CheckMemoryMetricWithName(source, "Total2.PrivateMemoryFootprint",
-                                  false, metric_count);
+        CheckMemoryMetricWithName(
+            source_id, UkmEntry::kTotal2_PrivateMemoryFootprintName, false, 1);
       }
     }
   }
 
-  void CheckMemoryMetricWithName(const ukm::UkmSource* source,
+  void CheckMemoryMetricWithName(ukm::SourceId source_id,
                                  const char* name,
                                  bool can_be_zero,
                                  size_t metric_count = 1u) {
-    std::vector<int64_t> metrics =
-        test_ukm_recorder_->GetMetrics(*source, UkmEventName, name);
-    EXPECT_EQ(metric_count, metrics.size());
-    EXPECT_GE(metrics[0], can_be_zero ? 0 : 1) << name;
-    EXPECT_LE(metrics[0], 4000) << name;
+    std::vector<int64_t> metrics = test_ukm_recorder_->GetMetricValues(
+        source_id, UkmEntry::kEntryName, name);
+    EXPECT_EQ(metric_count, metrics.size()) << name;
+    if (metrics.size() > 0) {
+      int64_t metric = *metrics.begin();
+      EXPECT_GE(metric, can_be_zero ? 0 : 1) << name;
+      EXPECT_LE(metric, 4000) << name;
+    }
   }
 
-  void CheckUkmRendererSource(const ukm::UkmSource* source,
+  void CheckUkmRendererSource(ukm::SourceId source_id,
                               size_t metric_count = 1u) {
-    CheckMemoryMetricWithName(source, "Malloc", false, metric_count);
-    CheckMemoryMetricWithName(source, "Resident", false, metric_count);
-    CheckMemoryMetricWithName(source, "PrivateMemoryFootprint", false,
+    CheckMemoryMetricWithName(source_id, UkmEntry::kMallocName, false,
                               metric_count);
-    CheckMemoryMetricWithName(source, "BlinkGC", true, metric_count);
-    CheckMemoryMetricWithName(source, "PartitionAlloc", true, metric_count);
-    CheckMemoryMetricWithName(source, "V8", true, metric_count);
-    CheckMemoryMetricWithName(source, "NumberOfExtensions", true, metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kResidentName, false,
+                              metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kPrivateMemoryFootprintName,
+                              false, metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kBlinkGCName, true,
+                              metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kPartitionAllocName, true,
+                              metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kV8Name, true, metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kNumberOfExtensionsName,
+                              true, metric_count);
   }
 
-  void CheckUkmBrowserSource(const ukm::UkmSource* source,
+  void CheckUkmBrowserSource(ukm::SourceId source_id,
                              size_t metric_count = 1u) {
-    CheckMemoryMetricWithName(source, "Malloc", false, metric_count);
-    CheckMemoryMetricWithName(source, "Resident", false, metric_count);
-    CheckMemoryMetricWithName(source, "PrivateMemoryFootprint", false,
+    CheckMemoryMetricWithName(source_id, UkmEntry::kMallocName, false,
                               metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kResidentName, false,
+                              metric_count);
+    CheckMemoryMetricWithName(source_id, UkmEntry::kPrivateMemoryFootprintName,
+                              false, metric_count);
   }
 
-  bool ProcessHasTypeForSource(const ukm::UkmSource* source,
+  bool ProcessHasTypeForSource(ukm::SourceId source_id,
                                ProcessType process_type) {
-    std::vector<int64_t> metrics =
-        test_ukm_recorder_->GetMetrics(*source, UkmEventName, "ProcessType");
+    std::vector<int64_t> metrics = test_ukm_recorder_->GetMetricValues(
+        source_id, UkmEntry::kEntryName, UkmEntry::kProcessTypeName);
 
     return std::find(metrics.begin(), metrics.end(),
                      static_cast<int64_t>(process_type)) != metrics.end();
diff --git a/chrome/browser/notifications/message_center_notifications_unittest.cc b/chrome/browser/notifications/message_center_notifications_unittest.cc
index ada0252..43794bf9 100644
--- a/chrome/browser/notifications/message_center_notifications_unittest.cc
+++ b/chrome/browser/notifications/message_center_notifications_unittest.cc
@@ -134,9 +134,7 @@
   chrome::MultiUserWindowManagerChromeOS* multi_user_window_manager =
       new chrome::MultiUserWindowManagerChromeOS(active_user_id);
   multi_user_window_manager->Init();
-  chrome::MultiUserWindowManager::SetInstanceForTest(
-      multi_user_window_manager,
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
+  chrome::MultiUserWindowManager::SetInstanceForTest(multi_user_window_manager);
   std::unique_ptr<MultiUserNotificationBlockerChromeOS> blocker(
       new MultiUserNotificationBlockerChromeOS(
           message_center::MessageCenter::Get(), active_user_id));
diff --git a/chrome/browser/notifications/notification_permission_infobar_delegate.cc b/chrome/browser/notifications/notification_permission_infobar_delegate.cc
deleted file mode 100644
index c41486e..0000000
--- a/chrome/browser/notifications/notification_permission_infobar_delegate.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/notifications/notification_permission_infobar_delegate.h"
-
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/grit/generated_resources.h"
-
-NotificationPermissionInfoBarDelegate::NotificationPermissionInfoBarDelegate(
-    ContentSettingsType type,
-    const GURL& requesting_frame,
-    bool user_gesture,
-    Profile* profile,
-    const PermissionSetCallback& callback)
-    : PermissionInfoBarDelegate(requesting_frame,
-                                type,
-                                user_gesture,
-                                profile,
-                                callback) {
-  DCHECK(type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
-         type == CONTENT_SETTINGS_TYPE_PUSH_MESSAGING);
-}
-
-NotificationPermissionInfoBarDelegate::~NotificationPermissionInfoBarDelegate()
-    {}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-NotificationPermissionInfoBarDelegate::GetIdentifier() const {
-  return NOTIFICATION_PERMISSION_INFOBAR_DELEGATE;
-}
-
-int NotificationPermissionInfoBarDelegate::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_NOTIFICATIONS;
-}
-
-int NotificationPermissionInfoBarDelegate::GetMessageResourceId() const {
-  return IDS_NOTIFICATION_PERMISSIONS;
-}
diff --git a/chrome/browser/notifications/notification_permission_infobar_delegate.h b/chrome/browser/notifications/notification_permission_infobar_delegate.h
deleted file mode 100644
index 6765722..0000000
--- a/chrome/browser/notifications/notification_permission_infobar_delegate.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 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_NOTIFICATIONS_NOTIFICATION_PERMISSION_INFOBAR_DELEGATE_H_
-#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_PERMISSION_INFOBAR_DELEGATE_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
-
-class NotificationPermissionInfoBarDelegate : public PermissionInfoBarDelegate {
- public:
-  NotificationPermissionInfoBarDelegate(
-      ContentSettingsType type,
-      const GURL& requesting_frame,
-      bool user_gesture,
-      Profile* profile,
-      const PermissionSetCallback& callback);
-
- private:
-  ~NotificationPermissionInfoBarDelegate() override;
-
-  // PermissionInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  int GetMessageResourceId() const override;
-
-  DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate);
-};
-
-#endif  // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_PERMISSION_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
index 87fe57ac..1e7acffb 100644
--- a/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
+++ b/chrome/browser/offline_pages/android/evaluation/offline_page_evaluation_bridge.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/offline_pages/android/background_scheduler_bridge.h"
 #include "chrome/browser/offline_pages/android/downloads/offline_page_notification_bridge.h"
 #include "chrome/browser/offline_pages/android/evaluation/evaluation_test_scheduler.h"
-#include "chrome/browser/offline_pages/android/prerendering_offliner.h"
 #include "chrome/browser/offline_pages/background_loader_offliner.h"
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/offline_pages/request_coordinator_factory.h"
@@ -168,16 +167,6 @@
   return std::move(request_coordinator);
 }
 
-std::unique_ptr<KeyedService> GetTestPrerenderRequestCoordinator(
-    content::BrowserContext* context) {
-  std::unique_ptr<OfflinerPolicy> policy(new OfflinerPolicy());
-  std::unique_ptr<Offliner> offliner(new PrerenderingOffliner(
-      context, policy.get(),
-      OfflinePageModelFactory::GetForBrowserContext(context)));
-  return GetTestingRequestCoordinator(context, std::move(policy),
-                                      std::move(offliner));
-}
-
 std::unique_ptr<KeyedService> GetTestBackgroundLoaderRequestCoordinator(
     content::BrowserContext* context) {
   std::unique_ptr<OfflinerPolicy> policy(new OfflinerPolicy());
@@ -190,35 +179,28 @@
 }
 
 RequestCoordinator* GetRequestCoordinator(Profile* profile,
-                                          bool use_evaluation_scheduler,
-                                          bool use_background_loader) {
+                                          bool use_evaluation_scheduler) {
   if (!use_evaluation_scheduler) {
     return RequestCoordinatorFactory::GetForBrowserContext(profile);
   }
-  if (use_background_loader) {
-    return static_cast<RequestCoordinator*>(
-        RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse(
-            profile, &GetTestBackgroundLoaderRequestCoordinator));
-  }
   return static_cast<RequestCoordinator*>(
       RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse(
-          profile, &GetTestPrerenderRequestCoordinator));
+          profile, &GetTestBackgroundLoaderRequestCoordinator));
 }
+
 }  // namespace
 
 static jlong CreateBridgeForProfile(JNIEnv* env,
                                     const JavaParamRef<jobject>& obj,
                                     const JavaParamRef<jobject>& j_profile,
-                                    const jboolean j_use_evaluation_scheduler,
-                                    const jboolean j_use_background_loader) {
+                                    const jboolean j_use_evaluation_scheduler) {
   Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
 
   OfflinePageModel* offline_page_model =
       OfflinePageModelFactory::GetForBrowserContext(profile);
 
   RequestCoordinator* request_coordinator = GetRequestCoordinator(
-      profile, static_cast<bool>(j_use_evaluation_scheduler),
-      static_cast<bool>(j_use_background_loader));
+      profile, static_cast<bool>(j_use_evaluation_scheduler));
 
   if (offline_page_model == nullptr || request_coordinator == nullptr)
     return 0;
diff --git a/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py b/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py
index 5f27311..75def29c 100755
--- a/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py
+++ b/chrome/browser/offline_pages/android/evaluation/run_offline_page_evaluation_test.py
@@ -29,7 +29,6 @@
 
 DEFAULT_USER_REQUEST = True
 DEFAULT_USE_TEST_SCHEDULER = True
-DEFAULT_USE_BACKGROUND_LOADER = False
 # 0 means the batch would be the whole list of urls.
 DEFAULT_BATCH_SIZE = 0
 DEFAULT_VERBOSE = False
@@ -41,7 +40,6 @@
 IsUserRequested = {is_user_requested}
 UseTestScheduler = {use_test_scheduler}
 ScheduleBatchSize = {schedule_batch_size}
-UseBackgroundLoader = {use_background_loader}
 """
 
 
@@ -92,23 +90,12 @@
   parser.add_argument('build_output_dir', help='Path to build directory.')
   parser.add_argument(
       'test_urls_file', help='Path to input file with urls to be tested.')
-  parser.add_argument(
-      '--use-background-loader',
-      dest='use_background_loader',
-      action='store_true',
-      help='Use background loader instead of prerenderer.')
-  parser.add_argument(
-      '--use-prerenderer',
-      dest='use_background_loader',
-      action='store_false',
-      help='Use prerenderer instead of background loader.')
   parser.set_defaults(
       output_dir=os.path.expanduser('~/offline_eval_output'),
       user_request=DEFAULT_USER_REQUEST,
       use_test_scheduler=DEFAULT_USE_TEST_SCHEDULER,
       schedule_batch_size=DEFAULT_BATCH_SIZE,
-      verbose=DEFAULT_VERBOSE,
-      use_background_loader=DEFAULT_USE_BACKGROUND_LOADER)
+      verbose=DEFAULT_VERBOSE)
 
   # Get the arguments and several paths.
   options, extra_args = parser.parse_known_args(args)
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index 3253fee9..62d5607 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -35,6 +35,8 @@
 const char kUkmHttpRttEstimate[] = "Net.HttpRttEstimate.OnNavigationStart";
 const char kUkmTransportRttEstimate[] =
     "Net.TransportRttEstimate.OnNavigationStart";
+const char kUkmDownstreamKbpsEstimate[] =
+    "Net.DownstreamKbpsEstimate.OnNavigationStart";
 const char kUkmNetErrorCode[] = "Net.ErrorCode.OnFailedProvisionalLoad";
 const char kUkmPageTransition[] = "Navigation.PageTransition";
 
@@ -89,6 +91,8 @@
         network_quality_provider_->GetEffectiveConnectionType();
     http_rtt_estimate_ = network_quality_provider_->GetHttpRTT();
     transport_rtt_estimate_ = network_quality_provider_->GetTransportRTT();
+    downstream_kbps_estimate_ =
+        network_quality_provider_->GetDownstreamThroughputKbps();
   }
   page_transition_ = navigation_handle->GetPageTransition();
   return CONTINUE_OBSERVING;
@@ -213,6 +217,10 @@
         internal::kUkmTransportRttEstimate,
         static_cast<int64_t>(transport_rtt_estimate_.value().InMilliseconds()));
   }
+  if (downstream_kbps_estimate_) {
+    builder->AddMetric(internal::kUkmDownstreamKbpsEstimate,
+                       static_cast<int64_t>(downstream_kbps_estimate_.value()));
+  }
   // page_transition_ fits in a uint32_t, so we can safely cast to int64_t.
   builder->AddMetric(internal::kUkmPageTransition,
                      static_cast<int64_t>(page_transition_));
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
index 79c3f35..6a2ebfb 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -33,6 +33,7 @@
 extern const char kUkmEffectiveConnectionType[];
 extern const char kUkmHttpRttEstimate[];
 extern const char kUkmTransportRttEstimate[];
+extern const char kUkmDownstreamKbpsEstimate[];
 extern const char kUkmPageTransition[];
 
 }  // namespace internal
@@ -96,6 +97,7 @@
       net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
   base::Optional<base::TimeDelta> http_rtt_estimate_;
   base::Optional<base::TimeDelta> transport_rtt_estimate_;
+  base::Optional<int32_t> downstream_kbps_estimate_;
 
   // PAGE_TRANSITION_LINK is the default PageTransition value.
   ui::PageTransition page_transition_ = ui::PAGE_TRANSITION_LINK;
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index db522c2..4f54f1f 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -33,6 +33,7 @@
                      net::EffectiveConnectionType());
   MOCK_CONST_METHOD0(GetHttpRTT, base::Optional<base::TimeDelta>());
   MOCK_CONST_METHOD0(GetTransportRTT, base::Optional<base::TimeDelta>());
+  MOCK_CONST_METHOD0(GetDownstreamThroughputKbps, base::Optional<int32_t>());
 };
 
 }  // namespace
@@ -59,6 +60,10 @@
     EXPECT_CALL(mock_network_quality_provider_, GetTransportRTT())
         .Times(AnyNumber())
         .WillRepeatedly(Return(base::Optional<base::TimeDelta>()));
+
+    EXPECT_CALL(mock_network_quality_provider_, GetDownstreamThroughputKbps())
+        .Times(AnyNumber())
+        .WillRepeatedly(Return(base::Optional<int32_t>()));
   }
 
   MockNetworkQualityProvider& mock_network_quality_provider() {
@@ -257,6 +262,8 @@
       .WillRepeatedly(Return(base::TimeDelta::FromMilliseconds(100)));
   EXPECT_CALL(mock_network_quality_provider(), GetTransportRTT())
       .WillRepeatedly(Return(base::TimeDelta::FromMilliseconds(200)));
+  EXPECT_CALL(mock_network_quality_provider(), GetDownstreamThroughputKbps())
+      .WillRepeatedly(Return(300));
 
   NavigateAndCommit(GURL(kTestUrl1));
 
@@ -276,6 +283,8 @@
                                    internal::kUkmHttpRttEstimate, 100);
   test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
                                    internal::kUkmTransportRttEstimate, 200);
+  test_ukm_recorder().ExpectMetric(*source, internal::kUkmPageLoadEventName,
+                                   internal::kUkmDownstreamKbpsEstimate, 300);
 }
 
 TEST_F(UkmPageLoadMetricsObserverTest, PageTransitionReload) {
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index 25540ce6..8302c223 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -40,10 +40,6 @@
 #include "extensions/common/constants.h"
 #include "url/gurl.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/permissions/permission_queue_controller.h"
-#endif
-
 namespace {
 
 const char kPermissionBlockedKillSwitchMessage[] =
@@ -90,10 +86,6 @@
       content_settings_type_(content_settings_type),
       feature_policy_feature_(feature_policy_feature),
       weak_factory_(this) {
-#if defined(OS_ANDROID)
-  permission_queue_controller_.reset(
-      new PermissionQueueController(profile_, content_settings_type_));
-#endif
   PermissionDecisionAutoBlocker::UpdateFromVariations();
 }
 
@@ -290,19 +282,11 @@
     const PermissionRequestID& id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (PermissionRequestManager::IsEnabled()) {
-    auto it = pending_requests_.find(id.ToString());
-    if (it != pending_requests_.end() && web_contents != nullptr &&
-        PermissionRequestManager::FromWebContents(web_contents) != nullptr) {
-      PermissionRequestManager::FromWebContents(web_contents)
-          ->CancelRequest(it->second.get());
-    }
-  } else {
-#if defined(OS_ANDROID)
-    GetQueueController()->CancelInfoBarRequest(id);
-#else
-    NOTREACHED();
-#endif
+  auto it = pending_requests_.find(id.ToString());
+  if (it != pending_requests_.end() && web_contents != nullptr &&
+      PermissionRequestManager::FromWebContents(web_contents) != nullptr) {
+    PermissionRequestManager::FromWebContents(web_contents)
+        ->CancelRequest(it->second.get());
   }
 }
 
@@ -332,44 +316,29 @@
     const BrowserPermissionCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (PermissionRequestManager::IsEnabled()) {
-    PermissionRequestManager* permission_request_manager =
-        PermissionRequestManager::FromWebContents(web_contents);
-    // TODO(felt): sometimes |permission_request_manager| is null. This check is
-    // meant to prevent crashes. See crbug.com/457091.
-    if (!permission_request_manager)
-      return;
+  PermissionRequestManager* permission_request_manager =
+      PermissionRequestManager::FromWebContents(web_contents);
+  // TODO(felt): sometimes |permission_request_manager| is null. This check is
+  // meant to prevent crashes. See crbug.com/457091.
+  if (!permission_request_manager)
+    return;
 
-    std::unique_ptr<PermissionRequest> request_ptr =
-        base::MakeUnique<PermissionRequestImpl>(
-            requesting_origin, content_settings_type_, profile_, user_gesture,
-            base::Bind(&PermissionContextBase::PermissionDecided,
-                       weak_factory_.GetWeakPtr(), id, requesting_origin,
-                       embedding_origin, user_gesture, callback),
-            base::Bind(&PermissionContextBase::CleanUpRequest,
-                       weak_factory_.GetWeakPtr(), id));
-    PermissionRequest* request = request_ptr.get();
+  std::unique_ptr<PermissionRequest> request_ptr =
+      base::MakeUnique<PermissionRequestImpl>(
+          requesting_origin, content_settings_type_, profile_, user_gesture,
+          base::Bind(&PermissionContextBase::PermissionDecided,
+                     weak_factory_.GetWeakPtr(), id, requesting_origin,
+                     embedding_origin, user_gesture, callback),
+          base::Bind(&PermissionContextBase::CleanUpRequest,
+                     weak_factory_.GetWeakPtr(), id));
+  PermissionRequest* request = request_ptr.get();
 
-    bool inserted =
-        pending_requests_
-            .insert(std::make_pair(id.ToString(), std::move(request_ptr)))
-            .second;
-    DCHECK(inserted) << "Duplicate id " << id.ToString();
-    permission_request_manager->AddRequest(request);
-  } else {
-#if defined(OS_ANDROID)
-    GetQueueController()->CreateInfoBarRequest(
-        id, requesting_origin, embedding_origin, user_gesture,
-        base::Bind(&PermissionContextBase::PermissionDecided,
-                   weak_factory_.GetWeakPtr(), id, requesting_origin,
-                   embedding_origin, user_gesture, callback,
-                   // the queue controller takes care of persisting the
-                   // permission
-                   false));
-#else
-    NOTREACHED();
-#endif
-  }
+  bool inserted =
+      pending_requests_
+          .insert(std::make_pair(id.ToString(), std::move(request_ptr)))
+          .second;
+  DCHECK(inserted) << "Duplicate id " << id.ToString();
+  permission_request_manager->AddRequest(request);
 }
 
 void PermissionContextBase::PermissionDecided(
@@ -380,35 +349,31 @@
     const BrowserPermissionCallback& callback,
     bool persist,
     ContentSetting content_setting) {
-  if (PermissionRequestManager::IsEnabled()) {
-    // Infobar persistence and its related UMA is tracked on the infobar
-    // controller directly.
-    PermissionRequestGestureType gesture_type =
-        user_gesture ? PermissionRequestGestureType::GESTURE
-                     : PermissionRequestGestureType::NO_GESTURE;
-    PermissionEmbargoStatus embargo_status =
-        PermissionEmbargoStatus::NOT_EMBARGOED;
-    DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
-           content_setting == CONTENT_SETTING_BLOCK ||
-           content_setting == CONTENT_SETTING_DEFAULT);
-    if (content_setting == CONTENT_SETTING_ALLOW) {
-      PermissionUmaUtil::PermissionGranted(content_settings_type_, gesture_type,
+  PermissionRequestGestureType gesture_type =
+      user_gesture ? PermissionRequestGestureType::GESTURE
+                   : PermissionRequestGestureType::NO_GESTURE;
+  PermissionEmbargoStatus embargo_status =
+      PermissionEmbargoStatus::NOT_EMBARGOED;
+  DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
+         content_setting == CONTENT_SETTING_BLOCK ||
+         content_setting == CONTENT_SETTING_DEFAULT);
+  if (content_setting == CONTENT_SETTING_ALLOW) {
+    PermissionUmaUtil::PermissionGranted(content_settings_type_, gesture_type,
+                                         requesting_origin, profile_);
+  } else if (content_setting == CONTENT_SETTING_BLOCK) {
+    PermissionUmaUtil::PermissionDenied(content_settings_type_, gesture_type,
+                                        requesting_origin, profile_);
+  } else {
+    PermissionUmaUtil::PermissionDismissed(content_settings_type_, gesture_type,
                                            requesting_origin, profile_);
-    } else if (content_setting == CONTENT_SETTING_BLOCK) {
-      PermissionUmaUtil::PermissionDenied(content_settings_type_, gesture_type,
-                                          requesting_origin, profile_);
-    } else {
-      PermissionUmaUtil::PermissionDismissed(
-          content_settings_type_, gesture_type, requesting_origin, profile_);
 
-      if (PermissionDecisionAutoBlocker::GetForProfile(profile_)
-              ->RecordDismissAndEmbargo(requesting_origin,
-                                        content_settings_type_)) {
-        embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS;
-      }
+    if (PermissionDecisionAutoBlocker::GetForProfile(profile_)
+            ->RecordDismissAndEmbargo(requesting_origin,
+                                      content_settings_type_)) {
+      embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS;
     }
-    PermissionUmaUtil::RecordEmbargoStatus(embargo_status);
   }
+  PermissionUmaUtil::RecordEmbargoStatus(embargo_status);
 
   UserMadePermissionDecision(id, requesting_origin, embedding_origin,
                              content_setting);
@@ -416,12 +381,6 @@
                       persist, content_setting);
 }
 
-#if defined(OS_ANDROID)
-PermissionQueueController* PermissionContextBase::GetQueueController() {
-  return permission_queue_controller_.get();
-}
-#endif
-
 Profile* PermissionContextBase::profile() const {
   return profile_;
 }
diff --git a/chrome/browser/permissions/permission_context_base.h b/chrome/browser/permissions/permission_context_base.h
index 4c073a1..5ebcddbb 100644
--- a/chrome/browser/permissions/permission_context_base.h
+++ b/chrome/browser/permissions/permission_context_base.h
@@ -18,9 +18,6 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "third_party/WebKit/public/platform/WebFeaturePolicyFeature.h"
 
-#if defined(OS_ANDROID)
-class PermissionQueueController;
-#endif
 class GURL;
 class PermissionRequestID;
 class Profile;
@@ -152,11 +149,6 @@
                                 const GURL& requesting_origin,
                                 bool allowed) {}
 
-#if defined(OS_ANDROID)
-  // Return an instance of the infobar queue controller, creating it if needed.
-  PermissionQueueController* GetQueueController();
-#endif
-
   // Returns the profile associated with this permission context.
   Profile* profile() const;
 
@@ -206,9 +198,6 @@
   Profile* profile_;
   const ContentSettingsType content_settings_type_;
   const blink::WebFeaturePolicyFeature feature_policy_feature_;
-#if defined(OS_ANDROID)
-  std::unique_ptr<PermissionQueueController> permission_queue_controller_;
-#endif
   std::unordered_map<std::string, std::unique_ptr<PermissionRequest>>
       pending_requests_;
 
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc
index 8890fbe..a3fc0f0 100644
--- a/chrome/browser/permissions/permission_context_base_unittest.cc
+++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -23,7 +23,6 @@
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/permissions/permission_decision_auto_blocker.h"
 #include "chrome/browser/permissions/permission_manager.h"
-#include "chrome/browser/permissions/permission_queue_controller.h"
 #include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
 #include "chrome/browser/permissions/permission_uma_util.h"
diff --git a/chrome/browser/permissions/permission_dialog_delegate.cc b/chrome/browser/permissions/permission_dialog_delegate.cc
index 85655c4..9ef98ace 100644
--- a/chrome/browser/permissions/permission_dialog_delegate.cc
+++ b/chrome/browser/permissions/permission_dialog_delegate.cc
@@ -12,11 +12,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/android/resource_mapper.h"
 #include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/geolocation/geolocation_infobar_delegate_android.h"
-#include "chrome/browser/media/midi_permission_infobar_delegate_android.h"
-#include "chrome/browser/media/protected_media_identifier_infobar_delegate_android.h"
-#include "chrome/browser/media/webrtc/media_stream_infobar_delegate_android.h"
-#include "chrome/browser/notifications/notification_permission_infobar_delegate.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
@@ -44,57 +39,7 @@
   }
 
   // Dispatch the dialog to Java, which manages the lifetime of this object.
-  new PermissionDialogDelegate(tab, /*infobar_delegate=*/nullptr,
-                               permission_prompt);
-}
-
-// static
-void PermissionDialogDelegate::Create(content::WebContents* web_contents,
-                                      ContentSettingsType type,
-                                      const GURL& requesting_frame,
-                                      bool user_gesture,
-                                      Profile* profile,
-                                      const PermissionSetCallback& callback) {
-  DCHECK(web_contents);
-
-  // If we don't have a tab, just act as though the prompt was dismissed.
-  TabAndroid* tab = TabAndroid::FromWebContents(web_contents);
-  if (!tab) {
-    callback.Run(false, PermissionAction::DISMISSED);
-    return;
-  }
-
-  // Dispatch the dialog to Java, which manages the lifetime of this object.
-  new PermissionDialogDelegate(
-      tab,
-      PermissionInfoBarDelegate::CreateDelegate(
-          type, requesting_frame, user_gesture, profile, callback),
-      /*permission_prompt=*/nullptr);
-}
-
-// static
-void PermissionDialogDelegate::CreateMediaStreamDialog(
-    content::WebContents* web_contents,
-    bool user_gesture,
-    std::unique_ptr<MediaStreamDevicesController::Request> request) {
-  DCHECK(web_contents);
-
-  // If we don't have a tab, just act as though the prompt was dismissed.
-  TabAndroid* tab = TabAndroid::FromWebContents(web_contents);
-  if (!tab) {
-    request->Cancelled();
-    return;
-  }
-
-  // Called this way because the infobar delegate has a private destructor.
-  std::unique_ptr<PermissionInfoBarDelegate> infobar_delegate;
-  infobar_delegate.reset(new MediaStreamInfoBarDelegateAndroid(
-      Profile::FromBrowserContext(web_contents->GetBrowserContext()),
-      user_gesture, std::move(request)));
-
-  // Dispatch the dialog to Java, which manages the lifetime of this object.
-  new PermissionDialogDelegate(tab, std::move(infobar_delegate),
-                               /*permission_prompt=*/nullptr);
+  new PermissionDialogDelegate(tab, permission_prompt);
 }
 
 // static
@@ -110,21 +55,6 @@
       ConvertUTF16ToJavaString(env,
                                l10n_util::GetStringUTF16(IDS_PERMISSION_DENY));
 
-  if (infobar_delegate_) {
-    std::vector<int> content_settings_types{
-        infobar_delegate_->content_settings_types()};
-
-    j_delegate_.Reset(Java_PermissionDialogDelegate_create(
-        env, reinterpret_cast<uintptr_t>(this), tab_->GetJavaObject(),
-        base::android::ToJavaIntArray(env, content_settings_types),
-        ResourceMapper::MapFromChromiumId(infobar_delegate_->GetIconId()),
-        ConvertUTF16ToJavaString(env, infobar_delegate_->GetMessageText()),
-        ConvertUTF16ToJavaString(env, infobar_delegate_->GetLinkText()),
-        primaryButtonText, secondaryButtonText,
-        infobar_delegate_->ShouldShowPersistenceToggle()));
-    return;
-  }
-
   std::vector<int> content_settings_types;
   for (size_t i = 0; i < permission_prompt_->PermissionCount(); ++i) {
     content_settings_types.push_back(
@@ -144,13 +74,6 @@
 void PermissionDialogDelegate::Accept(JNIEnv* env,
                                       const JavaParamRef<jobject>& obj,
                                       jboolean persist) {
-  if (infobar_delegate_) {
-    if (infobar_delegate_->ShouldShowPersistenceToggle())
-      infobar_delegate_->set_persist(persist);
-    infobar_delegate_->Accept();
-    return;
-  }
-
   if (permission_prompt_->ShouldShowPersistenceToggle())
     permission_prompt_->TogglePersist(persist);
   permission_prompt_->Accept();
@@ -159,13 +82,6 @@
 void PermissionDialogDelegate::Cancel(JNIEnv* env,
                                       const JavaParamRef<jobject>& obj,
                                       jboolean persist) {
-  if (infobar_delegate_) {
-    if (infobar_delegate_->ShouldShowPersistenceToggle())
-      infobar_delegate_->set_persist(persist);
-    infobar_delegate_->Cancel();
-    return;
-  }
-
   if (permission_prompt_->ShouldShowPersistenceToggle())
     permission_prompt_->TogglePersist(persist);
   permission_prompt_->Deny();
@@ -173,22 +89,13 @@
 
 void PermissionDialogDelegate::Dismissed(JNIEnv* env,
                                          const JavaParamRef<jobject>& obj) {
-  if (infobar_delegate_) {
-    infobar_delegate_->InfoBarDismissed();
-    return;
-  }
-
   permission_prompt_->Closing();
 }
 
 void PermissionDialogDelegate::LinkClicked(JNIEnv* env,
                                            const JavaParamRef<jobject>& obj) {
-  // Don't call delegate_->LinkClicked() because that relies on having an
-  // InfoBarService as an owner() to open the link. That will fail since the
-  // wrapped delegate has no owner (it hasn't been added as an infobar).
   if (tab_->web_contents()) {
-    GURL linkURL = infobar_delegate_ ? infobar_delegate_->GetLinkURL()
-                                     : permission_prompt_->GetLinkURL();
+    GURL linkURL = permission_prompt_->GetLinkURL();
     tab_->web_contents()->OpenURL(content::OpenURLParams(
         linkURL, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
         ui::PAGE_TRANSITION_LINK, false));
@@ -202,16 +109,12 @@
 
 PermissionDialogDelegate::PermissionDialogDelegate(
     TabAndroid* tab,
-    std::unique_ptr<PermissionInfoBarDelegate> infobar_delegate,
     PermissionPromptAndroid* permission_prompt)
     : content::WebContentsObserver(tab->web_contents()),
       tab_(tab),
-      infobar_delegate_(std::move(infobar_delegate)),
       permission_prompt_(permission_prompt) {
   DCHECK(tab_);
-  // Only one of the PermissionPromptAndroid and PermissionInfoBarDelegate is
-  // used, depending on whether the PermissionRequestManager is enabled or not.
-  DCHECK(!!permission_prompt_ ^ !!infobar_delegate_);
+  DCHECK(permission_prompt_);
 
   // Create our Java counterpart, which manages our lifetime.
   JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chrome/browser/permissions/permission_dialog_delegate.h b/chrome/browser/permissions/permission_dialog_delegate.h
index efe4aef6..b2b25d4b8f 100644
--- a/chrome/browser/permissions/permission_dialog_delegate.h
+++ b/chrome/browser/permissions/permission_dialog_delegate.h
@@ -21,19 +21,11 @@
 namespace content {
 class WebContents;
 }
-class GURL;
-class PermissionInfoBarDelegate;
-class Profile;
 class TabAndroid;
 
 // Delegate class for displaying a permission prompt as a modal dialog. Used as
 // the native to Java interface to allow Java to communicate the user's
 // decision.
-//
-// This class owns a PermissionInfoBarDelegate if the PermissionRequestManager
-// is disabled and points to a PermissionPromptAndroid if it's enabled. When the
-// PermissionRequestManager is enabled by default, we can remove the code path
-// for using a PermissionInfoBarDelegate. This is tracked in crbug.com/606138.
 class PermissionDialogDelegate : public content::WebContentsObserver {
  public:
   using PermissionSetCallback = base::Callback<void(bool, PermissionAction)>;
@@ -43,23 +35,6 @@
   static void Create(content::WebContents* web_contents,
                      PermissionPromptAndroid* permission_prompt);
 
-  // The interface for creating a modal dialog when the PermissionRequestManager
-  // is disabled, i.e. we're using the PermissionQueueController.
-  static void Create(content::WebContents* web_contents,
-                     ContentSettingsType type,
-                     const GURL& requesting_frame,
-                     bool user_gesture,
-                     Profile* profile,
-                     const PermissionSetCallback& callback);
-
-  // Creates a modal dialog for a media stream permission request.
-  // TODO(dominickn): remove this when media stream requests are eventually
-  // folded in with other permission requests.
-  static void CreateMediaStreamDialog(
-      content::WebContents* web_contents,
-      bool user_gesture,
-      std::unique_ptr<MediaStreamDevicesController::Request> request);
-
   // Returns true if we should show the user a modal permission prompt rather
   // than an infobar.
   static bool ShouldShowDialog();
@@ -70,14 +45,13 @@
   void Dismissed(JNIEnv* env, const JavaParamRef<jobject>& obj);
   void LinkClicked(JNIEnv* env, const JavaParamRef<jobject>& obj);
 
-  // Frees this object and the wrapped PermissionInfoBarDelegate. Called from
-  // Java once the permission dialog has been responded to.
+  // Frees this object. Called from Java once the permission dialog has been
+  // responded to.
   void Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj);
 
  private:
   PermissionDialogDelegate(
       TabAndroid* tab,
-      std::unique_ptr<PermissionInfoBarDelegate> infobar_delegate,
       PermissionPromptAndroid* permission_prompt);
   ~PermissionDialogDelegate() override;
 
@@ -95,10 +69,6 @@
 
   TabAndroid* tab_;
 
-  // TODO(timloh): Remove this when the refactoring is finished and we can
-  // delete the PermissionQueueController.
-  std::unique_ptr<PermissionInfoBarDelegate> infobar_delegate_;
-
   // The PermissionPromptAndroid is deleted when either the dialog is resolved
   // or the tab is navigated/closed. We close the prompt on DidFinishNavigation
   // and WebContentsDestroyed, so it should always be safe to use this pointer.
diff --git a/chrome/browser/permissions/permission_infobar_delegate.cc b/chrome/browser/permissions/permission_infobar_delegate.cc
deleted file mode 100644
index b3eea78..0000000
--- a/chrome/browser/permissions/permission_infobar_delegate.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
-
-#include <utility>
-
-#include "build/build_config.h"
-#include "chrome/browser/geolocation/geolocation_infobar_delegate_android.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/media/midi_permission_infobar_delegate_android.h"
-#include "chrome/browser/media/protected_media_identifier_infobar_delegate_android.h"
-#include "chrome/browser/notifications/notification_permission_infobar_delegate.h"
-#include "chrome/browser/permissions/permission_decision_auto_blocker.h"
-#include "chrome/browser/permissions/permission_request.h"
-#include "chrome/browser/permissions/permission_uma_util.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/infobars/core/infobar.h"
-#include "components/url_formatter/elide_url.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/l10n/l10n_util.h"
-
-// static
-infobars::InfoBar* PermissionInfoBarDelegate::Create(
-    InfoBarService* infobar_service,
-    ContentSettingsType type,
-    const GURL& requesting_frame,
-    bool user_gesture,
-    Profile* profile,
-    const PermissionSetCallback& callback) {
-  std::unique_ptr<PermissionInfoBarDelegate> delegate =
-      PermissionInfoBarDelegate::CreateDelegate(
-          type, requesting_frame, user_gesture, profile, callback);
-
-  if (!delegate)
-    return nullptr;
-
-  return infobar_service->AddInfoBar(
-      CreatePermissionInfoBar(std::move(delegate)));
-}
-
-// static
-std::unique_ptr<PermissionInfoBarDelegate>
-PermissionInfoBarDelegate::CreateDelegate(
-    ContentSettingsType type,
-    const GURL& requesting_frame,
-    bool user_gesture,
-    Profile* profile,
-    const PermissionSetCallback& callback) {
-  switch (type) {
-    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
-      return std::unique_ptr<PermissionInfoBarDelegate>(
-              new GeolocationInfoBarDelegateAndroid(
-                  requesting_frame, user_gesture, profile, callback));
-    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
-    case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
-      return std::unique_ptr<PermissionInfoBarDelegate>(
-          new NotificationPermissionInfoBarDelegate(
-              type, requesting_frame, user_gesture, profile, callback));
-    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
-      return std::unique_ptr<PermissionInfoBarDelegate>(
-              new MidiPermissionInfoBarDelegateAndroid(
-                  requesting_frame, user_gesture, profile, callback));
-    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
-      return std::unique_ptr<PermissionInfoBarDelegate>(
-              new ProtectedMediaIdentifierInfoBarDelegateAndroid(
-                  requesting_frame, user_gesture, profile, callback));
-    default:
-      NOTREACHED();
-      return nullptr;
-  }
-}
-
-PermissionInfoBarDelegate::~PermissionInfoBarDelegate() {
-  if (!action_taken_) {
-    PermissionUmaUtil::PermissionIgnored(
-        content_settings_type_,
-        user_gesture_ ? PermissionRequestGestureType::GESTURE
-                      : PermissionRequestGestureType::NO_GESTURE,
-        requesting_origin_, profile_);
-
-    PermissionEmbargoStatus embargo_status =
-        PermissionEmbargoStatus::NOT_EMBARGOED;
-    if (PermissionDecisionAutoBlocker::GetForProfile(profile_)
-            ->RecordIgnoreAndEmbargo(requesting_origin_,
-                                     content_settings_type_)) {
-      embargo_status = PermissionEmbargoStatus::REPEATED_IGNORES;
-    }
-    PermissionUmaUtil::RecordEmbargoStatus(embargo_status);
-  }
-}
-
-std::vector<int> PermissionInfoBarDelegate::content_settings_types() const {
-  return std::vector<int>{content_settings_type_};
-}
-
-bool PermissionInfoBarDelegate::ShouldShowPersistenceToggle() const {
-  return PermissionUtil::ShouldShowPersistenceToggle(content_settings_type_);
-}
-
-bool PermissionInfoBarDelegate::Accept() {
-  bool update_content_setting = true;
-  if (ShouldShowPersistenceToggle()) {
-    update_content_setting = persist_;
-    PermissionUmaUtil::PermissionPromptAcceptedWithPersistenceToggle(
-        content_settings_type_, persist_);
-  }
-
-  SetPermission(update_content_setting, PermissionAction::GRANTED);
-  return true;
-}
-
-bool PermissionInfoBarDelegate::Cancel() {
-  bool update_content_setting = true;
-  if (ShouldShowPersistenceToggle()) {
-    update_content_setting = persist_;
-    PermissionUmaUtil::PermissionPromptDeniedWithPersistenceToggle(
-        content_settings_type_, persist_);
-  }
-
-  SetPermission(update_content_setting, PermissionAction::DENIED);
-  return true;
-}
-
-void PermissionInfoBarDelegate::InfoBarDismissed() {
-  SetPermission(false, PermissionAction::DISMISSED);
-}
-
-base::string16 PermissionInfoBarDelegate::GetButtonLabel(
-    InfoBarButton button) const {
-  return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_PERMISSION_ALLOW
-                                                         : IDS_PERMISSION_DENY);
-}
-
-base::string16 PermissionInfoBarDelegate::GetMessageText() const {
-  return l10n_util::GetStringFUTF16(
-      GetMessageResourceId(),
-      url_formatter::FormatUrlForSecurityDisplay(
-          requesting_origin_,
-          url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
-}
-
-PermissionInfoBarDelegate::PermissionInfoBarDelegate(
-    const GURL& requesting_origin,
-    ContentSettingsType content_settings_type,
-    bool user_gesture,
-    Profile* profile,
-    const PermissionSetCallback& callback)
-    : requesting_origin_(requesting_origin),
-      content_settings_type_(content_settings_type),
-      profile_(profile),
-      callback_(callback),
-      action_taken_(false),
-      user_gesture_(user_gesture),
-      persist_(true) {}
-
-infobars::InfoBarDelegate::Type PermissionInfoBarDelegate::GetInfoBarType()
-    const {
-  return PAGE_ACTION_TYPE;
-}
-
-PermissionInfoBarDelegate*
-PermissionInfoBarDelegate::AsPermissionInfoBarDelegate() {
-  return this;
-}
-
-void PermissionInfoBarDelegate::SetPermission(bool update_content_setting,
-                                              PermissionAction decision) {
-  action_taken_ = true;
-  callback_.Run(update_content_setting, decision);
-}
diff --git a/chrome/browser/permissions/permission_infobar_delegate.h b/chrome/browser/permissions/permission_infobar_delegate.h
deleted file mode 100644
index 9dfbf4b..0000000
--- a/chrome/browser/permissions/permission_infobar_delegate.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 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_PERMISSIONS_PERMISSION_INFOBAR_DELEGATE_H_
-#define CHROME_BROWSER_PERMISSIONS_PERMISSION_INFOBAR_DELEGATE_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "chrome/browser/permissions/permission_util.h"
-#include "components/content_settings/core/common/content_settings_types.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "url/gurl.h"
-
-namespace infobars {
-class InfoBar;
-}
-
-class InfoBarService;
-class Profile;
-
-// Base delegate class for permission prompts on Android. The default behavior
-// is that the accept/deny buttons grant/deny the relevant permission
-// respectively. A basic implementor only needs to implement the methods that
-// provide an icon and a message text to the infobar.
-//
-// By default, the user is presented with an infobar to make their choice. If
-// the experimental ModalPermissionPrompts feature is active, they will instead
-// see a modal dialog. Currently, this class is used for both; future
-// refactoring will be undertaken based on whether support for infobars is
-// retained following the modal prompt experiment.
-class PermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  using PermissionSetCallback = base::Callback<void(bool, PermissionAction)>;
-
-  // Creates an infobar for |type|. The returned pointer is owned by
-  // |infobar_service| and manages its own lifetime; callers must only use it
-  // for calls to |infobar_service|.
-  static infobars::InfoBar* Create(InfoBarService* infobar_service,
-                                   ContentSettingsType type,
-                                   const GURL& requesting_frame,
-                                   bool user_gesture,
-                                   Profile* profile,
-                                   const PermissionSetCallback& callback);
-
-  static std::unique_ptr<PermissionInfoBarDelegate> CreateDelegate(
-      ContentSettingsType type,
-      const GURL& requesting_frame,
-      bool user_gesture,
-      Profile* profile,
-      const PermissionSetCallback& callback);
-
-  ~PermissionInfoBarDelegate() override;
-  virtual std::vector<int> content_settings_types() const;
-
-  // Returns true if the infobar should display a toggle to allow users to
-  // opt-out of persisting their accept/deny decision.
-  bool ShouldShowPersistenceToggle() const;
-
-  // Sets whether or not a decided permission should be persisted to content
-  // settings.
-  void set_persist(bool persist) { persist_ = persist; }
-  bool persist() const { return persist_; }
-
-  bool user_gesture() const { return user_gesture_; }
-
-  // ConfirmInfoBarDelegate:
-  bool Accept() override;
-  bool Cancel() override;
-  void InfoBarDismissed() override;
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  base::string16 GetMessageText() const override;
-
- protected:
-  PermissionInfoBarDelegate(const GURL& requesting_origin,
-                            ContentSettingsType content_settings_type,
-                            bool user_gesture,
-                            Profile* profile,
-                            const PermissionSetCallback& callback);
-
- private:
-  // ConfirmInfoBarDelegate:
-  Type GetInfoBarType() const override;
-  PermissionInfoBarDelegate* AsPermissionInfoBarDelegate() override;
-
-  virtual int GetMessageResourceId() const = 0;
-  void SetPermission(bool update_content_setting, PermissionAction decision);
-
-  GURL requesting_origin_;
-  ContentSettingsType content_settings_type_;
-  Profile* const profile_;
-  const PermissionSetCallback callback_;
-  bool action_taken_;
-  bool user_gesture_;
-  bool persist_;
-
-  DISALLOW_COPY_AND_ASSIGN(PermissionInfoBarDelegate);
-};
-
-// Implemented in platform-specific code.
-std::unique_ptr<infobars::InfoBar> CreatePermissionInfoBar(
-    std::unique_ptr<PermissionInfoBarDelegate> delegate);
-
-#endif  // CHROME_BROWSER_PERMISSIONS_PERMISSION_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc
index 19c6834..563a03d 100644
--- a/chrome/browser/permissions/permission_manager.cc
+++ b/chrome/browser/permissions/permission_manager.cc
@@ -463,8 +463,12 @@
       continue;
     context->CancelPermissionRequest(web_contents, request);
   }
+
   // The request should be automatically removed from |pending_requests_| as a
   // result of it being cancelled but not necessarily immediately.
+  // TODO(timloh): It would be nice to DCHECK that the request is removed, but
+  // currently the PermissionUpdateInfobar (and maybe other places) does this
+  // asynchronously.
 }
 
 void PermissionManager::ResetPermission(PermissionType permission,
diff --git a/chrome/browser/permissions/permission_queue_controller.cc b/chrome/browser/permissions/permission_queue_controller.cc
deleted file mode 100644
index 8e8b770..0000000
--- a/chrome/browser/permissions/permission_queue_controller.cc
+++ /dev/null
@@ -1,455 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/permissions/permission_queue_controller.h"
-
-#include "build/build_config.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/permissions/permission_decision_auto_blocker.h"
-#include "chrome/browser/permissions/permission_dialog_delegate.h"
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
-#include "chrome/browser/permissions/permission_request.h"
-#include "chrome/browser/permissions/permission_request_id.h"
-#include "chrome/browser/permissions/permission_uma_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/common/content_settings.h"
-#include "components/infobars/core/infobar.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/url_constants.h"
-
-namespace {
-
-content::WebContents* GetWebContents(const PermissionRequestID& id) {
-  return tab_util::GetWebContentsByFrameID(
-      id.render_process_id(), id.render_frame_id());
-}
-
-
-InfoBarService* GetInfoBarService(const PermissionRequestID& id) {
-  content::WebContents* web_contents = GetWebContents(id);
-  return web_contents ? InfoBarService::FromWebContents(web_contents) : nullptr;
-}
-
-bool ArePermissionRequestsForSameTab(
-    const PermissionRequestID& request,
-    const PermissionRequestID& other_request) {
-  content::WebContents* web_contents = tab_util::GetWebContentsByFrameID(
-      request.render_process_id(), request.render_frame_id());
-  content::WebContents* other_web_contents = tab_util::GetWebContentsByFrameID(
-      other_request.render_process_id(), other_request.render_frame_id());
-
-  return web_contents == other_web_contents;
-}
-
-}  // anonymous namespace
-
-class PermissionQueueController::PendingInfobarRequest {
- public:
-  PendingInfobarRequest(ContentSettingsType type,
-                        const PermissionRequestID& id,
-                        const GURL& requesting_frame,
-                        const GURL& embedder,
-                        bool user_gesture,
-                        Profile* profile,
-                        const PermissionDecidedCallback& callback);
-  ~PendingInfobarRequest();
-
-  bool IsForPair(const GURL& requesting_frame,
-                 const GURL& embedder) const;
-
-  PermissionRequestType request_type() const {
-    return PermissionUtil::GetRequestType(type_);
-  }
-
-  PermissionRequestGestureType gesture_type() const {
-    return PermissionUtil::GetGestureType(user_gesture_);
-  }
-
-  const PermissionRequestID& id() const { return id_; }
-  const GURL& requesting_frame() const { return requesting_frame_; }
-  bool has_infobar() const { return !!infobar_; }
-  bool has_dialog() const { return has_dialog_; }
-  infobars::InfoBar* infobar() { return infobar_; }
-
-  void RunCallback(ContentSetting content_setting);
-  void CreatePrompt(PermissionQueueController* controller, bool show_dialog);
-
- private:
-  ContentSettingsType type_;
-  PermissionRequestID id_;
-  GURL requesting_frame_;
-  GURL embedder_;
-  bool user_gesture_;
-  Profile* profile_;
-  PermissionDecidedCallback callback_;
-  infobars::InfoBar* infobar_;
-  bool has_dialog_;
-
-  // Purposefully do not disable copying, as this is stored in STL containers.
-};
-
-PermissionQueueController::PendingInfobarRequest::PendingInfobarRequest(
-    ContentSettingsType type,
-    const PermissionRequestID& id,
-    const GURL& requesting_frame,
-    const GURL& embedder,
-    bool user_gesture,
-    Profile* profile,
-    const PermissionDecidedCallback& callback)
-    : type_(type),
-      id_(id),
-      requesting_frame_(requesting_frame),
-      embedder_(embedder),
-      user_gesture_(user_gesture),
-      profile_(profile),
-      callback_(callback),
-      infobar_(nullptr),
-      has_dialog_(false) {}
-
-PermissionQueueController::PendingInfobarRequest::~PendingInfobarRequest() {
-}
-
-bool PermissionQueueController::PendingInfobarRequest::IsForPair(
-    const GURL& requesting_frame,
-    const GURL& embedder) const {
-  return (requesting_frame_ == requesting_frame) && (embedder_ == embedder);
-}
-
-void PermissionQueueController::PendingInfobarRequest::RunCallback(
-    ContentSetting content_setting) {
-  callback_.Run(content_setting);
-}
-
-void PermissionQueueController::PendingInfobarRequest::CreatePrompt(
-    PermissionQueueController* controller,
-    bool show_dialog) {
-  // Controller can be Unretained because the lifetime of the infobar
-  // is tied to that of the queue controller. Before QueueController
-  // is destroyed, all requests will be cancelled and so all delegates
-  // will be destroyed.
-  PermissionInfoBarDelegate::PermissionSetCallback callback = base::Bind(
-      &PermissionQueueController::OnPermissionSet, base::Unretained(controller),
-      id_, requesting_frame_, embedder_, user_gesture_);
-
-  if (show_dialog) {
-    // We should show a dialog prompt instead of an infobar. Since only one
-    // dialog can be shown at a time, the Java-side owns and manages the queue
-    // of prompts; the bookkeeping in this class will work as expected:
-    //   i. no pending request will ever have an infobar created for it.
-    //  ii. OnPermissionSet is still called when the user makes a decision.
-    has_dialog_ = true;
-    PermissionDialogDelegate::Create(GetWebContents(id_), type_,
-                                     requesting_frame_, user_gesture_, profile_,
-                                     callback);
-  } else {
-    infobar_ = PermissionInfoBarDelegate::Create(
-        GetInfoBarService(id_), type_, requesting_frame_, user_gesture_,
-        profile_, callback);
-  }
-}
-
-PermissionQueueController::PermissionQueueController(
-    Profile* profile,
-    ContentSettingsType content_settings_type)
-    : profile_(profile),
-      content_settings_type_(content_settings_type),
-      in_shutdown_(false) {}
-
-PermissionQueueController::~PermissionQueueController() {
-  // Cancel all outstanding requests.
-  in_shutdown_ = true;
-  while (!pending_infobar_requests_.empty())
-    CancelInfoBarRequest(pending_infobar_requests_.front().id());
-}
-
-void PermissionQueueController::CreateInfoBarRequest(
-    const PermissionRequestID& id,
-    const GURL& requesting_frame,
-    const GURL& embedder,
-    bool user_gesture,
-    const PermissionDecidedCallback& callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  if (requesting_frame.SchemeIs(content::kChromeUIScheme) ||
-      embedder.SchemeIs(content::kChromeUIScheme))
-    return;
-
-  pending_infobar_requests_.push_back(
-      PendingInfobarRequest(content_settings_type_, id, requesting_frame,
-                            embedder, user_gesture, profile_, callback));
-  if (!AlreadyShowingInfoBarForTab(id))
-    ShowQueuedInfoBarForTab(id);
-}
-
-void PermissionQueueController::CancelInfoBarRequest(
-    const PermissionRequestID& id) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  for (PendingInfobarRequests::iterator i(pending_infobar_requests_.begin());
-       i != pending_infobar_requests_.end(); ++i) {
-    if (id != i->id())
-      continue;
-
-    InfoBarService* infobar_service = GetInfoBarService(id);
-    if (infobar_service && i->has_infobar())
-      infobar_service->RemoveInfoBar(i->infobar());
-    else
-      pending_infobar_requests_.erase(i);
-    return;
-  }
-}
-
-void PermissionQueueController::OnPermissionSet(const PermissionRequestID& id,
-                                                const GURL& requesting_frame,
-                                                const GURL& embedder,
-                                                bool user_gesture,
-                                                bool update_content_setting,
-                                                PermissionAction decision) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  PermissionRequestType request_type =
-      PermissionUtil::GetRequestType(content_settings_type_);
-  PermissionRequestGestureType gesture_type =
-      PermissionUtil::GetGestureType(user_gesture);
-  PermissionEmbargoStatus embargo_status =
-      PermissionEmbargoStatus::NOT_EMBARGOED;
-
-  switch (decision) {
-    case PermissionAction::GRANTED:
-      PermissionUmaUtil::PermissionGranted(content_settings_type_, gesture_type,
-                                           requesting_frame, profile_);
-      PermissionUmaUtil::RecordPermissionPromptAccepted(request_type,
-                                                        gesture_type);
-      break;
-    case PermissionAction::DENIED:
-      PermissionUmaUtil::PermissionDenied(content_settings_type_, gesture_type,
-                                          requesting_frame, profile_);
-      PermissionUmaUtil::RecordPermissionPromptDenied(request_type,
-                                                      gesture_type);
-      break;
-    case PermissionAction::DISMISSED:
-      PermissionUmaUtil::PermissionDismissed(
-          content_settings_type_, gesture_type, requesting_frame, profile_);
-      if (PermissionDecisionAutoBlocker::GetForProfile(profile_)
-              ->RecordDismissAndEmbargo(requesting_frame,
-                                        content_settings_type_)) {
-        embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS;
-      }
-      break;
-    default:
-      NOTREACHED();
-  }
-  PermissionUmaUtil::RecordEmbargoStatus(embargo_status);
-
-  // TODO(miguelg): move the permission persistence to
-  // PermissionContextBase once all the types are moved there.
-  if (update_content_setting)
-    UpdateContentSetting(requesting_frame, embedder, decision);
-
-  // Cancel this request first, then notify listeners.  TODO(pkasting): Why
-  // is this order important?
-  PendingInfobarRequests requests_to_notify;
-  PendingInfobarRequests infobars_to_remove;
-  std::vector<PendingInfobarRequests::iterator> pending_requests_to_remove;
-  for (PendingInfobarRequests::iterator i = pending_infobar_requests_.begin();
-       i != pending_infobar_requests_.end(); ++i) {
-    if (!i->IsForPair(requesting_frame, embedder))
-      continue;
-    requests_to_notify.push_back(*i);
-    if (!i->has_infobar()) {
-      // We haven't created an infobar yet, just record the pending request
-      // index and remove it later.
-      pending_requests_to_remove.push_back(i);
-      continue;
-    }
-    if (id == i->id()) {
-      // The infobar that called us is i->infobar(), and its delegate is
-      // currently in either Accept() or Cancel(). This means that
-      // RemoveInfoBar() will be called later on, and that will trigger a
-      // notification we're observing.
-      continue;
-    }
-
-    // This infobar is for the same frame/embedder pair, but in a different
-    // tab. We should remove it now that we've got an answer for it.
-    infobars_to_remove.push_back(*i);
-  }
-
-  // Remove all infobars for the same |requesting_frame| and |embedder|.
-  for (PendingInfobarRequests::iterator i = infobars_to_remove.begin();
-       i != infobars_to_remove.end(); ++i)
-    GetInfoBarService(i->id())->RemoveInfoBar(i->infobar());
-
-  // PermissionContextBase needs to know about the new ContentSetting value,
-  // CONTENT_SETTING_DEFAULT being the value for nothing happened. The callers
-  // of ::OnPermissionSet passes { bool, GRANTED } for allow, { bool, DENIED }
-  // for block and { false, DISMISSED } for dismissed. The tuple being
-  // { update_content_setting, decision }.
-  ContentSetting content_setting = CONTENT_SETTING_DEFAULT;
-  if (decision == PermissionAction::GRANTED)
-    content_setting = CONTENT_SETTING_ALLOW;
-  else if (decision == PermissionAction::DENIED)
-    content_setting = CONTENT_SETTING_BLOCK;
-  else
-    DCHECK_EQ(PermissionAction::DISMISSED, decision);
-
-  // Send out the permission notifications.
-  for (PendingInfobarRequests::iterator i = requests_to_notify.begin();
-       i != requests_to_notify.end(); ++i) {
-    i->RunCallback(content_setting);
-  }
-
-  // Remove the pending requests in reverse order.
-  for (int i = pending_requests_to_remove.size() - 1; i >= 0; --i)
-    pending_infobar_requests_.erase(pending_requests_to_remove[i]);
-}
-
-void PermissionQueueController::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, type);
-  // We will receive this notification for all infobar closures, so we need to
-  // check whether this is the geolocation infobar we're tracking. Note that the
-  // InfoBarContainer (if any) may have received this notification before us and
-  // caused the infobar to be deleted, so it's not safe to dereference the
-  // contents of the infobar. The address of the infobar, however, is OK to
-  // use to find the PendingInfobarRequest to remove because
-  // pending_infobar_requests_ will not have received any new entries between
-  // the NotificationService's call to InfoBarContainer::Observe and this
-  // method.
-  infobars::InfoBar* infobar =
-      content::Details<infobars::InfoBar::RemovedDetails>(details)->first;
-  for (PendingInfobarRequests::iterator i = pending_infobar_requests_.begin();
-       i != pending_infobar_requests_.end(); ++i) {
-    if (i->infobar() == infobar) {
-      PermissionRequestID id(i->id());
-      pending_infobar_requests_.erase(i);
-      ShowQueuedInfoBarForTab(id);
-      return;
-    }
-  }
-}
-
-bool PermissionQueueController::AlreadyShowingInfoBarForTab(
-    const PermissionRequestID& id) const {
-  for (PendingInfobarRequests::const_iterator i(
-           pending_infobar_requests_.begin());
-       i != pending_infobar_requests_.end(); ++i) {
-    if (ArePermissionRequestsForSameTab(i->id(), id) &&
-        (i->has_infobar() || i->has_dialog())) {
-      return true;
-    }
-  }
-  return false;
-}
-
-void PermissionQueueController::ShowQueuedInfoBarForTab(
-    const PermissionRequestID& id) {
-  DCHECK(!AlreadyShowingInfoBarForTab(id));
-
-  // We can get here for example during tab shutdown, when the InfoBarService is
-  // removing all existing infobars, thus calling back to Observe(). In this
-  // case the service still exists, and is supplied as the source of the
-  // notification we observed, but is no longer accessible from its WebContents.
-  // In this case we should just go ahead and cancel further infobars for this
-  // tab instead of trying to access the service.
-  //
-  // Similarly, if we're being destroyed, we should also avoid showing further
-  // infobars.
-  InfoBarService* infobar_service = GetInfoBarService(id);
-  if (!infobar_service || in_shutdown_) {
-    ClearPendingInfobarRequestsForTab(id);
-    return;
-  }
-
-  for (PendingInfobarRequests::iterator i = pending_infobar_requests_.begin();
-       i != pending_infobar_requests_.end(); ++i) {
-    if (ArePermissionRequestsForSameTab(i->id(), id) && !i->has_infobar()) {
-      // When using modal permission prompts, Java controls the display queue,
-      // so infobar notifications are not relevant.
-      bool show_dialog = PermissionDialogDelegate::ShouldShowDialog();
-      if (!show_dialog)
-        RegisterForInfoBarNotifications(infobar_service);
-
-      PermissionUmaUtil::RecordPermissionPromptShown(i->request_type(),
-                                                     i->gesture_type());
-      i->CreatePrompt(this, show_dialog);
-      return;
-    }
-  }
-
-  UnregisterForInfoBarNotifications(infobar_service);
-}
-
-void PermissionQueueController::ClearPendingInfobarRequestsForTab(
-    const PermissionRequestID& id) {
-  for (PendingInfobarRequests::iterator i = pending_infobar_requests_.begin();
-       i != pending_infobar_requests_.end(); ) {
-    if (ArePermissionRequestsForSameTab(i->id(), id)) {
-      DCHECK(!i->has_infobar());
-      i = pending_infobar_requests_.erase(i);
-    } else {
-      ++i;
-    }
-  }
-}
-
-void PermissionQueueController::RegisterForInfoBarNotifications(
-    InfoBarService* infobar_service) {
-  if (!registrar_.IsRegistered(
-      this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
-      content::Source<InfoBarService>(infobar_service))) {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
-                   content::Source<InfoBarService>(infobar_service));
-  }
-}
-
-void PermissionQueueController::UnregisterForInfoBarNotifications(
-    InfoBarService* infobar_service) {
-  if (registrar_.IsRegistered(
-      this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
-      content::Source<InfoBarService>(infobar_service))) {
-    registrar_.Remove(this,
-                      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
-                      content::Source<InfoBarService>(infobar_service));
-  }
-}
-
-void PermissionQueueController::UpdateContentSetting(
-    const GURL& requesting_frame,
-    const GURL& embedder,
-    PermissionAction decision) {
-  DCHECK(decision == PermissionAction::GRANTED ||
-         decision == PermissionAction::DENIED);
-  if (requesting_frame.GetOrigin().SchemeIsFile()) {
-    // Chrome can be launched with --disable-web-security which allows
-    // geolocation requests from file:// URLs. We don't want to store these
-    // in the host content settings map.
-    return;
-  }
-
-  ContentSetting content_setting = (decision == PermissionAction::GRANTED)
-                                       ? CONTENT_SETTING_ALLOW
-                                       : CONTENT_SETTING_BLOCK;
-
-  // TODO(timloh): Remove this logic when push and notification permissions
-  // are reconciled, see crbug.com/563297.
-  ContentSettingsType type_for_map = content_settings_type_;
-  if (type_for_map == CONTENT_SETTINGS_TYPE_PUSH_MESSAGING)
-    type_for_map = CONTENT_SETTINGS_TYPE_NOTIFICATIONS;
-  HostContentSettingsMapFactory::GetForProfile(profile_)
-      ->SetContentSettingDefaultScope(
-          requesting_frame.GetOrigin(), embedder.GetOrigin(),
-          type_for_map, std::string(), content_setting);
-}
diff --git a/chrome/browser/permissions/permission_queue_controller.h b/chrome/browser/permissions/permission_queue_controller.h
deleted file mode 100644
index ec73873..0000000
--- a/chrome/browser/permissions/permission_queue_controller.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERMISSIONS_PERMISSION_QUEUE_CONTROLLER_H_
-#define CHROME_BROWSER_PERMISSIONS_PERMISSION_QUEUE_CONTROLLER_H_
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "chrome/browser/permissions/permission_util.h"
-#include "components/content_settings/core/common/content_settings.h"
-#include "components/content_settings/core/common/content_settings_types.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-class GURL;
-class PermissionRequestID;
-class InfoBarService;
-class Profile;
-
-// This class controls an infobar queue per profile, and it's used by
-// GeolocationPermissionContext, and so on. It is only used on Android.
-// An alternate approach would be to have this queue per tab, and use
-// notifications to broadcast when permission is set / listen to notification to
-// cancel pending requests. This may be specially useful if there are other
-// things listening for such notifications.
-// For the time being this class is self-contained and it doesn't seem pulling
-// the notification infrastructure would simplify.
-class PermissionQueueController : public content::NotificationObserver {
- public:
-  using PermissionDecidedCallback = base::Callback<void(ContentSetting)>;
-
-  PermissionQueueController(Profile* profile,
-                            ContentSettingsType content_settings_type);
-  ~PermissionQueueController() override;
-
-  // The InfoBar will be displayed immediately if the tab is not already
-  // displaying one, otherwise it'll be queued.
-  void CreateInfoBarRequest(const PermissionRequestID& id,
-                            const GURL& requesting_frame,
-                            const GURL& embedder,
-                            bool user_gesture,
-                            const PermissionDecidedCallback& callback);
-
-  // Cancels a specific infobar request.
-  void CancelInfoBarRequest(const PermissionRequestID& id);
-
-  // Called by the InfoBarDelegate to notify permission has been set.
-  // It'll notify and dismiss any other pending InfoBar request for the same
-  // |requesting_frame| and embedder.
-  void OnPermissionSet(const PermissionRequestID& id,
-                       const GURL& requesting_frame,
-                       const GURL& embedder,
-                       bool user_gesture,
-                       bool update_content_setting,
-                       PermissionAction decision);
-
-  // Performs the update to content settings for a particular request frame
-  // context.
-  void UpdateContentSetting(const GURL& requesting_frame,
-                            const GURL& embedder,
-                            PermissionAction decision);
-
- protected:
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
- private:
-  class PendingInfobarRequest;
-  class RequestEquals;
-
-  typedef std::vector<PendingInfobarRequest> PendingInfobarRequests;
-
-  // Returns true if a geolocation infobar is already visible for the tab
-  // corresponding to |id|.
-  bool AlreadyShowingInfoBarForTab(const PermissionRequestID& id) const;
-
-  // Shows the next pending infobar for the tab corresponding to |id|, if any.
-  // Note that this may not be the pending request whose ID is |id| if other
-  // requests are higher in the queue.  If we can't show infobars because there
-  // is no InfoBarService for this tab, removes all queued requests for this
-  // tab.
-  void ShowQueuedInfoBarForTab(const PermissionRequestID& id);
-
-  void ClearPendingInfobarRequestsForTab(const PermissionRequestID& id);
-
-  void RegisterForInfoBarNotifications(InfoBarService* infobar_service);
-  void UnregisterForInfoBarNotifications(InfoBarService* infobar_service);
-
-  content::NotificationRegistrar registrar_;
-
-  Profile* const profile_;
-  ContentSettingsType content_settings_type_;
-  PendingInfobarRequests pending_infobar_requests_;
-  bool in_shutdown_;
-
-  DISALLOW_COPY_AND_ASSIGN(PermissionQueueController);
-};
-
-#endif  // CHROME_BROWSER_PERMISSIONS_PERMISSION_QUEUE_CONTROLLER_H_
diff --git a/chrome/browser/permissions/permission_queue_controller_unittest.cc b/chrome/browser/permissions/permission_queue_controller_unittest.cc
deleted file mode 100644
index f9ce02d..0000000
--- a/chrome/browser/permissions/permission_queue_controller_unittest.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/permissions/permission_queue_controller.h"
-
-#include "base/macros.h"
-#include "base/synchronization/waitable_event.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/permissions/permission_request_id.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/content_settings/core/common/content_settings_types.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/mock_render_process_host.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-
-// PermissionQueueControllerTests ---------------------------------------------
-
-class PermissionQueueControllerTests : public ChromeRenderViewHostTestHarness {
- protected:
-  PermissionQueueControllerTests() {}
-  ~PermissionQueueControllerTests() override {}
-
-  PermissionRequestID RequestID(int bridge_id) {
-    return PermissionRequestID(
-        web_contents()->GetRenderProcessHost()->GetID(),
-        web_contents()->GetMainFrame()->GetRoutingID(),
-        bridge_id);
-  }
-
- private:
-  // ChromeRenderViewHostTestHarness:
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-    InfoBarService::CreateForWebContents(web_contents());
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(PermissionQueueControllerTests);
-};
-
-
-// ObservationCountingQueueController -----------------------------------------
-
-class ObservationCountingQueueController : public PermissionQueueController {
- public:
-  explicit ObservationCountingQueueController(Profile* profile);
-  ~ObservationCountingQueueController() override;
-
-  int call_count() const { return call_count_; }
-
- private:
-  int call_count_;
-
-  // PermissionQueueController:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
-  DISALLOW_COPY_AND_ASSIGN(ObservationCountingQueueController);
-};
-
-ObservationCountingQueueController::ObservationCountingQueueController(
-    Profile* profile)
-    : PermissionQueueController(profile,
-                                CONTENT_SETTINGS_TYPE_GEOLOCATION),
-      call_count_(0) {}
-
-ObservationCountingQueueController::~ObservationCountingQueueController() {
-}
-
-void ObservationCountingQueueController::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, type);
-  ++call_count_;
-  PermissionQueueController::Observe(type, source, details);
-}
-
-
-// Actual tests ---------------------------------------------------------------
-
-TEST_F(PermissionQueueControllerTests, OneObservationPerInfoBarCancelled) {
-  // When an infobar is cancelled, the infobar helper sends a notification to
-  // the controller. If the controller has another infobar queued, it should
-  // maintain its registration for notifications with the helper, but on the
-  // last infobar cancellation it should unregister for notifications.
-  //
-  // What we don't want is for the controller to unregister and then re-register
-  // for notifications, which can lead to getting notified multiple times.  This
-  // test checks that in the case where the controller should remain registered
-  // for notifications, it gets notified exactly once."
-  ObservationCountingQueueController queue_controller(profile());
-  GURL url("http://www.example.com/geolocation");
-  base::Callback<void(ContentSetting)> callback;
-  queue_controller.CreateInfoBarRequest(RequestID(0), url, url,
-                                        false /* user_gesture */, callback);
-  queue_controller.CreateInfoBarRequest(RequestID(1), url, url,
-                                        false /* user_gesture */, callback);
-  queue_controller.CancelInfoBarRequest(RequestID(0));
-  EXPECT_EQ(1, queue_controller.call_count());
-}
-
-TEST_F(PermissionQueueControllerTests, FailOnBadPattern) {
-  ObservationCountingQueueController queue_controller(profile());
-  GURL url("chrome://settings");
-  base::Callback<void(ContentSetting)> callback;
-  queue_controller.CreateInfoBarRequest(RequestID(0), url, url,
-                                        false /* user_gesture */, callback);
-  queue_controller.CancelInfoBarRequest(RequestID(0));
-  EXPECT_EQ(0, queue_controller.call_count());
-}
diff --git a/chrome/browser/permissions/permission_request_manager.cc b/chrome/browser/permissions/permission_request_manager.cc
index 83a0577..ff752d8 100644
--- a/chrome/browser/permissions/permission_request_manager.cc
+++ b/chrome/browser/permissions/permission_request_manager.cc
@@ -8,7 +8,6 @@
 
 #include "base/command_line.h"
 #include "base/containers/circular_deque.h"
-#include "base/feature_list.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "build/build_config.h"
@@ -16,7 +15,6 @@
 #include "chrome/browser/permissions/permission_uma_util.h"
 #include "chrome/browser/ui/permission_bubble/permission_prompt.h"
 #include "chrome/browser/vr/vr_tab_helper.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
@@ -261,15 +259,6 @@
   return view_ && !requests_.empty();
 }
 
-// static
-bool PermissionRequestManager::IsEnabled() {
-#if defined(OS_ANDROID)
-  return base::FeatureList::IsEnabled(features::kUseGroupedPermissionInfobars);
-#else
-  return true;
-#endif
-}
-
 gfx::NativeWindow PermissionRequestManager::GetBubbleWindow() {
   if (view_)
     return view_->GetNativeWindow();
diff --git a/chrome/browser/permissions/permission_request_manager.h b/chrome/browser/permissions/permission_request_manager.h
index 864a60b..cd1ae65 100644
--- a/chrome/browser/permissions/permission_request_manager.h
+++ b/chrome/browser/permissions/permission_request_manager.h
@@ -92,10 +92,6 @@
   // TODO(hcarmona): Remove this as part of the bubble API work.
   bool IsBubbleVisible();
 
-  // Whether PermissionRequestManager is reused on Android, instead of
-  // PermissionQueueController.
-  static bool IsEnabled();
-
   // Get the native window of the bubble.
   // TODO(hcarmona): Remove this as part of the bubble API work.
   gfx::NativeWindow GetBubbleWindow();
diff --git a/chrome/browser/permissions/permission_request_manager_browsertest.cc b/chrome/browser/permissions/permission_request_manager_browsertest.cc
index 66afab57..701eabe 100644
--- a/chrome/browser/permissions/permission_request_manager_browsertest.cc
+++ b/chrome/browser/permissions/permission_request_manager_browsertest.cc
@@ -34,39 +34,6 @@
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
-namespace test {
-class MediaStreamDevicesControllerTestApi
-    : public MediaStreamDevicesController::PermissionPromptDelegate {
- public:
-  static void AddRequestToManager(
-      PermissionRequestManager* manager,
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback) {
-    MediaStreamDevicesControllerTestApi delegate(manager);
-    MediaStreamDevicesController::RequestPermissionsWithDelegate(
-        request, callback, &delegate);
-  }
-
- private:
-  // MediaStreamDevicesController::PermissionPromptDelegate:
-  void ShowPrompt(
-      bool user_gesture,
-      content::WebContents* web_contents,
-      std::unique_ptr<MediaStreamDevicesController::Request> request) override {
-    manager_->AddRequest(request.release());
-  }
-
-  explicit MediaStreamDevicesControllerTestApi(
-      PermissionRequestManager* manager)
-      : manager_(manager) {}
-
-  PermissionRequestManager* manager_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesControllerTestApi);
-};
-}  // namespace test
-
 namespace {
 
 const char* kPermissionsKillSwitchFieldStudy =
@@ -140,8 +107,6 @@
   GURL GetUrl() { return GURL("https://example.com"); }
 
   PermissionRequest* MakeRegisterProtocolHandlerRequest();
-  void AddMediaRequest(PermissionRequestManager* manager,
-                       ContentSettingsType permission);
   PermissionRequest* MakePermissionRequest(ContentSettingsType permission);
 
   // TestBrowserDialog:
@@ -167,43 +132,6 @@
                                                       GetUrl(), user_gesture);
 }
 
-void PermissionDialogTest::AddMediaRequest(PermissionRequestManager* manager,
-                                           ContentSettingsType permission) {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  content::MediaStreamRequestType request_type = content::MEDIA_DEVICE_ACCESS;
-  content::MediaStreamType audio_type = content::MEDIA_NO_SERVICE;
-  content::MediaStreamType video_type = content::MEDIA_NO_SERVICE;
-  std::string audio_id = "audio_id";
-  std::string video_id = "video_id";
-
-  if (permission == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)
-    audio_type = content::MEDIA_DEVICE_AUDIO_CAPTURE;
-  else
-    video_type = content::MEDIA_DEVICE_VIDEO_CAPTURE;
-  int render_process_id = web_contents->GetRenderProcessHost()->GetID();
-  int render_frame_id = web_contents->GetMainFrame()->GetRoutingID();
-  content::MediaStreamRequest request(render_process_id, render_frame_id, 0,
-                                      GetUrl(), false, request_type, audio_id,
-                                      video_id, audio_type, video_type, false);
-
-  // Add fake devices, otherwise the request will auto-block.
-  MediaCaptureDevicesDispatcher::GetInstance()->SetTestAudioCaptureDevices(
-      content::MediaStreamDevices(
-          1, content::MediaStreamDevice(content::MEDIA_DEVICE_AUDIO_CAPTURE,
-                                        audio_id, "Fake Audio")));
-  MediaCaptureDevicesDispatcher::GetInstance()->SetTestVideoCaptureDevices(
-      content::MediaStreamDevices(
-          1, content::MediaStreamDevice(content::MEDIA_DEVICE_VIDEO_CAPTURE,
-                                        video_id, "Fake Video")));
-
-  auto response = [](const content::MediaStreamDevices& devices,
-                     content::MediaStreamRequestResult result,
-                     std::unique_ptr<content::MediaStreamUI> ui) {};
-  test::MediaStreamDevicesControllerTestApi::AddRequestToManager(
-      manager, web_contents, request, base::Bind(response));
-}
-
 PermissionRequest* PermissionDialogTest::MakePermissionRequest(
     ContentSettingsType permission) {
   bool user_gesture = true;
@@ -252,14 +180,6 @@
       break;
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
-      if (base::FeatureList::IsEnabled(
-              features::kUsePermissionManagerForMediaRequests)) {
-        manager->AddRequest(MakePermissionRequest(it->type));
-      } else {
-        AddMediaRequest(manager, it->type);
-      }
-      break;
-    // Regular permissions requests.
     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
     case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:  // Same as notifications.
     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
@@ -592,25 +512,11 @@
 // Host wants to use your microphone.
 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_mic) {
   RunDialog();
-
-  {
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitAndEnableFeature(
-        features::kUsePermissionManagerForMediaRequests);
-    RunDialog();
-  }
 }
 
 // Host wants to use your camera.
 IN_PROC_BROWSER_TEST_F(PermissionDialogTest, InvokeDialog_camera) {
   RunDialog();
-
-  {
-    base::test::ScopedFeatureList scoped_feature_list;
-    scoped_feature_list.InitAndEnableFeature(
-        features::kUsePermissionManagerForMediaRequests);
-    RunDialog();
-  }
 }
 
 // Host wants to open email links.
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 273d554..440c62d 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -3177,33 +3177,6 @@
     : public PolicyTest,
       public testing::WithParamInterface<bool> {
  public:
-  // TODO(raymes): When crbug.com/606138 is finished and the
-  // PermissionRequestManager is used to show all prompts on Android/Desktop
-  // we should remove PermissionPromptDelegate and just use
-  // MockPermissionPromptFactory instead. The APIs are the same.
-  class TestPermissionPromptDelegate
-      : public MediaStreamDevicesController::PermissionPromptDelegate {
-   public:
-    void ShowPrompt(bool user_gesture,
-                    content::WebContents* web_contents,
-                    std::unique_ptr<MediaStreamDevicesController::Request>
-                        request) override {
-      if (response_type_ == PermissionRequestManager::ACCEPT_ALL)
-        request->PermissionGranted();
-      else if (response_type_ == PermissionRequestManager::DENY_ALL)
-        request->PermissionDenied();
-    }
-
-    void set_response_type(
-        PermissionRequestManager::AutoResponseType response_type) {
-      response_type_ = response_type;
-    }
-
-   private:
-    PermissionRequestManager::AutoResponseType response_type_ =
-        PermissionRequestManager::NONE;
-  };
-
   MediaStreamDevicesControllerBrowserTest()
       : request_url_allowed_via_whitelist_(false),
         request_url_("https://www.example.com/foo") {
@@ -3219,17 +3192,12 @@
     // since we are already using WithParamInterface. We only test whichever one
     // is enabled in chrome_features.cc since we won't keep the old path around
     // for long once we flip the flag.
-    if (base::FeatureList::IsEnabled(
-            features::kUsePermissionManagerForMediaRequests)) {
-      PermissionRequestManager* manager =
-          PermissionRequestManager::FromWebContents(
-              browser()->tab_strip_model()->GetActiveWebContents());
-      prompt_factory_.reset(new MockPermissionPromptFactory(manager));
-      prompt_factory_->set_response_type(PermissionRequestManager::ACCEPT_ALL);
-      manager->DisplayPendingRequests();
-    } else {
-      prompt_delegate_.set_response_type(PermissionRequestManager::ACCEPT_ALL);
-    }
+    PermissionRequestManager* manager =
+        PermissionRequestManager::FromWebContents(
+            browser()->tab_strip_model()->GetActiveWebContents());
+    prompt_factory_.reset(new MockPermissionPromptFactory(manager));
+    prompt_factory_->set_response_type(PermissionRequestManager::ACCEPT_ALL);
+    manager->DisplayPendingRequests();
   }
 
   void TearDownOnMainThread() override { prompt_factory_.reset(); }
@@ -3296,11 +3264,9 @@
         content::MEDIA_DEVICE_AUDIO_CAPTURE, content::MEDIA_NO_SERVICE));
     // TODO(raymes): Test MEDIA_DEVICE_OPEN (Pepper) which grants both webcam
     // and microphone permissions at the same time.
-    MediaStreamDevicesController::RequestPermissionsWithDelegate(
-        request,
-        base::Bind(&MediaStreamDevicesControllerBrowserTest::Accept,
-                   base::Unretained(this)),
-        &prompt_delegate_);
+    MediaStreamDevicesController::RequestPermissions(
+        request, base::Bind(&MediaStreamDevicesControllerBrowserTest::Accept,
+                            base::Unretained(this)));
 
     base::RunLoop::QuitCurrentWhenIdleDeprecated();
   }
@@ -3310,16 +3276,13 @@
         content::MEDIA_NO_SERVICE, content::MEDIA_DEVICE_VIDEO_CAPTURE));
     // TODO(raymes): Test MEDIA_DEVICE_OPEN (Pepper) which grants both webcam
     // and microphone permissions at the same time.
-    MediaStreamDevicesController::RequestPermissionsWithDelegate(
-        request,
-        base::Bind(&MediaStreamDevicesControllerBrowserTest::Accept,
-                   base::Unretained(this)),
-        &prompt_delegate_);
+    MediaStreamDevicesController::RequestPermissions(
+        request, base::Bind(&MediaStreamDevicesControllerBrowserTest::Accept,
+                            base::Unretained(this)));
 
     base::RunLoop::QuitCurrentWhenIdleDeprecated();
   }
 
-  TestPermissionPromptDelegate prompt_delegate_;
   std::unique_ptr<MockPermissionPromptFactory> prompt_factory_;
   bool policy_value_;
   bool request_url_allowed_via_whitelist_;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 1263f275..99d8a54 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/io_thread.h"
 #include "chrome/browser/media/media_device_id_salt.h"
 #include "chrome/browser/media/media_engagement_service.h"
+#include "chrome/browser/media/media_storage_id_salt.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h"
 #include "chrome/browser/metrics/chrome_metrics_service_client.h"
@@ -478,6 +479,7 @@
   MediaCaptureDevicesDispatcher::RegisterProfilePrefs(registry);
   MediaDeviceIDSalt::RegisterProfilePrefs(registry);
   MediaEngagementService::RegisterProfilePrefs(registry);
+  MediaStorageIdSalt::RegisterProfilePrefs(registry);
   MediaStreamDevicesController::RegisterProfilePrefs(registry);
   NavigationCorrectionTabObserver::RegisterProfilePrefs(registry);
   NotifierStateTracker::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
index 77f58823..149e632 100644
--- a/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
+++ b/chrome/browser/prefs/profile_pref_store_manager_unittest.cc
@@ -245,11 +245,8 @@
       ClearResetRecorded();
       // Force everything to be written to disk, triggering the PrefHashFilter
       // while our RegistryVerifier is watching.
-      pref_store_->CommitPendingWrite();
-      base::RunLoop().RunUntilIdle();
       base::RunLoop run_loop;
-      base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
-          FROM_HERE, base::BindOnce(&base::DoNothing), run_loop.QuitClosure());
+      pref_store_->CommitPendingWrite(run_loop.QuitClosure());
       run_loop.Run();
 
       pref_store_->RemoveObserver(&registry_verifier_);
@@ -275,11 +272,8 @@
                          base::MakeUnique<base::Value>(kFoobar),
                          WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
     pref_store->RemoveObserver(&registry_verifier_);
-    pref_store->CommitPendingWrite();
-    base::RunLoop().RunUntilIdle();
     base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostTaskAndReply(
-        FROM_HERE, base::BindOnce(&base::DoNothing), run_loop.QuitClosure());
+    pref_store->CommitPendingWrite(run_loop.QuitClosure());
     run_loop.Run();
   }
 
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 6227364..eead77d 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -379,9 +379,7 @@
   DCHECK_NE(ORIGIN_MAX, origin());
 
   prerender_manager_->RecordFinalStatus(origin(), final_status());
-
-  bool used = final_status() == FINAL_STATUS_USED;
-  prerender_manager_->RecordNetworkBytes(origin(), used, network_bytes_);
+  prerender_manager_->RecordNetworkBytesConsumed(origin(), network_bytes_);
 
   // Broadcast the removal of aliases.
   for (content::RenderProcessHost::iterator host_iterator =
diff --git a/chrome/browser/prerender/prerender_histograms.cc b/chrome/browser/prerender/prerender_histograms.cc
index fabba4f5..613afae 100644
--- a/chrome/browser/prerender/prerender_histograms.cc
+++ b/chrome/browser/prerender/prerender_histograms.cc
@@ -75,76 +75,14 @@
   return ComposeHistogramName("none", name);
 }
 
-bool OriginIsOmnibox(Origin origin) {
-  return origin == ORIGIN_OMNIBOX;
-}
-
 const char* FirstContentfulPaintHiddenName(bool was_hidden) {
   return was_hidden ? ".Hidden" : ".Visible";
 }
 
 }  // namespace
 
-// Helper macro for origin-based histogram reporting. All HISTOGRAM arguments
-// must be UMA_HISTOGRAM... macros that contain an argument "name" which this
-// macro will eventually substitute for the actual name used.
-#define PREFIXED_HISTOGRAM(histogram_name, origin, HISTOGRAM)                 \
-  do {                                                                        \
-    {                                                                         \
-      /* Do not rename.  HISTOGRAM expects a local variable "name". */        \
-      std::string name = ComposeHistogramName(std::string(), histogram_name); \
-      HISTOGRAM;                                                              \
-    }                                                                         \
-    /* Do not rename.  HISTOGRAM expects a local variable "name". */          \
-    std::string name = GetHistogramName(origin, histogram_name);              \
-    /* Branching because HISTOGRAM is caching the histogram into a static. */ \
-    if (origin == ORIGIN_OMNIBOX) {                                           \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_NONE) {                                       \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN) {              \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN) {             \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_EXTERNAL_REQUEST) {                           \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_INSTANT) {                                    \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_LINK_REL_NEXT) {                              \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_EXTERNAL_REQUEST_FORCED_PRERENDER) {          \
-      HISTOGRAM;                                                              \
-    } else if (origin == ORIGIN_OFFLINE) {                                    \
-      HISTOGRAM;                                                              \
-    } else {                                                                  \
-      HISTOGRAM;                                                              \
-    }                                                                         \
-  } while (0)
-
 PrerenderHistograms::PrerenderHistograms() {}
 
-void PrerenderHistograms::RecordPrerenderStarted(Origin origin) const {
-  if (OriginIsOmnibox(origin)) {
-    UMA_HISTOGRAM_ENUMERATION(
-        "Prerender.OmniboxPrerenderCount", 1, 2);
-  }
-}
-
-void PrerenderHistograms::RecordUsedPrerender(Origin origin) const {
-  if (OriginIsOmnibox(origin)) {
-    UMA_HISTOGRAM_ENUMERATION(
-        "Prerender.OmniboxNavigationsUsedPrerenderCount", 1, 2);
-  }
-}
-
-void PrerenderHistograms::RecordTimeSinceLastRecentVisit(
-    Origin origin,
-    base::TimeDelta delta) const {
-  PREFIXED_HISTOGRAM(
-      "TimeSinceLastRecentVisit", origin,
-      UMA_HISTOGRAM_TIMES(name, delta));
-}
-
 void PrerenderHistograms::RecordPerceivedFirstContentfulPaintStatus(
     Origin origin,
     bool successful,
@@ -154,70 +92,20 @@
                             successful);
 }
 
-void PrerenderHistograms::RecordPercentLoadDoneAtSwapin(Origin origin,
-                                                        double fraction) const {
-  if (fraction < 0.0 || fraction > 1.0)
-    return;
-  int percentage = static_cast<int>(fraction * 100);
-  if (percentage < 0 || percentage > 100)
-    return;
-  PREFIXED_HISTOGRAM("PercentLoadDoneAtSwapin",
-                     origin, UMA_HISTOGRAM_PERCENTAGE(name, percentage));
-}
-
-void PrerenderHistograms::RecordTimeUntilUsed(
-    Origin origin,
-    base::TimeDelta time_until_used) const {
-  PREFIXED_HISTOGRAM(
-      "TimeUntilUsed2", origin,
-      UMA_HISTOGRAM_CUSTOM_TIMES(
-          name,
-          time_until_used,
-          base::TimeDelta::FromMilliseconds(10),
-          base::TimeDelta::FromMinutes(30),
-          50));
-}
-
-void PrerenderHistograms::RecordAbandonTimeUntilUsed(
-    Origin origin,
-    base::TimeDelta time_until_used) const {
-  PREFIXED_HISTOGRAM(
-      "AbandonTimeUntilUsed", origin,
-      UMA_HISTOGRAM_CUSTOM_TIMES(
-          name,
-          time_until_used,
-          base::TimeDelta::FromMilliseconds(10),
-          base::TimeDelta::FromSeconds(30),
-          50));
-}
-
-void PrerenderHistograms::RecordPerSessionCount(Origin origin,
-                                                int count) const {
-  PREFIXED_HISTOGRAM(
-      "PrerendersPerSessionCount", origin,
-      UMA_HISTOGRAM_COUNTS(name, count));
-}
-
-void PrerenderHistograms::RecordTimeBetweenPrerenderRequests(
-    Origin origin, base::TimeDelta time) const {
-  PREFIXED_HISTOGRAM(
-      "TimeBetweenPrerenderRequests", origin,
-      UMA_HISTOGRAM_TIMES(name, time));
-}
-
 void PrerenderHistograms::RecordFinalStatus(
     Origin origin,
     FinalStatus final_status) const {
   DCHECK(final_status != FINAL_STATUS_MAX);
-  PREFIXED_HISTOGRAM(
-      "FinalStatus", origin,
-      UMA_HISTOGRAM_ENUMERATION(name, final_status, FINAL_STATUS_MAX));
+  base::UmaHistogramEnumeration(GetHistogramName(origin, "FinalStatus"),
+                                final_status, FINAL_STATUS_MAX);
+  base::UmaHistogramEnumeration(ComposeHistogramName("", "FinalStatus"),
+                                final_status, FINAL_STATUS_MAX);
 }
 
-void PrerenderHistograms::RecordNetworkBytes(Origin origin,
-                                             bool used,
-                                             int64_t prerender_bytes,
-                                             int64_t profile_bytes) const {
+void PrerenderHistograms::RecordNetworkBytesConsumed(
+    Origin origin,
+    int64_t prerender_bytes,
+    int64_t profile_bytes) const {
   const int kHistogramMin = 1;
   const int kHistogramMax = 100000000;  // 100M.
   const int kBucketCount = 50;
@@ -231,19 +119,12 @@
   if (prerender_bytes == 0)
     return;
 
-  if (used) {
-    PREFIXED_HISTOGRAM(
-        "NetworkBytesUsed",
-        origin,
-        UMA_HISTOGRAM_CUSTOM_COUNTS(
-            name, prerender_bytes, kHistogramMin, kHistogramMax, kBucketCount));
-  } else {
-    PREFIXED_HISTOGRAM(
-        "NetworkBytesWasted",
-        origin,
-        UMA_HISTOGRAM_CUSTOM_COUNTS(
-            name, prerender_bytes, kHistogramMin, kHistogramMax, kBucketCount));
-  }
+  base::UmaHistogramCustomCounts(GetHistogramName(origin, "NetworkBytesWasted"),
+                                 prerender_bytes, kHistogramMin, kHistogramMax,
+                                 kBucketCount);
+  base::UmaHistogramCustomCounts(ComposeHistogramName("", "NetworkBytesWasted"),
+                                 prerender_bytes, kHistogramMin, kHistogramMax,
+                                 kBucketCount);
 }
 
 void PrerenderHistograms::RecordPrefetchResponseReceived(
diff --git a/chrome/browser/prerender/prerender_histograms.h b/chrome/browser/prerender/prerender_histograms.h
index 3fda4be..c1b81a9 100644
--- a/chrome/browser/prerender/prerender_histograms.h
+++ b/chrome/browser/prerender/prerender_histograms.h
@@ -51,48 +51,21 @@
                                                  bool successful,
                                                  bool was_hidden) const;
 
-  // Records, in a histogram, the percentage of the page load time that had
-  // elapsed by the time it is swapped in.  Values outside of [0, 1.0] are
-  // invalid and ignored.
-  void RecordPercentLoadDoneAtSwapin(Origin origin, double fraction) const;
-
-  // Records the time from when a page starts prerendering to when the user
-  // navigates to it. This must be called on the UI thread.
-  void RecordTimeUntilUsed(Origin origin,
-                           base::TimeDelta time_until_used) const;
-
-  // Records the time from when a prerender is abandoned to when the user
-  // navigates to it. This must be called on the UI thread.
-  void RecordAbandonTimeUntilUsed(Origin origin,
-                                  base::TimeDelta time_until_used) const;
-
   // Record a PerSessionCount data point.
   void RecordPerSessionCount(Origin origin, int count) const;
 
-  // Record time between two prerender requests.
-  void RecordTimeBetweenPrerenderRequests(Origin origin,
-                                          base::TimeDelta time) const;
-
   // Record a final status of a prerendered page in a histogram.
   void RecordFinalStatus(Origin origin, FinalStatus final_status) const;
 
   // To be called when a new prerender is started.
   void RecordPrerenderStarted(Origin origin) const;
 
-  // Called when we swap in a prerender.
-  void RecordUsedPrerender(Origin origin) const;
-
-  // Record the time since a page was recently visited.
-  void RecordTimeSinceLastRecentVisit(Origin origin,
-                                      base::TimeDelta time) const;
-
-  // Record the bytes in the prerender, whether it was used or not, and the
+  // Record the histogram for number of bytes consumed by the prerender, and the
   // total number of bytes fetched for this profile since the last call to
   // RecordBytes.
-  void RecordNetworkBytes(Origin origin,
-                          bool used,
-                          int64_t prerender_bytes,
-                          int64_t profile_bytes) const;
+  void RecordNetworkBytesConsumed(Origin origin,
+                                  int64_t prerender_bytes,
+                                  int64_t profile_bytes) const;
 
   // Called when a NoStatePrefetch request has received a response (including
   // redirects). May be called several times per resource, in case of redirects.
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 682e0868..00a7cb5 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -160,9 +160,6 @@
 PrerenderManagerObserver::~PrerenderManagerObserver() {}
 
 // static
-int PrerenderManager::prerenders_per_session_count_ = 0;
-
-// static
 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
     PRERENDER_MODE_SIMPLE_LOAD_EXPERIMENT;
 PrerenderManager::PrerenderManagerMode PrerenderManager::instant_mode_ =
@@ -441,20 +438,6 @@
       prerender_data->contents()->GetRenderViewHost()->GetProcess();
   process_host->RemoveObserver(this);
   prerender_process_hosts_.erase(process_host);
-  if (!prerender_data->contents()->load_start_time().is_null()) {
-    histograms_->RecordTimeUntilUsed(
-        prerender_data->contents()->origin(),
-        GetCurrentTimeTicks() - prerender_data->contents()->load_start_time());
-  }
-  histograms_->RecordAbandonTimeUntilUsed(
-      prerender_data->contents()->origin(),
-      prerender_data->abandon_time().is_null() ?
-          base::TimeDelta() :
-          GetCurrentTimeTicks() - prerender_data->abandon_time());
-
-  histograms_->RecordPerSessionCount(prerender_data->contents()->origin(),
-                                     ++prerenders_per_session_count_);
-  histograms_->RecordUsedPrerender(prerender_data->contents()->origin());
 
   PrerenderDataVector::iterator to_erase =
       FindIteratorForPrerenderContents(prerender_data->contents());
@@ -744,11 +727,8 @@
   CleanUpOldNavigations(&navigations_, base::TimeDelta::FromMilliseconds(
                                            kNavigationRecordWindowMs));
   for (auto it = navigations_.rbegin(); it != navigations_.rend(); ++it) {
-    if (it->url == url) {
-      base::TimeDelta delta = GetCurrentTimeTicks() - it->time;
-      histograms_->RecordTimeSinceLastRecentVisit(origin, delta);
+    if (it->url == url)
       return true;
-    }
   }
 
   return false;
@@ -1000,7 +980,6 @@
     return nullptr;
   }
 
-  histograms_->RecordPrerenderStarted(origin);
   DCHECK(!prerender_contents_ptr->prerendering_has_started());
 
   std::unique_ptr<PrerenderHandle> prerender_handle =
@@ -1162,10 +1141,6 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::TimeDelta elapsed_time =
       GetCurrentTimeTicks() - last_prerender_start_time_;
-  histograms_->RecordTimeBetweenPrerenderRequests(origin, elapsed_time);
-  // TODO(gabadie,pasko): Re-implement missing tests for
-  // FINAL_STATUS_RATE_LIMIT_EXCEEDED that where removed by:
-  //    http://crrev.com/a2439eeab37f7cb7a118493fb55ec0cb07f93b49.
   if (origin == ORIGIN_OFFLINE)
     return true;
   if (!config_.rate_limit_enabled)
@@ -1304,17 +1279,16 @@
   prerender_contents->Destroy(FINAL_STATUS_CREATING_AUDIO_STREAM);
 }
 
-void PrerenderManager::RecordNetworkBytes(Origin origin,
-                                          bool used,
-                                          int64_t prerender_bytes) {
+void PrerenderManager::RecordNetworkBytesConsumed(Origin origin,
+                                                  int64_t prerender_bytes) {
   if (!IsAnyPrerenderingPossible())
     return;
   int64_t recent_profile_bytes =
       profile_network_bytes_ - last_recorded_profile_network_bytes_;
   last_recorded_profile_network_bytes_ = profile_network_bytes_;
   DCHECK_GE(recent_profile_bytes, 0);
-  histograms_->RecordNetworkBytes(
-      origin, used, prerender_bytes, recent_profile_bytes);
+  histograms_->RecordNetworkBytesConsumed(origin, prerender_bytes,
+                                          recent_profile_bytes);
 }
 
 NetworkPredictionStatus PrerenderManager::GetPredictionStatus() const {
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index 870a585..768a2be3 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -348,7 +348,7 @@
 
   // Notification that a prerender has completed and its bytes should be
   // recorded.
-  void RecordNetworkBytes(Origin origin, bool used, int64_t prerender_bytes);
+  void RecordNetworkBytesConsumed(Origin origin, int64_t prerender_bytes);
 
   // Add to the running tally of bytes transferred over the network for this
   // profile if prerendering is currently enabled.
@@ -597,10 +597,6 @@
   static PrerenderManagerMode instant_mode_;
   static PrerenderManagerMode omnibox_mode_;
 
-  // A count of how many prerenders we do per session. Initialized to 0 then
-  // incremented and emitted to a histogram on each successful prerender.
-  static int prerenders_per_session_count_;
-
   // RepeatingTimer to perform periodic cleanups of pending prerendered
   // pages.
   base::RepeatingTimer repeating_timer_;
diff --git a/chrome/browser/printing/pwg_raster_converter_browsertest.cc b/chrome/browser/printing/pwg_raster_converter_browsertest.cc
new file mode 100644
index 0000000..46d3253
--- /dev/null
+++ b/chrome/browser/printing/pwg_raster_converter_browsertest.cc
@@ -0,0 +1,111 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/base/in_process_browser_test.h"
+
+#include "base/files/file_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+#include "chrome/browser/printing/pwg_raster_converter.h"
+#include "printing/pdf_render_settings.h"
+#include "printing/pwg_raster_settings.h"
+
+namespace printing {
+
+namespace {
+
+void ResultCallbackImpl(bool* called,
+                        bool* success_out,
+                        base::FilePath* temp_file_out,
+                        base::Closure quit_closure,
+                        bool success_in,
+                        const base::FilePath& temp_file_in) {
+  *called = true;
+  *success_out = success_in;
+  *temp_file_out = temp_file_in;
+  quit_closure.Run();
+}
+
+class PDFToPWGRasterBrowserTest : public InProcessBrowserTest {
+ public:
+  PDFToPWGRasterBrowserTest()
+      : converter_(PWGRasterConverter::CreateDefault()) {}
+  ~PDFToPWGRasterBrowserTest() override {}
+
+  void Convert(base::RefCountedMemory* pdf_data,
+               const PdfRenderSettings& conversion_settings,
+               const PwgRasterSettings& bitmap_settings,
+               bool expect_success,
+               base::FilePath* temp_file) {
+    bool called = false;
+    bool success = false;
+    base::RunLoop run_loop;
+    converter_->Start(pdf_data, conversion_settings, bitmap_settings,
+                      base::Bind(&ResultCallbackImpl, &called, &success,
+                                 temp_file, run_loop.QuitClosure()));
+    run_loop.Run();
+    ASSERT_TRUE(called);
+    EXPECT_EQ(success, expect_success);
+  }
+
+ private:
+  std::unique_ptr<PWGRasterConverter> converter_;
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(PDFToPWGRasterBrowserTest, TestFailure) {
+  scoped_refptr<base::RefCountedStaticMemory> bad_pdf_data =
+      base::MakeRefCounted<base::RefCountedStaticMemory>("0123456789", 10);
+  base::FilePath temp_file;
+  Convert(bad_pdf_data.get(), PdfRenderSettings(), PwgRasterSettings(),
+          /*expect_success=*/false, &temp_file);
+}
+
+IN_PROC_BROWSER_TEST_F(PDFToPWGRasterBrowserTest, TestSuccess) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  base::FilePath test_data_dir;
+  ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+  base::FilePath pdf_file = test_data_dir.AppendASCII(
+      "chrome/test/data/printing/pdf_to_pwg_raster_test.pdf");
+  std::string pdf_data_str;
+  ASSERT_TRUE(base::ReadFileToString(pdf_file, &pdf_data_str));
+  ASSERT_GT(pdf_data_str.length(), 0U);
+  scoped_refptr<base::RefCountedString> pdf_data(
+      base::RefCountedString::TakeString(&pdf_data_str));
+
+  PdfRenderSettings pdf_settings(gfx::Rect(0, 0, 500, 500), gfx::Point(0, 0),
+                                 /*dpi=*/1000, /*autorotate=*/false,
+                                 PdfRenderSettings::Mode::NORMAL);
+  PwgRasterSettings pwg_settings;
+  pwg_settings.odd_page_transform = PwgRasterTransformType::TRANSFORM_NORMAL;
+  pwg_settings.rotate_all_pages = false;
+  pwg_settings.reverse_page_order = false;
+
+  base::FilePath temp_file;
+  Convert(pdf_data.get(), pdf_settings, pwg_settings,
+          /*expect_success=*/true, &temp_file);
+  ASSERT_FALSE(temp_file.empty());
+
+  // Note that for some reason the generated PWG varies depending on the
+  // platform (32 or 64 bits) on Linux.
+  base::FilePath pwg_file = test_data_dir.AppendASCII(
+#if defined(OS_LINUX) && defined(ARCH_CPU_32_BITS)
+      "chrome/test/data/printing/pdf_to_pwg_raster_test_32.pwg");
+#else
+      "chrome/test/data/printing/pdf_to_pwg_raster_test.pwg");
+#endif
+
+  std::string pwg_expected_data_str;
+  ASSERT_TRUE(base::ReadFileToString(pwg_file, &pwg_expected_data_str));
+  std::string pwg_actual_data_str;
+  ASSERT_TRUE(base::ReadFileToString(temp_file, &pwg_actual_data_str));
+  ASSERT_EQ(pwg_expected_data_str, pwg_actual_data_str);
+}
+
+}  // namespace printing
diff --git a/chrome/browser/process_singleton_modal_dialog_lock.cc b/chrome/browser/process_singleton_modal_dialog_lock.cc
index 62a20e5e3..7bbc521 100644
--- a/chrome/browser/process_singleton_modal_dialog_lock.cc
+++ b/chrome/browser/process_singleton_modal_dialog_lock.cc
@@ -4,48 +4,19 @@
 
 #include "chrome/browser/process_singleton_modal_dialog_lock.h"
 
-#if defined(OS_WIN)
-#include <Windows.h>
-#endif
+#include <utility>
 
 #include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "build/build_config.h"
-
-namespace {
-
-#if !defined(OS_WIN) || defined(USE_AURA)
-void DoSetForegroundWindow(gfx::NativeWindow /* target_window */) {
-  NOTREACHED();
-}
-#else
-void DoSetForegroundWindow(HWND target_window) {
-  ::SetForegroundWindow(target_window);
-}
-#endif
-
-}  // namespace
 
 ProcessSingletonModalDialogLock::ProcessSingletonModalDialogLock(
     const ProcessSingleton::NotificationCallback& original_callback)
-    : active_dialog_(NULL),
-      original_callback_(original_callback),
-      set_foreground_window_handler_(base::Bind(&DoSetForegroundWindow)) {}
-
-ProcessSingletonModalDialogLock::ProcessSingletonModalDialogLock(
-    const ProcessSingleton::NotificationCallback& original_callback,
-    const SetForegroundWindowHandler& set_foreground_window_handler)
-    : active_dialog_(NULL),
-      original_callback_(original_callback),
-      set_foreground_window_handler_(set_foreground_window_handler) {}
+    : original_callback_(original_callback) {}
 
 ProcessSingletonModalDialogLock::~ProcessSingletonModalDialogLock() {}
 
-void ProcessSingletonModalDialogLock::SetActiveModalDialog(
-    gfx::NativeWindow active_dialog) {
-  active_dialog_ = active_dialog;
+void ProcessSingletonModalDialogLock::SetModalDialogNotificationHandler(
+    base::Closure notification_handler) {
+  notification_handler_ = std::move(notification_handler);
 }
 
 ProcessSingleton::NotificationCallback
@@ -57,10 +28,8 @@
 bool ProcessSingletonModalDialogLock::NotificationCallbackImpl(
     const base::CommandLine& command_line,
     const base::FilePath& current_directory) {
-  if (active_dialog_ != NULL) {
-    set_foreground_window_handler_.Run(active_dialog_);
-    return true;
-  } else {
-    return original_callback_.Run(command_line, current_directory);
-  }
+  if (notification_handler_)
+    notification_handler_.Run();
+
+  return original_callback_.Run(command_line, current_directory);
 }
diff --git a/chrome/browser/process_singleton_modal_dialog_lock.h b/chrome/browser/process_singleton_modal_dialog_lock.h
index e597668..ac1c566 100644
--- a/chrome/browser/process_singleton_modal_dialog_lock.h
+++ b/chrome/browser/process_singleton_modal_dialog_lock.h
@@ -5,44 +5,33 @@
 #ifndef CHROME_BROWSER_PROCESS_SINGLETON_MODAL_DIALOG_LOCK_H_
 #define CHROME_BROWSER_PROCESS_SINGLETON_MODAL_DIALOG_LOCK_H_
 
-#include "base/callback_forward.h"
+#include "base/callback.h"
 #include "base/macros.h"
 #include "chrome/browser/process_singleton.h"
-#include "ui/gfx/native_widget_types.h"
 
 namespace base {
 class CommandLine;
 class FilePath;
 }
 
-// Provides a ProcessSingleton::NotificationCallback that prevents
-// command-line handling when a modal dialog is active during startup. The
-// client must ensure that SetActiveModalDialog is called appropriately when
-// such dialogs are displayed or dismissed.
+// Provides a ProcessSingleton::NotificationCallback that allows for closing a
+// modal dialog that is active during startup. The client must ensure that
+// SetModalDialogCallback is called appropriately when such dialogs are
+// displayed or dismissed.
 //
-// While a dialog is active, the ProcessSingleton notification
-// callback will handle but ignore notifications:
-// 1. Neither this process nor the invoking process will handle the command
-//    line.
-// 2. The active dialog is brought to the foreground and/or the taskbar icon
-//    flashed (using ::SetForegroundWindow on Windows).
-//
-// Otherwise, the notification is forwarded to a wrapped NotificationCallback.
+// After invoking the modal dialog's callback, this process will continue normal
+// processing of the command line by forwarding the notification to a wrapped
+// NotificationCallback.
 class ProcessSingletonModalDialogLock {
  public:
-  typedef base::Callback<void(gfx::NativeWindow)> SetForegroundWindowHandler;
   explicit ProcessSingletonModalDialogLock(
       const ProcessSingleton::NotificationCallback& original_callback);
 
-  ProcessSingletonModalDialogLock(
-      const ProcessSingleton::NotificationCallback& original_callback,
-      const SetForegroundWindowHandler& set_foreground_window_handler);
-
   ~ProcessSingletonModalDialogLock();
 
-  // Receives a handle to the active modal dialog, or NULL if the active dialog
-  // is dismissed.
-  void SetActiveModalDialog(gfx::NativeWindow active_dialog);
+  // Receives a callback to be run to close the active modal dialog, or an empty
+  // closure if the active dialog is dismissed.
+  void SetModalDialogNotificationHandler(base::Closure notification_handler);
 
   // Returns the ProcessSingleton::NotificationCallback.
   // The callback is only valid during the lifetime of the
@@ -53,9 +42,8 @@
   bool NotificationCallbackImpl(const base::CommandLine& command_line,
                                 const base::FilePath& current_directory);
 
-  gfx::NativeWindow active_dialog_;
+  base::Closure notification_handler_;
   ProcessSingleton::NotificationCallback original_callback_;
-  SetForegroundWindowHandler set_foreground_window_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(ProcessSingletonModalDialogLock);
 };
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index e692ce5..27d85f7b 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -142,7 +142,8 @@
 #include "chrome/browser/ui/desktop_ios_promotion/sms_service_factory.h"
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#include "chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.h"
 #include "chrome/browser/feature_engagement/new_tab/new_tab_tracker_factory.h"
 #endif
 
@@ -290,7 +291,8 @@
   MediaGalleriesPreferencesFactory::GetInstance();
   NTPResourceCacheFactory::GetInstance();
 #endif
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+  feature_engagement::BookmarkTrackerFactory::GetInstance();
   feature_engagement::NewTabTrackerFactory::GetInstance();
 #endif
   ContentSuggestionsServiceFactory::GetInstance();
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 0886548..a4215b1 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -339,7 +339,7 @@
 
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
 void SignOut(SigninManager* signin_manager) {
-  signin_manager->SignOut(
+  signin_manager->SignOutAndRemoveAllAccounts(
       signin_metrics::AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
 }
diff --git a/chrome/browser/profiling_host/BUILD.gn b/chrome/browser/profiling_host/BUILD.gn
index 533bbbf..7133ead 100644
--- a/chrome/browser/profiling_host/BUILD.gn
+++ b/chrome/browser/profiling_host/BUILD.gn
@@ -6,6 +6,8 @@
 
 static_library("profiling_host") {
   sources = [
+    "background_profiling_triggers.cc",
+    "background_profiling_triggers.h",
     "chrome_browser_main_extra_parts_profiling.cc",
     "chrome_browser_main_extra_parts_profiling.h",
     "profiling_process_host.cc",
diff --git a/chrome/browser/profiling_host/background_profiling_triggers.cc b/chrome/browser/profiling_host/background_profiling_triggers.cc
new file mode 100644
index 0000000..6a0d65c
--- /dev/null
+++ b/chrome/browser/profiling_host/background_profiling_triggers.cc
@@ -0,0 +1,95 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/profiling_host/background_profiling_triggers.h"
+
+#include "base/task_scheduler/post_task.h"
+#include "chrome/browser/profiling_host/profiling_process_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
+
+namespace profiling {
+
+namespace {
+// Check memory usage every hour. Trigger slow report if needed.
+const int kRepeatingCheckMemoryDelayInHours = 1;
+const int kSecondReportRepeatingCheckMemoryDelayInHours = 12;
+const size_t kBrowserProcessMallocTriggerKb = 600 * 1024;    // 600 Meg
+const size_t kRendererProcessMallocTriggerKb = 2000 * 1024;  // 2 Gig
+}  // namespace
+
+BackgroundProfilingTriggers::BackgroundProfilingTriggers(
+    ProfilingProcessHost* host)
+    : host_(host), weak_ptr_factory_(this) {
+  DCHECK(host_);
+}
+
+BackgroundProfilingTriggers::~BackgroundProfilingTriggers() {}
+
+void BackgroundProfilingTriggers::StartTimer() {
+  // Register a repeating timer to check memory usage periodically.
+  timer_.Start(
+      FROM_HERE, base::TimeDelta::FromHours(kRepeatingCheckMemoryDelayInHours),
+      base::Bind(&BackgroundProfilingTriggers::PerformMemoryUsageChecks,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BackgroundProfilingTriggers::PerformMemoryUsageChecks() {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::BindOnce(
+          &BackgroundProfilingTriggers::PerformMemoryUsageChecksOnIOThread,
+          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BackgroundProfilingTriggers::PerformMemoryUsageChecksOnIOThread() {
+  memory_instrumentation::MemoryInstrumentation::GetInstance()
+      ->RequestGlobalDump(
+          base::Bind(&BackgroundProfilingTriggers::OnReceivedMemoryDump,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BackgroundProfilingTriggers::OnReceivedMemoryDump(
+    bool success,
+    memory_instrumentation::mojom::GlobalMemoryDumpPtr dump) {
+  if (!success)
+    return;
+
+  ProfilingProcessHost::Mode mode = host_->mode();
+  for (const auto& proc : dump->process_dumps) {
+    bool trigger_report = false;
+
+    if (proc->process_type ==
+            memory_instrumentation::mojom::ProcessType::BROWSER &&
+        (mode == profiling::ProfilingProcessHost::Mode::kBrowser ||
+         mode == profiling::ProfilingProcessHost::Mode::kAll)) {
+      trigger_report =
+          proc->os_dump->private_footprint_kb > kBrowserProcessMallocTriggerKb;
+    }
+
+    if (proc->process_type ==
+            memory_instrumentation::mojom::ProcessType::RENDERER &&
+        mode == profiling::ProfilingProcessHost::Mode::kAll) {
+      trigger_report =
+          proc->os_dump->private_footprint_kb > kRendererProcessMallocTriggerKb;
+    }
+
+    if (trigger_report)
+      TriggerMemoryReportForProcess(proc->pid);
+  }
+}
+
+void BackgroundProfilingTriggers::TriggerMemoryReportForProcess(
+    base::ProcessId pid) {
+  host_->RequestProcessReport(pid);
+
+  // Reset the timer to avoid uploading too many reports.
+  timer_.Start(
+      FROM_HERE,
+      base::TimeDelta::FromHours(kSecondReportRepeatingCheckMemoryDelayInHours),
+      base::Bind(&BackgroundProfilingTriggers::PerformMemoryUsageChecks,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+}  // namespace profiling
diff --git a/chrome/browser/profiling_host/background_profiling_triggers.h b/chrome/browser/profiling_host/background_profiling_triggers.h
new file mode 100644
index 0000000..ab6fef7f
--- /dev/null
+++ b/chrome/browser/profiling_host/background_profiling_triggers.h
@@ -0,0 +1,57 @@
+// 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_PROFILING_HOST_BACKGROUND_PROFILING_TRIGGERS_H_
+#define CHROME_BROWSER_PROFILING_HOST_BACKGROUND_PROFILING_TRIGGERS_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process_handle.h"
+#include "base/timer/timer.h"
+#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+
+namespace profiling {
+
+class ProfilingProcessHost;
+
+// BackgroundProfilingTriggers is used on the browser process to trigger the
+// collection of memory dumps and upload the results to the slow-reports
+// service. BackgroundProfilingTriggers class sets a periodic timer and
+// interacts with ProfilingProcessHost to trigger and upload memory dumps.
+class BackgroundProfilingTriggers {
+ public:
+  explicit BackgroundProfilingTriggers(ProfilingProcessHost* host);
+  virtual ~BackgroundProfilingTriggers();
+
+  // Register a periodic timer calling |PerformMemoryUsageChecks|.
+  void StartTimer();
+
+ protected:
+  // Virtual for testing. Called when the memory dump is received. Performs
+  // checks on memory usage and trigger a memory report with
+  // |TriggerMemoryReportForProcess| if needed.
+  virtual void OnReceivedMemoryDump(
+      bool success,
+      memory_instrumentation::mojom::GlobalMemoryDumpPtr ptr);
+
+  // Virtual for testing. Called when a memory report needs to be send.
+  virtual void TriggerMemoryReportForProcess(base::ProcessId pid);
+
+ private:
+  // Check the current memory usage and send a slow-report if needed.
+  void PerformMemoryUsageChecks();
+  void PerformMemoryUsageChecksOnIOThread();
+
+  // Timer to periodically check memory consumption and upload a slow-report.
+  base::RepeatingTimer timer_;
+  ProfilingProcessHost* host_;
+
+  base::WeakPtrFactory<BackgroundProfilingTriggers> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundProfilingTriggers);
+};
+
+}  // namespace profiling
+
+#endif  // CHROME_BROWSER_PROFILING_HOST_BACKGROUND_PROFILING_TRIGGERS_H_
diff --git a/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc b/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
new file mode 100644
index 0000000..e16d3d65
--- /dev/null
+++ b/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/profiling_host/background_profiling_triggers.h"
+
+#include "base/time/time.h"
+#include "chrome/browser/profiling_host/profiling_process_host.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h"
+#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace profiling {
+
+namespace {
+
+const uint32_t kProcessMallocTriggerKb = 2 * 1024 * 1024;  // 2 Gig
+
+using GlobalMemoryDumpPtr = memory_instrumentation::mojom::GlobalMemoryDumpPtr;
+using ProcessMemoryDumpPtr =
+    memory_instrumentation::mojom::ProcessMemoryDumpPtr;
+using OSMemDumpPtr = memory_instrumentation::mojom::OSMemDumpPtr;
+using ProcessType = memory_instrumentation::mojom::ProcessType;
+
+class MockProfilingProcessHost : public ProfilingProcessHost {
+ public:
+  MockProfilingProcessHost() {}
+  ~MockProfilingProcessHost() override {}
+
+  void SetMode(Mode mode) { ProfilingProcessHost::SetMode(mode); }
+};
+
+class TestBackgroundProfilingTriggers : public BackgroundProfilingTriggers {
+ public:
+  TestBackgroundProfilingTriggers() : BackgroundProfilingTriggers(&host_) {}
+  void OnReceivedMemoryDump(bool success, GlobalMemoryDumpPtr ptr) override {
+    BackgroundProfilingTriggers::OnReceivedMemoryDump(success, std::move(ptr));
+  }
+
+  void TriggerMemoryReportForProcess(base::ProcessId pid) override {
+    pids_.insert(pid);
+  }
+
+  void Reset() { pids_.clear(); }
+
+  std::set<base::ProcessId> pids_;
+  MockProfilingProcessHost host_;
+};
+
+OSMemDumpPtr GetFakeOSMemDump(uint32_t resident_set_kb,
+                              uint32_t private_footprint_kb) {
+  using memory_instrumentation::mojom::VmRegion;
+  std::vector<memory_instrumentation::mojom::VmRegionPtr> vm_regions;
+  return memory_instrumentation::mojom::OSMemDump::New(
+      resident_set_kb, private_footprint_kb, std::move(vm_regions));
+}
+
+void PopulateMetrics(GlobalMemoryDumpPtr& global_dump,
+                     base::ProcessId pid,
+                     ProcessType process_type,
+                     uint32_t resident_set_kb,
+                     uint32_t private_memory_kb) {
+  ProcessMemoryDumpPtr pmd(
+      memory_instrumentation::mojom::ProcessMemoryDump::New());
+  pmd->pid = pid;
+  pmd->process_type = process_type;
+  pmd->chrome_dump = memory_instrumentation::mojom::ChromeMemDump::New();
+  pmd->os_dump = GetFakeOSMemDump(resident_set_kb, private_memory_kb);
+  global_dump->process_dumps.push_back(std::move(pmd));
+}
+
+GlobalMemoryDumpPtr GetLargeMemoryDump() {
+  GlobalMemoryDumpPtr dump(
+      memory_instrumentation::mojom::GlobalMemoryDump::New());
+  PopulateMetrics(dump, 1, ProcessType::BROWSER, kProcessMallocTriggerKb,
+                  kProcessMallocTriggerKb);
+  PopulateMetrics(dump, 2, ProcessType::RENDERER, kProcessMallocTriggerKb,
+                  kProcessMallocTriggerKb);
+  PopulateMetrics(dump, 3, ProcessType::RENDERER, 1, 1);
+  return dump;
+}
+
+}  // namespace.
+
+TEST(BackgroungProfilingTriggersTest, OnReceivedMemoryDump) {
+  TestBackgroundProfilingTriggers triggers;
+
+  // Validate triggers for browser processes only.
+  triggers.host_.SetMode(ProfilingProcessHost::Mode::kBrowser);
+
+  GlobalMemoryDumpPtr dump_empty(
+      memory_instrumentation::mojom::GlobalMemoryDump::New());
+  triggers.OnReceivedMemoryDump(true, std::move(dump_empty));
+  EXPECT_TRUE(triggers.pids_.empty());
+
+  // A small browser process doesn't trigger a report.
+  GlobalMemoryDumpPtr dump_browser(
+      memory_instrumentation::mojom::GlobalMemoryDump::New());
+  PopulateMetrics(dump_browser, 1, ProcessType::BROWSER, 1, 1);
+  triggers.OnReceivedMemoryDump(true, std::move(dump_browser));
+  EXPECT_TRUE(triggers.pids_.empty());
+
+  // A larger browser process must trigger a report. Renderers are not reported.
+  triggers.OnReceivedMemoryDump(true, GetLargeMemoryDump());
+  EXPECT_THAT(triggers.pids_, testing::ElementsAre(1));
+  triggers.Reset();
+
+  // Validate triggers for all processes.
+  triggers.host_.SetMode(ProfilingProcessHost::Mode::kAll);
+
+  // Both browser and renderer must be reported.
+  triggers.OnReceivedMemoryDump(true, GetLargeMemoryDump());
+  EXPECT_THAT(triggers.pids_, testing::ElementsAre(1, 2));
+  triggers.Reset();
+
+  // Validate triggers when off.
+  triggers.host_.SetMode(ProfilingProcessHost::Mode::kNone);
+
+  triggers.OnReceivedMemoryDump(true, GetLargeMemoryDump());
+  EXPECT_TRUE(triggers.pids_.empty());
+  triggers.Reset();
+}
+
+}  // namespace profiling
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index 82aa9fe..d708bcd 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -7,6 +7,7 @@
 #include "base/allocator/features.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/process/process_iterator.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_info.h"
 #include "base/task_scheduler/post_task.h"
@@ -89,13 +90,24 @@
 
 }  // namespace
 
-ProfilingProcessHost::ProfilingProcessHost() {
+ProfilingProcessHost::ProfilingProcessHost()
+    : is_registered_(false), background_triggers_(this) {}
+
+ProfilingProcessHost::~ProfilingProcessHost() {
+  if (is_registered_)
+    Unregister();
+}
+
+void ProfilingProcessHost::Register() {
+  DCHECK(!is_registered_);
   Add(this);
   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
                  content::NotificationService::AllBrowserContextsAndSources());
+  is_registered_ = true;
 }
 
-ProfilingProcessHost::~ProfilingProcessHost() {
+void ProfilingProcessHost::Unregister() {
+  DCHECK(is_registered_);
   Remove(this);
 }
 
@@ -162,13 +174,27 @@
 bool ProfilingProcessHost::OnMemoryDump(
     const base::trace_event::MemoryDumpArgs& args,
     base::trace_event::ProcessMemoryDump* pmd) {
-  DCHECK_NE(GetCurrentMode(), Mode::kNone);
-  // TODO: Support dumping all processes for --memlog=all mode.
-  // https://crbug.com/758437.
-  memlog_->DumpProcessForTracing(
-      base::Process::Current().Pid(),
-      base::BindOnce(&ProfilingProcessHost::OnDumpProcessForTracingCallback,
-                     base::Unretained(this)));
+  // Dump the browser process, which happens to be this process.
+  if (GetCurrentMode() == Mode::kBrowser) {
+    memlog_->DumpProcessForTracing(
+        base::Process::Current().Pid(),
+        base::BindOnce(&ProfilingProcessHost::OnDumpProcessForTracingCallback,
+                       base::Unretained(this)));
+    return true;
+  }
+
+  // Attempt to dump all processes. Some of these processes will not be profiled
+  // [e.g. utility processes, including the profiling process]. The profiling
+  // process will gracefully handle these failures.
+  DCHECK_EQ(GetCurrentMode(), Mode::kAll);
+  base::ProcessIterator process_iter(NULL);
+  while (const base::ProcessEntry* process_entry =
+             process_iter.NextProcessEntry()) {
+    memlog_->DumpProcessForTracing(
+        process_entry->pid(),
+        base::BindOnce(&ProfilingProcessHost::OnDumpProcessForTracingCallback,
+                       base::Unretained(this)));
+  }
   return true;
 }
 
@@ -176,7 +202,8 @@
     mojo::ScopedSharedBufferHandle buffer,
     uint32_t size) {
   if (!buffer->is_valid()) {
-    DLOG(ERROR) << "Failed to dump process for tracing";
+    // The profiling process host will have logged error messages indicating the
+    // nature of the problem.
     return;
   }
 
@@ -209,7 +236,10 @@
     base::ProcessId pid) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
 
-  mojo::edk::PlatformChannelPair data_channel;
+  // Writes to the data_channel must be atomic to ensure that the profiling
+  // process can demux the messages. We accomplish this by making writes
+  // synchronous, and protecting the write() itself with a Lock.
+  mojo::edk::PlatformChannelPair data_channel(true /* client_is_blocking */);
 
   memlog_->AddSender(
       pid,
@@ -261,8 +291,10 @@
   has_started_ = true;
   ProfilingProcessHost* host = GetInstance();
   host->SetMode(mode);
+  host->Register();
   host->MakeConnector(connection);
   host->LaunchAsService();
+  host->ConfigureBackgroundProfilingTriggers();
   return host;
 }
 
@@ -273,6 +305,10 @@
       base::LeakySingletonTraits<ProfilingProcessHost>>::get();
 }
 
+void ProfilingProcessHost::ConfigureBackgroundProfilingTriggers() {
+  background_triggers_.StartTimer();
+}
+
 void ProfilingProcessHost::RequestProcessDump(base::ProcessId pid,
                                               const base::FilePath& dest) {
   if (!connector_) {
@@ -374,7 +410,10 @@
   if (!success) {
     DLOG(ERROR) << "Cannot dump process.";
     // On any errors, the requested trace output file is deleted.
-    base::DeleteFile(file_path, false);
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+        base::BindOnce(base::IgnoreResult(&base::DeleteFile), file_path,
+                       false));
     return;
   }
 
@@ -382,7 +421,10 @@
     UploadTraceToCrashServer(file_path);
 
     // Uploaded file is a temporary file and must be deleted.
-    base::DeleteFile(file_path, false);
+    base::PostTaskWithTraits(
+        FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+        base::BindOnce(base::IgnoreResult(&base::DeleteFile), file_path,
+                       false));
   }
 }
 
diff --git a/chrome/browser/profiling_host/profiling_process_host.h b/chrome/browser/profiling_host/profiling_process_host.h
index c79535736..2a1a74c 100644
--- a/chrome/browser/profiling_host/profiling_process_host.h
+++ b/chrome/browser/profiling_host/profiling_process_host.h
@@ -10,6 +10,7 @@
 #include "base/process/process.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "build/build_config.h"
+#include "chrome/browser/profiling_host/background_profiling_triggers.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/profiling/memlog.mojom.h"
 #include "chrome/common/profiling/memlog_client.h"
@@ -58,6 +59,9 @@
     kAll,
   };
 
+  // Returns the mode.
+  Mode mode() const { return mode_; }
+
   // Returns the mode set on the current process' command line.
   static Mode GetCurrentMode();
 
@@ -72,6 +76,8 @@
   // Returns a pointer to the current global profiling process host.
   static ProfilingProcessHost* GetInstance();
 
+  void ConfigureBackgroundProfilingTriggers();
+
   // Sends a message to the profiling process that it dump the given process'
   // memory data to the given file.
   void RequestProcessDump(base::ProcessId pid, const base::FilePath& dest);
@@ -80,11 +86,19 @@
   // memory data to the crash server (slow-report).
   void RequestProcessReport(base::ProcessId pid);
 
- private:
+ protected:
   friend struct base::DefaultSingletonTraits<ProfilingProcessHost>;
+  // Exposed for unittests.
   ProfilingProcessHost();
   ~ProfilingProcessHost() override;
 
+  void Register();
+  void Unregister();
+
+  // Set the profiling mode. Exposed for unittests.
+  void SetMode(Mode mode);
+
+ private:
   // Make and store a connector from |connection|.
   void MakeConnector(content::ServiceManagerConnection* connection);
 
@@ -128,8 +142,6 @@
                              bool upload,
                              bool success);
 
-  void SetMode(Mode mode);
-
   // Returns the metadata for the trace. This is the minimum amount of metadata
   // needed to symbolize the trace.
   std::unique_ptr<base::DictionaryValue> GetMetadataJSONForTrace();
@@ -138,9 +150,17 @@
   std::unique_ptr<service_manager::Connector> connector_;
   mojom::MemlogPtr memlog_;
 
+  // Whether or not the host is registered to the |registrar_|.
+  bool is_registered_;
+
+  // Handle background triggers on high memory pressure. A trigger will call
+  // |RequestProcessReport| on this instance.
+  BackgroundProfilingTriggers background_triggers_;
+
   // The mode determines which processes should be profiled.
   Mode mode_;
 
+  // Whether or not the profiling host is started.
   static bool has_started_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfilingProcessHost);
diff --git a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc
index 95a482c..a21917c 100644
--- a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc
@@ -5,9 +5,13 @@
 #include "chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h"
 
 #include "base/bind_helpers.h"
+#include "chrome/browser/media/cdm_storage_id.h"
+#include "chrome/browser/media/media_storage_id_salt.h"
+#include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_ppapi_host.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/host/dispatch_host_message.h"
@@ -17,6 +21,17 @@
 
 namespace chrome {
 
+namespace {
+
+std::vector<uint8_t> GetSalt(content::RenderFrameHost* rfh) {
+  DCHECK(rfh);
+  Profile* profile =
+      Profile::FromBrowserContext(rfh->GetProcess()->GetBrowserContext());
+  return MediaStorageIdSalt::GetSalt(profile->GetPrefs());
+}
+
+}  // namespace
+
 PepperPlatformVerificationMessageFilter::
     PepperPlatformVerificationMessageFilter(content::BrowserPpapiHost* host,
                                             PP_Instance instance)
@@ -115,14 +130,31 @@
 
 int32_t PepperPlatformVerificationMessageFilter::OnGetStorageId(
     ppapi::host::HostMessageContext* context) {
-  // TODO(jrummell): Implement Storage ID. For now simply returns empty string.
-  // http://crbug.com/478960.
-  ppapi::host::ReplyMessageContext reply_context =
-      context->MakeReplyMessageContext();
+  content::RenderFrameHost* rfh =
+      content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
+  if (!rfh) {
+    // Won't be able to get the salt, so return empty buffer.
+    GetStorageIdCallback(context->MakeReplyMessageContext(),
+                         std::vector<uint8_t>());
+    return PP_OK_COMPLETIONPENDING;
+  }
+
+  std::vector<uint8_t> salt = GetSalt(rfh);
+  DCHECK(salt.size());
+  cdm_storage_id::ComputeStorageId(
+      salt, rfh->GetLastCommittedOrigin(),
+      base::BindOnce(
+          &PepperPlatformVerificationMessageFilter::GetStorageIdCallback, this,
+          context->MakeReplyMessageContext()));
+  return PP_OK_COMPLETIONPENDING;
+}
+
+void PepperPlatformVerificationMessageFilter::GetStorageIdCallback(
+    ppapi::host::ReplyMessageContext reply_context,
+    const std::vector<uint8_t>& storage_id) {
   reply_context.params.set_result(PP_OK);
   SendReply(reply_context,
-            PpapiHostMsg_PlatformVerification_GetStorageIdReply(std::string()));
-  return PP_OK_COMPLETIONPENDING;
+            PpapiHostMsg_PlatformVerification_GetStorageIdReply(storage_id));
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h
index 0b54a380..23961a9 100644
--- a/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h
+++ b/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h
@@ -7,6 +7,9 @@
 
 #include <stdint.h>
 
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/host/resource_message_filter.h"
@@ -58,6 +61,8 @@
 #endif
 
   int32_t OnGetStorageId(ppapi::host::HostMessageContext* context);
+  void GetStorageIdCallback(ppapi::host::ReplyMessageContext reply_context,
+                            const std::vector<uint8_t>& storage_id);
 
   // Used to lookup the WebContents associated with this PP_Instance.
   int render_process_id_;
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
index ecad2336..46fedde 100644
--- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -409,10 +409,10 @@
   auto* tab = browser()->tab_strip_model()->GetWebContentsAt(1);
 
   // Simulate that a video stream is now being captured.
-  content::MediaStreamDevice fake_media_device(
-      content::MEDIA_DEVICE_VIDEO_CAPTURE, "fake_media_device",
-      "fake_media_device");
-  content::MediaStreamDevices video_devices(1, fake_media_device);
+  content::MediaStreamDevices video_devices(1);
+  video_devices[0] =
+      content::MediaStreamDevice(content::MEDIA_DEVICE_VIDEO_CAPTURE,
+                                 "fake_media_device", "fake_media_device");
   MediaCaptureDevicesDispatcher* dispatcher =
       MediaCaptureDevicesDispatcher::GetInstance();
   dispatcher->SetTestVideoCaptureDevices(video_devices);
@@ -443,10 +443,10 @@
 
   auto* tab = browser()->tab_strip_model()->GetWebContentsAt(1);
   // Simulate that a video stream is now being captured.
-  content::MediaStreamDevice fake_media_device(
-      content::MEDIA_DEVICE_VIDEO_CAPTURE, "fake_media_device",
-      "fake_media_device");
-  content::MediaStreamDevices video_devices(1, fake_media_device);
+  content::MediaStreamDevices video_devices(1);
+  video_devices[0] =
+      content::MediaStreamDevice(content::MEDIA_DEVICE_VIDEO_CAPTURE,
+                                 "fake_media_device", "fake_media_device");
   MediaCaptureDevicesDispatcher* dispatcher =
       MediaCaptureDevicesDispatcher::GetInstance();
   dispatcher->SetTestVideoCaptureDevices(video_devices);
diff --git a/chrome/browser/resources/chromeos/arc_support/background.js b/chrome/browser/resources/chromeos/arc_support/background.js
index 7fea6b5f..c5c02c6 100644
--- a/chrome/browser/resources/chromeos/arc_support/background.js
+++ b/chrome/browser/resources/chromeos/arc_support/background.js
@@ -425,6 +425,12 @@
 
     this.deviceManagementUrlPrefix_ = null;
 
+    // https://crbug.com/756144: Disable event processing while the page is not
+    // shown. The bug seems to be caused by erroneous onErrorOccurred events
+    // that are fired even though authView_.src is never set. This might be
+    // related to a bug in webview, see also CL:638413.
+    this.process_events_ = false;
+
     container.querySelector('#button-active-directory-auth-cancel')
         .addEventListener('click', () => this.onCancel_());
   }
@@ -442,16 +448,31 @@
   }
 
   /**
+   * Toggles onCompleted and onErrorOccurred event processing.
+   * @param {boolean} enabled Process (true) or ignore (false) events.
+   */
+  enableEventProcessing(enabled) {
+    this.process_events_ = enabled;
+  }
+
+  /**
    * Auth view onCompleted event handler. Checks whether the SAML flow
    * reached its endpoint, the device management server.
    * @param {!Object} details Event parameters.
    */
   onAuthViewCompleted_(details) {
+    if (!this.process_events_) {
+      console.error(
+          'Unexpected onAuthViewCompleted_ event from URL ' + details.url);
+      return;
+    }
     // See if we hit the device management server. This should happen at the
     // end of the SAML flow. Before that, we're on the Active Directory
     // Federation Services server.
     if (this.deviceManagementUrlPrefix_ &&
         details.url.startsWith(this.deviceManagementUrlPrefix_)) {
+      // Once we hit the final URL, stop processing further events.
+      this.process_events_ = false;
       // Did it actually work?
       if (details.statusCode == 200) {
         // 'code' is unused, but it needs to be there.
@@ -470,13 +491,21 @@
    * @param {!Object} details Event parameters.
    */
   onAuthViewErrorOccurred_(details) {
+    if (!this.process_events_) {
+      console.error(
+          'Unexpected onAuthViewErrorOccurred_ event: ' + details.error);
+      return;
+    }
     // Retry triggers net::ERR_ABORTED, so ignore it.
     if (details.error == 'net::ERR_ABORTED')
       return;
+    // Stop processing further events on first error.
+    this.process_events_ = false;
     sendNativeMessage(
         'onAuthFailed', {errorMessage: 'Error occurred: ' + details.error});
   }
 
+  /** Called when the "CANCEL" button is clicked. */
   onCancel_() {
     closeWindow();
   }
@@ -564,16 +593,13 @@
     termsPage.onLocationServicePreferenceChanged(
         message.enabled, message.managed);
   } else if (message.action == 'showPage') {
-    showPage(message.page);
+    showPage(message.page, message.options);
   } else if (message.action == 'showErrorPage') {
     showErrorPage(message.errorMessage, message.shouldShowSendFeedback);
   } else if (message.action == 'closeWindow') {
     closeWindow();
   } else if (message.action == 'setWindowBounds') {
     setWindowBounds();
-  } else if (message.action == 'setActiveDirectoryAuthUrls') {
-    activeDirectoryAuthPage.setUrls(
-        message.federationUrl, message.deviceManagementUrlPrefix);
   }
 }
 
@@ -590,8 +616,12 @@
  * Shows requested page and hide others. Show appWindow if it was hidden before.
  * 'none' hides all views.
  * @param {string} pageDivId id of divider of the page to show.
+ * @param {dictionary=} options Addional options depending on pageDivId. For
+ *     'active-directory-auth', this has to contain keys 'federationUrl' and
+ *     'deviceManagementUrlPrefix' with corresponding values. See
+ *     ActiveDirectoryAuthPage::setUrls for a description of those parameters.
  */
-function showPage(pageDivId) {
+function showPage(pageDivId, options) {
   if (!appWindow) {
     return;
   }
@@ -618,6 +648,14 @@
         'device_type=arc_plus_plus&device_id=' + currentDeviceId +
         '&hl=' + navigator.language;
   }
+  if (pageDivId == 'active-directory-auth') {
+    activeDirectoryAuthPage.enableEventProcessing(true);
+    activeDirectoryAuthPage.setUrls(
+        options.federationUrl, options.deviceManagementUrlPrefix);
+  } else {
+    activeDirectoryAuthPage.enableEventProcessing(false);
+  }
+
   appWindow.show();
   if (pageDivId == 'terms') {
     termsPage.onShow();
@@ -854,6 +892,9 @@
   var onWindowClosed = function() {
     appWindow = null;
 
+    // Turn off event processing.
+    activeDirectoryAuthPage.enableEventProcessing(false);
+
     // Notify to Chrome.
     sendNativeMessage('onWindowClosed');
 
diff --git a/chrome/browser/resources/chromeos/login/md_top_header_bar.css b/chrome/browser/resources/chromeos/login/md_top_header_bar.css
index 1914131..fb88a5b 100644
--- a/chrome/browser/resources/chromeos/login/md_top_header_bar.css
+++ b/chrome/browser/resources/chromeos/login/md_top_header_bar.css
@@ -57,14 +57,10 @@
   pointer-events: none;
 }
 
-.new-note-action:not(.new-note-action-short-transition) {
+.new-note-action {
   transition: all 300ms;
 }
 
-.new-note-action-short-transition {
-  transition: all 5ms;
-}
-
 html[dir=rtl] .new-note-action {
   border-radius: 0 0 44px 0;
 }
@@ -83,7 +79,6 @@
 }
 
 .new-note-action-container-activated > .new-note-action {
-  background-color: #000;
   bottom: auto;
   left: auto;
   position: absolute;
diff --git a/chrome/browser/resources/chromeos/login/md_top_header_bar.js b/chrome/browser/resources/chromeos/login/md_top_header_bar.js
index 3a11efa1..f969021 100644
--- a/chrome/browser/resources/chromeos/login/md_top_header_bar.js
+++ b/chrome/browser/resources/chromeos/login/md_top_header_bar.js
@@ -351,8 +351,9 @@
       if (this.lockScreenAppsState_ == state)
         return;
 
+      var previousState = this.lockScreenAppsState_;
       this.lockScreenAppsState_ = state;
-      this.updateUi_();
+      this.updateUi_(previousState);
     },
 
     /** override */
@@ -367,25 +368,10 @@
     },
 
     /**
+     * @param {!LockScreenAppsState} previousState
      * @private
      */
-    updateUi_: function() {
-      // Shorten transition duration when moving to available state, in
-      // particular when moving from foreground state - when moving from
-      // foreground state container gets cropped to top right corner
-      // immediately, while action element is updated from full screen with
-      // a transition. If the transition is too long, the action would be
-      // displayed as full square for a fraction of a second, which can look
-      // janky.
-      if (this.lockScreenAppsState_ == LOCK_SCREEN_APPS_STATE.AVAILABLE) {
-        $('new-note-action')
-            .classList.toggle('new-note-action-short-transition', true);
-        this.runOnNoteActionTransitionEnd_(function() {
-          $('new-note-action')
-              .classList.toggle('new-note-action-short-transition', false);
-        });
-      }
-
+    updateUi_: function(previousState) {
       this.swipeDetector_.setEnabled(
           this.lockScreenAppsState_ == LOCK_SCREEN_APPS_STATE.AVAILABLE);
 
@@ -413,14 +399,24 @@
           .classList.toggle('new-note-action-above-login-header', false);
 
       if (this.lockScreenAppsState_ != LOCK_SCREEN_APPS_STATE.FOREGROUND) {
-        // Reset properties that might have been set as a result of activating
-        // new note action.
+        var transitionOut =
+            previousState == LOCK_SCREEN_APPS_STATE.FOREGROUND &&
+            this.lockScreenAppsState_ == LOCK_SCREEN_APPS_STATE.AVAILABLE;
         $('new-note-action-container')
-            .classList.toggle('new-note-action-container-activated', false);
+            .classList.toggle(
+                'new-note-action-container-activated', transitionOut);
+        if (transitionOut) {
+          this.runOnNoteActionTransitionEnd_(function() {
+            $('new-note-action-container')
+                .classList.toggle('new-note-action-container-activated', false);
+          });
+        }
+
         $('new-note-action').style.removeProperty('border-bottom-left-radius');
         $('new-note-action').style.removeProperty('border-bottom-right-radius');
         $('new-note-action').style.removeProperty('height');
         $('new-note-action').style.removeProperty('width');
+        $('new-note-action').style.removeProperty('background-color');
       }
     },
 
@@ -498,6 +494,7 @@
       newNoteAction.style.setProperty(
           isRTL() ? 'border-bottom-right-radius' : 'border-bottom-left-radius',
           targetSize);
+      newNoteAction.style.setProperty('background-color', '#000');
     },
 
     /**
diff --git a/chrome/browser/resources/chromeos/login/oobe_change_picture.html b/chrome/browser/resources/chromeos/login/oobe_change_picture.html
index 5c38c3d..96fe322c 100644
--- a/chrome/browser/resources/chromeos/login/oobe_change_picture.html
+++ b/chrome/browser/resources/chromeos/login/oobe_change_picture.html
@@ -53,7 +53,8 @@
       </cr-picture-pane>
       <cr-picture-list id="pictureList"
           camera-present="[[cameraPresent]]"
-          default-images="[[defaultImages]]"
+          default-images="[[getDefaultImages_(defaultImages,
+              firstDefaultImageIndex)]]"
           selected-item="{{selectedItem_}}"
           old-image-label="[[i18nDynamic(locale, 'photoFromCamera')]]"
           profile-image-label="[[i18nDynamic(locale, 'profilePhoto')]]"
diff --git a/chrome/browser/resources/chromeos/login/oobe_change_picture.js b/chrome/browser/resources/chromeos/login/oobe_change_picture.js
index 16b5166..adf3d1e2 100644
--- a/chrome/browser/resources/chromeos/login/oobe_change_picture.js
+++ b/chrome/browser/resources/chromeos/login/oobe_change_picture.js
@@ -36,6 +36,9 @@
       value: false,
     },
 
+    /** Specifies the selected image index. */
+    selectedImageIndex: Number,
+
     /** Specifies the selected image URL, used to specify the initial image. */
     selectedImageUrl: {
       type: String,
@@ -54,6 +57,12 @@
     },
 
     /**
+     * The index of the first default image to use in the selection list.
+     * @private
+     */
+    firstDefaultImageIndex: Number,
+
+    /**
      * The currently selected item. This property is bound to the iron-selector
      * and never directly assigned. This may be undefined momentarily as
      * the selection changes due to iron-selector implementation details.
@@ -87,6 +96,15 @@
   },
 
   /**
+   * setProfileImageUrl is called possibly after sync.
+   * @param {string} imageUrl
+   * @param {boolean} selected
+   */
+  setProfileImageUrl: function(imageUrl, selected) {
+    this.pictureList_.setProfileImageUrl(imageUrl, selected);
+  },
+
+  /**
    * @return {string}
    * @private
    */
@@ -101,9 +119,13 @@
    * @private
    */
   selectedImageUrlChanged_: function(selectedImageUrl) {
-    var pictureList = /** @type {CrPictureListElement} */ (this.$.pictureList);
-    pictureList.setSelectedImageUrl(selectedImageUrl);
-    pictureList.setFocus();
+    if (this.selectedImageIndex >= this.firstDefaultImageIndex) {
+      this.pictureList_.setSelectedImageUrl(selectedImageUrl);
+    } else {
+      this.pictureList_.setOldImageUrl(
+          selectedImageUrl, this.selectedImageIndex);
+    }
+    this.pictureList_.setFocus();
   },
 
   /**
@@ -124,7 +146,13 @@
         this.sendSelectImage_(image.dataset.type, '');
         break;
       case CrPicture.SelectionTypes.OLD:
-        this.sendSelectImage_(image.dataset.type, '');
+        var imageIndex = image.dataset.imageIndex;
+        if (imageIndex !== undefined && imageIndex >= 0 && image.src) {
+          this.sendSelectImage_(
+              CrPicture.SelectionTypes.DEFAULT, image.dataset.url);
+        } else {
+          this.sendSelectImage_(image.dataset.type, '');
+        }
         break;
       case CrPicture.SelectionTypes.DEFAULT:
         this.sendSelectImage_(image.dataset.type, image.dataset.url);
@@ -203,4 +231,14 @@
     return (selectedItem && selectedItem.dataset.type) ||
         CrPicture.SelectionTypes.NONE;
   },
+
+  /**
+   * @param {!Array<!OobeDefaultImage>} defaultImages
+   * @param {number} firstDefaultImageIndex
+   * @return {!Array<!OobeDefaultImage>}
+   * @private
+   */
+  getDefaultImages_: function(defaultImages, firstDefaultImageIndex) {
+    return defaultImages.slice(firstDefaultImageIndex);
+  },
 });
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js
index 2067430..7ade283 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js
@@ -8,6 +8,7 @@
 
 login.createScreen('UserImageScreen', 'user-image', function() {
   var CONTEXT_KEY_IS_CAMERA_PRESENT = 'isCameraPresent';
+  var CONTEXT_KEY_SELECTED_IMAGE_INDEX = 'selectedImageIndex';
   var CONTEXT_KEY_SELECTED_IMAGE_URL = 'selectedImageURL';
   var CONTEXT_KEY_PROFILE_PICTURE_DATA_URL = 'profilePictureDataURL';
 
@@ -22,7 +23,9 @@
             $('changePicture').cameraPresent = present;
           });
       this.context.addObserver(
-          CONTEXT_KEY_SELECTED_IMAGE_URL, this.setSelectedImage_);
+          CONTEXT_KEY_SELECTED_IMAGE_INDEX, this.setSelectedImageIndex_);
+      this.context.addObserver(
+          CONTEXT_KEY_SELECTED_IMAGE_URL, this.setSelectedImageUrl_);
       this.context.addObserver(
           CONTEXT_KEY_PROFILE_PICTURE_DATA_URL, function(url) {
             self.profileImageLoading = false;
@@ -100,17 +103,27 @@
      * @param {Array<{url: string, author: string, website: string}>} images
      *   An array of default images data, including URL, author and website.
      */
-    setDefaultImages: function(imagesData) {
-      $('changePicture').defaultImages = imagesData;
+    setDefaultImages: function(info) {
+      $('changePicture').defaultImages = info.images;
+      $('changePicture').firstDefaultImageIndex = info.first;
       chrome.send('screenReady');
     },
 
     /**
+     * Selects user image with the given index.
+     * @param {number} index Index of the image to select.
+     * @private
+     */
+    setSelectedImageIndex_: function(index) {
+      $('changePicture').selectedImageIndex = index;
+    },
+
+    /**
      * Selects user image with the given URL.
      * @param {string} url URL of the image to select.
      * @private
      */
-    setSelectedImage_: function(url) {
+    setSelectedImageUrl_: function(url) {
       if (!url)
         return;
       $('changePicture').selectedImageUrl = url;
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js
index 3088529..87422a2 100644
--- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js
+++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.js
@@ -1426,10 +1426,10 @@
         selectedUserImage_: -1,
         imagesData: [],
 
-        setDefaultImages: function(imagesData) {
+        setDefaultImages: function(info) {
           var imageGrid = this.getScreenElement('image-grid');
-          imageGrid.setDefaultImages(imagesData);
-          this.imagesData_ = imagesData;
+          imageGrid.setDefaultImages(info.images);
+          this.imagesData_ = info.images;
         },
 
 
diff --git a/chrome/browser/resources/chromeos/sounds/touch_type.wav b/chrome/browser/resources/chromeos/sounds/touch_type.wav
new file mode 100644
index 0000000..4ab54435
--- /dev/null
+++ b/chrome/browser/resources/chromeos/sounds/touch_type.wav
Binary files differ
diff --git a/chrome/browser/resources/local_ntp/voice.css b/chrome/browser/resources/local_ntp/voice.css
index caf5f0d..bcd24e9 100644
--- a/chrome/browser/resources/local_ntp/voice.css
+++ b/chrome/browser/resources/local_ntp/voice.css
@@ -78,6 +78,11 @@
   width: 15px;
 }
 
+html[dir=rtl] .close-button {
+  left: 0;
+  right: auto;
+}
+
 .close-button:hover {
   opacity: .8;
 }
@@ -189,6 +194,10 @@
   transition: transform 218ms, opacity 218ms ease-in;
 }
 
+html[dir=rtl] .button-container {
+  float: left;
+}
+
 /* Common styles applied to the button-container. */
 .overlay .button-container,
 .overlay-hidden .button-container {
@@ -198,6 +207,12 @@
   width: 165px;
 }
 
+html[dir=rtl] .overlay .button-container,
+html[dir=rtl] .overlay-hidden .button-container {
+  left: -70px;
+  right: auto;
+}
+
 /* Container style when speech recognition is inactive. */
 .overlay-hidden .button-container {
   transform: scale(.1);
@@ -244,11 +259,20 @@
               top 0s linear 218ms;
 }
 
+html[dir=rtl] .voice-text {
+  text-align: right;
+}
+
 /* Recognition results text hidden in the Full Page UI. */
 .overlay-hidden .voice-text {
   margin-left: 44px;
 }
 
+html[dir=rtl] .overlay-hidden .voice-text {
+  margin-left: 0;
+  margin-right: 44px;
+}
+
 /* Styles applied to the text output elements. Common style for the text area
  * class for the full Page UI. To vertically center the text as longer queries
  * are wrapped, the 'top' position is specified in em here and below. */
@@ -260,6 +284,12 @@
   width: 460px;
 }
 
+html[dir=rtl] .overlay .voice-text,
+html[dir=rtl] .overlay-hidden .voice-text {
+  left: auto;
+  right: -44px;
+}
+
 /* Common style for when the text areas are made visible. */
 .overlay .voice-text {
   margin-left: 0;
@@ -267,6 +297,11 @@
   transition: opacity 500ms ease-out, margin-left 500ms ease-out;
 }
 
+html[dir=rtl] .overlay .voice-text {
+  margin-left: auto;
+  margin-right: 0;
+}
+
 /* Interim (low confidence) text. */
 #voice-text-i {
   color: var(--grey);
@@ -349,6 +384,7 @@
 
 /* Container element for microphone icon. */
 .microphone {
+  direction: ltr;
   height: 87px;
   left: 43px;
   pointer-events: none;
diff --git a/chrome/browser/resources/md_history/history.js b/chrome/browser/resources/md_history/history.js
index 5f8e6d4..e6c5ff0 100644
--- a/chrome/browser/resources/md_history/history.js
+++ b/chrome/browser/resources/md_history/history.js
@@ -4,7 +4,7 @@
 
 // Send the history query immediately. This allows the query to process during
 // the initial page startup.
-chrome.send('queryHistory', ['', 0, RESULTS_PER_PAGE]);
+chrome.send('queryHistory', ['', RESULTS_PER_PAGE]);
 chrome.send('getForeignSessions');
 
 /** @type {Promise} */
diff --git a/chrome/browser/resources/md_history/query_manager.js b/chrome/browser/resources/md_history/query_manager.js
index aadbf5a..de55e2b3 100644
--- a/chrome/browser/resources/md_history/query_manager.js
+++ b/chrome/browser/resources/md_history/query_manager.js
@@ -64,17 +64,14 @@
     this.set('queryState.querying', true);
     this.set('queryState.incremental', incremental);
 
-    var lastVisitTime = 0;
     if (incremental) {
-      var lastVisit = this.queryResult.results.slice(-1)[0];
-      lastVisitTime = lastVisit ? Math.floor(lastVisit.time) : 0;
+      chrome.send('queryHistoryContinuation');
+    } else {
+      chrome.send('queryHistory', [
+        queryState.searchTerm,
+        RESULTS_PER_PAGE,
+      ]);
     }
-
-    chrome.send('queryHistory', [
-      queryState.searchTerm,
-      lastVisitTime,
-      RESULTS_PER_PAGE,
-    ]);
   },
 
   /**
diff --git a/chrome/browser/resources/policy.html b/chrome/browser/resources/policy.html
index 480bdc9d..6a3ef70 100644
--- a/chrome/browser/resources/policy.html
+++ b/chrome/browser/resources/policy.html
@@ -113,7 +113,9 @@
             <div class="source elide"></div>
           </td>
           <td class="name-column">
-            <div class="name elide"></div>
+            <div class="name elide">
+              <a class="name-link" target="_blank"></a>
+            </div>
           </td>
           <td class="value-column">
             <div class="value-container">
diff --git a/chrome/browser/resources/policy_android.css b/chrome/browser/resources/policy_android.css
index 7bb0e2a..999e023 100644
--- a/chrome/browser/resources/policy_android.css
+++ b/chrome/browser/resources/policy_android.css
@@ -167,6 +167,12 @@
   width: 15%;
 }
 
+.no-help-link .name-link {
+  color: inherit;
+  pointer-events: none;
+  text-decoration: none;
+}
+
 div.elide,
 span.value {
   overflow: hidden;
diff --git a/chrome/browser/resources/policy_base.js b/chrome/browser/resources/policy_base.js
index 8994b97..5692a94 100644
--- a/chrome/browser/resources/policy_base.js
+++ b/chrome/browser/resources/policy_base.js
@@ -128,7 +128,15 @@
       this.unset = !value;
 
       // Populate the name column.
-      this.querySelector('.name').textContent = name;
+      this.querySelector('.name-link').textContent = name;
+      this.querySelector('.name-link').href =
+          'https://chromium.org/administrators/policy-list-3#' + name;
+      this.querySelector('.name-link').title =
+          loadTimeData.getStringF('policyLearnMore', name);
+
+      if (unknown) {
+        this.classList.add('no-help-link');
+      }
 
       // Populate the remaining columns with policy scope, level and value if a
       // value has been set. Otherwise, leave them blank.
@@ -479,6 +487,9 @@
     appendNewTable: function(id, label_title, label_content) {
       var newSection =
           this.createPolicyTableSection(id, label_title, label_content);
+      if (id != 'chrome') {
+        newSection.classList.add('no-help-link');
+      }
       this.mainSection.appendChild(newSection);
       return this.policyTables[id];
     },
diff --git a/chrome/browser/resources/policy_common.css b/chrome/browser/resources/policy_common.css
index b455641..937c38e 100644
--- a/chrome/browser/resources/policy_common.css
+++ b/chrome/browser/resources/policy_common.css
@@ -105,6 +105,12 @@
   font-weight: normal;
 }
 
+.no-help-link .name-link {
+  color: inherit;
+  pointer-events: none;
+  text-decoration: none;
+}
+
 div.elide,
 span.value {
   overflow: hidden;
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index 3a8bee6..bcb20f60 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -7,6 +7,7 @@
 <link rel="import" href="../i18n_setup.html">
 <link rel="import" href="../icons.html">
 <link rel="import" href="../prefs/prefs.html">
+<link rel="import" href="../prefs/prefs_behavior.html">
 <link rel="import" href="../settings_page/settings_animated_pages.html">
 <link rel="import" href="../settings_page/settings_subpage.html">
 <link rel="import" href="../settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
index 35b5c439..a626139 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -25,6 +25,8 @@
 Polymer({
   is: 'settings-bluetooth-page',
 
+  behaviors: [PrefsBehavior],
+
   properties: {
     /** Preferences state. */
     prefs: {
@@ -166,6 +168,7 @@
     this.adapterState_ = state;
     this.bluetoothToggleState_ = state.powered;
     this.bluetoothToggleDisabled_ = !state.available;
+    this.setPrefValue('ash.user.bluetooth.adapter_enabled', state.powered);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp b/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp
index 3d4051ba..975856e1 100644
--- a/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp
@@ -7,6 +7,7 @@
       'target_name': 'bluetooth_page',
       'dependencies': [
         '../compiled_resources2.gyp:route',
+        '../prefs/compiled_resources2.gyp:prefs_behavior',
         '../settings_page/compiled_resources2.gyp:settings_animated_pages',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html
index c49d8fa..61224dc 100644
--- a/chrome/browser/resources/settings/icons.html
+++ b/chrome/browser/resources/settings/icons.html
@@ -59,6 +59,8 @@
       <g id="content-copy"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"></path></g>
 <if expr="chromeos">
       <g id="computer"><path d="M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6z"></path></g>
+      <g id="devices-other"><path d="M3 6h18V4H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4v-2H3V6zm10 6H9v1.78c-.61.55-1 1.33-1 2.22s.39 1.67 1 2.22V20h4v-1.78c.61-.55 1-1.34 1-2.22s-.39-1.67-1-2.22V12zm-2 5.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM22 8h-6c-.5 0-1 .5-1 1v10c0 .5.5 1 1 1h6c.5 0 1-.5 1-1V9c0-.5-.5-1-1-1zm-1 10h-4v-8h4v8z"></path></g>
+
 </if>
       <g id="done"><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"></path></g>
       <g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g>
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_page.html b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
index fc03d5e..8ea02e6 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
@@ -8,7 +8,10 @@
   <template>
     <style include="settings-shared"></style>
     <div class="settings-box two-line">
-      <div id="smsConnectToggleLabel" class="start">
+      <div class="icon-container">
+        <iron-icon icon="cr:sms-connect"></iron-icon>
+      </div>
+      <div id="smsConnectToggleLabel" class="middle">
         $i18n{smsConnect}
         <div class="secondary">$i18n{smsConnectSummary}</div>
       </div>
diff --git a/chrome/browser/resources/settings/people_page/change_picture.html b/chrome/browser/resources/settings/people_page/change_picture.html
index 8f56248..2b642c9 100644
--- a/chrome/browser/resources/settings/people_page/change_picture.html
+++ b/chrome/browser/resources/settings/people_page/change_picture.html
@@ -15,9 +15,10 @@
   <template>
     <style>
       :host {
-        /* 56px cr_toolbar + 72px #headerLine */
-        --cr-settings-change-picture-top: 128px;
-        --title-height: 30px;
+        --cr-toolbar-height: 56px;
+        /* #headerLine height + padding */
+        --cr-settings-header-height: calc(62px + 1.34em);
+        --title-height: 2em;
         --title-padding: 16px;
         display: block;
         min-height: 328px;
@@ -34,6 +35,9 @@
         align-items: flex-start;
         display: flex;
         position: absolute;
+        top: calc(var(--cr-settings-header-height) +
+                  var(--title-padding) +
+                  var(--title-height));
       }
 
       #picturePane {
@@ -58,7 +62,8 @@
         /* TODO(reveman): Find a way to have height align to viewport
            without using fixed position. */
         height: calc(100vh -
-            var(--cr-settings-change-picture-top) -
+            var(--cr-toolbar-height) -
+            var(--cr-settings-header-height) -
             var(--title-padding) -
             var(--title-height));
         margin-top: 0;
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index 1b1dec61..6c70ddec 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -156,6 +156,9 @@
         settings.getCurrentRoute() == settings.routes.IMPORT_DATA;
 
     if (settings.getCurrentRoute() == settings.routes.SIGN_OUT) {
+      // <if expr="not chromeos">
+      settings.ProfileInfoBrowserProxyImpl.getInstance().getProfileStatsCount();
+      // </if>
       // If the sync status has not been fetched yet, optimistically display
       // the disconnect dialog. There is another check when the sync status is
       // fetched. The dialog will be closed then the user is not signed in.
@@ -229,11 +232,6 @@
     if (!this.syncStatus && syncStatus && !syncStatus.signedIn)
       chrome.metricsPrivate.recordUserAction('Signin_Impression_FromSettings');
 
-    // <if expr="not chromeos">
-    if (syncStatus.signedIn)
-      settings.ProfileInfoBrowserProxyImpl.getInstance().getProfileStatsCount();
-    // </if>
-
     if (!syncStatus.signedIn && this.showDisconnectDialog_)
       this.$$('#disconnectDialog').close();
 
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index ca970189..fcebde9 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -164,7 +164,7 @@
           </a>
 <if expr="chromeos">
           <a href="/multidevice" hidden="[[!showMultidevice]]">
-            <iron-icon icon="settings:sync"></iron-icon>
+            <iron-icon icon="settings:devices-other"></iron-icon>
             $i18n{multidevicePageTitle}
           </a>
 </if>
diff --git a/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb b/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb
index f98d4385..a02509a 100644
--- a/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb
+++ b/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb
@@ -152,6 +152,117 @@
 }
 
 mitm_software {
+  name: "Avast Antivirus",
+  issuer_common_name_regex: "avast! Web/Mail Shield Root",
+  issuer_organization_regex: "avast! Web/Mail Shield"
+}
+
+mitm_software {
+  name: "Bitdefender Antivirus",
+  issuer_common_name_regex: "Bitdefender Personal CA.Net-Defender",
+  issuer_organization_regex: "Bitdefender"
+}
+
+mitm_software {
+  name: "Cisco Umbrella",
+  issuer_common_name_regex: "Cisco Umbrella Root CA",
+  issuer_organization_regex: "Cisco"
+}
+
+mitm_software {
+  name: "Cisco Umbrella",
+  issuer_common_name_regex: "Cisco Umbrella Primary SubCA",
+  issuer_organization_regex: "Cisco"
+}
+
+mitm_software {
+  name: "ContentKeeper",
+  issuer_common_name_regex: "ContentKeeper Appliance CA \(\d+\)",
+  issuer_organization_regex: "ContentKeeper Technologies"
+}
+
+mitm_software {
+  name: "Cyberoam Firewall",
+  issuer_organization_regex: "Cyberoam Certificate Authority"
+}
+
+mitm_software {
+  name: "ForcePoint",
+  issuer_common_name_regex: "Forcepoint Cloud CA",
+  issuer_organization_regex: "Forcepoint LLC"
+}
+
+mitm_software {
+  name: "Fortigate",
+  issuer_common_name_regex: "FortiGate CA",
+  issuer_organization_regex: "Fortinet"
+}
+
+mitm_software {
+  name: "Fortinet",
+  issuer_organization_regex: "Fortinet( Ltd.)?"
+}
+
+mitm_software {
   name: "Kaspersky Internet Security",
   issuer_common_name_regex: "Kaspersky Anti-Virus Personal Root Certificate"
 }
+
+mitm_software {
+  name: "McAfee Web Gateway",
+  issuer_common_name_regex: "McAfee Web Gateway"
+}
+
+mitm_software {
+  name: "NetSpark",
+  issuer_common_name_regex: "www.netspark.com",
+  issuer_organization_regex: "NetSpark"
+}
+
+mitm_software {
+  name: "SmoothWall Firewall",
+  issuer_common_name_regex: "Smoothwall-default-root-certificate-authority"
+}
+
+mitm_software {
+  name: "SonicWall Firewall",
+  issuer_organization_regex: "HTTPS Management Certificate for SonicWALL"
+}
+
+mitm_software {
+  name: "Sophos",
+  issuer_common_name_regex: "Sophos SSL CA_[A-Z0-9\-]+",
+  issuer_organization_regex: "Sophos"
+}
+
+mitm_software {
+  name: "Sophos",
+  issuer_common_name_regex: "Sophos_CA_[A-Z0-9]+"
+}
+
+mitm_software {
+  name: "Sophos UTM",
+  issuer_common_name_regex: "sophosutm Proxy CA",
+  issuer_organization_regex: "sophosutm"
+}
+
+mitm_software {
+  name: "Sophos Web Appliance",
+  issuer_common_name_regex: "Sophos Web Appliance",
+  issuer_organization_regex: "Sophos Plc"
+}
+
+mitm_software {
+  name: "Symantec Blue Coat",
+  issuer_organization_regex: "Blue Coat.*"
+}
+
+mitm_software {
+  name: "Trend Micro InterScan Web Security Suite (IWSS)",
+  issuer_common_name_regex: "IWSS.TREND"
+}
+
+mitm_software {
+  name: "Zscaler",
+  issuer_organization_regex: "Zscaler Inc."
+}
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index e7bd01c..56304df 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -384,30 +384,6 @@
   }
 }
 
-void ChromePasswordProtectionService::ShowPhishingInterstitial(
-    const GURL& phishing_url,
-    const std::string& token,
-    content::WebContents* web_contents) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!ui_manager_)
-    return;
-  security_interstitials::UnsafeResource resource;
-  resource.url = phishing_url;
-  resource.original_url = phishing_url;
-  resource.is_subresource = false;
-  resource.threat_type = SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING;
-  resource.threat_source = ThreatSource::PASSWORD_PROTECTION_SERVICE;
-  resource.web_contents_getter =
-      SafeBrowsingUIManager::UnsafeResource::GetWebContentsGetter(
-          web_contents->GetRenderProcessHost()->GetID(),
-          web_contents->GetMainFrame()->GetRoutingID());
-  resource.token = token;
-  if (!ui_manager_->IsWhitelisted(resource)) {
-    web_contents->GetController().DiscardNonCommittedEntries();
-  }
-  ui_manager_->DisplayBlockingPage(resource);
-}
-
 void ChromePasswordProtectionService::UpdateSecurityState(
     SBThreatType threat_type,
     content::WebContents* web_contents) {
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.h b/chrome/browser/safe_browsing/chrome_password_protection_service.h
index 092fd1d0..fe93888 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.h
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -73,10 +73,6 @@
   void MaybeLogPasswordReuseDetectedEvent(
       content::WebContents* web_contents) override;
 
-  void ShowPhishingInterstitial(const GURL& phishing_url,
-                                const std::string& token,
-                                content::WebContents* web_contents) override;
-
   PasswordProtectionService::SyncAccountType GetSyncAccountType() override;
 
   void MaybeLogPasswordReuseLookupEvent(
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 01eaccb..fd8c295 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -57,28 +57,6 @@
 
 }  // namespace
 
-class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
- public:
-  explicit MockSafeBrowsingUIManager(SafeBrowsingService* service)
-      : SafeBrowsingUIManager(service) {}
-
-  MOCK_METHOD1(DisplayBlockingPage, void(const UnsafeResource& resource));
-
-  void InvokeOnBlockingPageComplete(
-      const security_interstitials::UnsafeResource::UrlCheckCallback&
-          callback) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    if (!callback.is_null())
-      callback.Run(false);
-  }
-
- protected:
-  virtual ~MockSafeBrowsingUIManager() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
-};
-
 class MockChromePasswordProtectionService
     : public ChromePasswordProtectionService {
  public:
@@ -101,13 +79,7 @@
     is_extended_reporting_ = is_extended_reporting;
   }
 
-  void SetUIManager(scoped_refptr<SafeBrowsingUIManager> ui_manager) {
-    ui_manager_ = ui_manager;
-  }
-
-  MockSafeBrowsingUIManager* ui_manager() {
-    return static_cast<MockSafeBrowsingUIManager*>(ui_manager_.get());
-  }
+  SafeBrowsingUIManager* ui_manager() { return ui_manager_.get(); }
 
  protected:
   friend class ChromePasswordProtectionServiceTest;
@@ -133,7 +105,7 @@
         false /* store_last_modified */);
     service_ = base::MakeUnique<MockChromePasswordProtectionService>(
         profile(), content_setting_map_,
-        new testing::StrictMock<MockSafeBrowsingUIManager>(
+        new SafeBrowsingUIManager(
             SafeBrowsingService::CreateSafeBrowsingService()));
     fake_user_event_service_ = static_cast<syncer::FakeUserEventService*>(
         browser_sync::UserEventServiceFactory::GetInstance()
@@ -263,68 +235,6 @@
       service_->IsPingingEnabled(kProtectedPasswordEntryPinging, &reason));
 }
 
-TEST_F(ChromePasswordProtectionServiceTest,
-       ShowInterstitialOnPasswordOnFocusPhishingVerdict) {
-  // Enables kPasswordProtectionInterstitial feature.
-  scoped_feature_list_.InitAndEnableFeature(kPasswordProtectionInterstitial);
-
-  InitializeRequest(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE);
-  InitializeVerdict(LoginReputationClientResponse::PHISHING);
-
-  security_interstitials::UnsafeResource resource;
-  EXPECT_CALL(*service_->ui_manager(), DisplayBlockingPage(testing::_))
-      .WillOnce(testing::SaveArg<0>(&resource));
-  RequestFinished(request_.get(), std::move(verdict_));
-  EXPECT_EQ(GURL(kPhishingURL), resource.url);
-  EXPECT_EQ(GURL(kPhishingURL), resource.original_url);
-  EXPECT_FALSE(resource.is_subresource);
-  EXPECT_EQ(SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING,
-            resource.threat_type);
-  EXPECT_EQ(ThreatSource::PASSWORD_PROTECTION_SERVICE, resource.threat_source);
-  EXPECT_EQ(web_contents(), resource.web_contents_getter.Run());
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
-                     service_->ui_manager(), resource.callback));
-}
-
-TEST_F(ChromePasswordProtectionServiceTest, NoInterstitialOnOtherVerdicts) {
-  // Enables kPasswordProtectionInterstitial feature.
-  scoped_feature_list_.InitAndEnableFeature(kPasswordProtectionInterstitial);
-
-  // For password on focus request, no interstitial shown if verdict is
-  // LOW_REPUTATION.
-  InitializeRequest(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE);
-  InitializeVerdict(LoginReputationClientResponse::LOW_REPUTATION);
-
-  security_interstitials::UnsafeResource resource;
-  EXPECT_CALL(*service_->ui_manager(), DisplayBlockingPage(testing::_))
-      .Times(0);
-  RequestFinished(request_.get(), std::move(verdict_));
-
-  // For password on focus request, no interstitial shown if verdict is
-  // SAFE.
-  InitializeVerdict(LoginReputationClientResponse::SAFE);
-  RequestFinished(request_.get(), std::move(verdict_));
-
-  // For protected password entry request, no interstitial shown if verdict is
-  // PHISHING.
-  InitializeRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
-  InitializeVerdict(LoginReputationClientResponse::PHISHING);
-  RequestFinished(request_.get(), std::move(verdict_));
-
-  // For protected password entry request, no interstitial shown if verdict is
-  // LOW_REPUTATION.
-  InitializeVerdict(LoginReputationClientResponse::LOW_REPUTATION);
-  RequestFinished(request_.get(), std::move(verdict_));
-
-  // For protected password entry request, no interstitial shown if verdict is
-  // SAFE.
-  InitializeVerdict(LoginReputationClientResponse::SAFE);
-  RequestFinished(request_.get(), std::move(verdict_));
-}
-
 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetSyncAccountType) {
   SigninManagerBase* signin_manager = static_cast<SigninManagerBase*>(
       SigninManagerFactory::GetForProfile(profile()));
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 29504001..308d489 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -18,8 +18,6 @@
 #include "chrome/browser/search/most_visited_iframe_source.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search/thumbnail_source.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/browser/thumbnails/thumbnail_list_source.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
 #include "chrome/browser/ui/webui/theme_source.h"
@@ -62,18 +60,6 @@
   // is only instantiated here (after the check for a UI thread above).
   instant_io_context_ = new InstantIOContext();
 
-  TemplateURLService* template_url_service =
-      TemplateURLServiceFactory::GetForProfile(profile_);
-  // TemplateURLService can be null in tests.
-  if (template_url_service) {
-    search_engine_base_url_tracker_ =
-        base::MakeUnique<SearchEngineBaseURLTracker>(
-            template_url_service,
-            base::MakeUnique<UIThreadSearchTermsData>(profile_),
-            base::Bind(&InstantService::OnSearchEngineBaseURLChanged,
-                       base::Unretained(this)));
-  }
-
   registrar_.Add(this,
                  content::NOTIFICATION_RENDERER_PROCESS_CREATED,
                  content::NotificationService::AllSources());
@@ -438,12 +424,3 @@
                                             weak_ptr_factory_.GetWeakPtr()),
                                  false);
 }
-
-void InstantService::OnSearchEngineBaseURLChanged(
-    SearchEngineBaseURLTracker::ChangeReason change_reason) {
-  bool google_base_url_changed =
-      change_reason ==
-      SearchEngineBaseURLTracker::ChangeReason::GOOGLE_BASE_URL;
-  for (InstantServiceObserver& observer : observers_)
-    observer.DefaultSearchProviderChanged(google_base_url_changed);
-}
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 3e0038e6..a008b00 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -16,7 +16,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
-#include "chrome/browser/search/search_engine_base_url_tracker.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/top_sites_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -95,7 +94,6 @@
 
  private:
   friend class InstantExtendedTest;
-  friend class InstantServiceTest;
   friend class InstantUnitTestBase;
 
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ProcessIsolation);
@@ -114,9 +112,6 @@
   void TopSitesChanged(history::TopSites* top_sites,
                        ChangeReason change_reason) override;
 
-  void OnSearchEngineBaseURLChanged(
-      SearchEngineBaseURLTracker::ChangeReason change_reason);
-
   // Called when a renderer process is terminated.
   void OnRendererProcessTerminated(int process_id);
 
@@ -140,8 +135,6 @@
 
   Profile* const profile_;
 
-  std::unique_ptr<SearchEngineBaseURLTracker> search_engine_base_url_tracker_;
-
   // The process ids associated with Instant processes.
   std::set<int> process_ids_;
 
diff --git a/chrome/browser/search/instant_service_observer.cc b/chrome/browser/search/instant_service_observer.cc
index 31fedf0..bed5299 100644
--- a/chrome/browser/search/instant_service_observer.cc
+++ b/chrome/browser/search/instant_service_observer.cc
@@ -10,7 +10,3 @@
 void InstantServiceObserver::MostVisitedItemsChanged(
     const std::vector<InstantMostVisitedItem>&) {
 }
-
-void InstantServiceObserver::DefaultSearchProviderChanged(
-    bool google_base_url_domain_changed) {
-}
diff --git a/chrome/browser/search/instant_service_observer.h b/chrome/browser/search/instant_service_observer.h
index 0ed36b5..e8e6820 100644
--- a/chrome/browser/search/instant_service_observer.h
+++ b/chrome/browser/search/instant_service_observer.h
@@ -20,12 +20,6 @@
   virtual void MostVisitedItemsChanged(
       const std::vector<InstantMostVisitedItem>&);
 
-  // Indicates that the default search provider changed. Parameter indicates
-  // whether the Google base URL changed (such as when the user migrates from
-  // one google.<TLD> to another TLD).
-  virtual void DefaultSearchProviderChanged(
-      bool google_base_url_domain_changed);
-
  protected:
   virtual ~InstantServiceObserver() {}
 };
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc
index 28046d52..e49aa01 100644
--- a/chrome/browser/search/instant_service_unittest.cc
+++ b/chrome/browser/search/instant_service_unittest.cc
@@ -4,66 +4,14 @@
 
 #include "chrome/browser/search/instant_service.h"
 
-#include <string>
 #include <vector>
 
-#include "chrome/browser/search/instant_service_observer.h"
 #include "chrome/browser/search/instant_unittest_base.h"
-#include "chrome/browser/search/search.h"
 #include "chrome/common/search/instant_types.h"
-#include "testing/gmock/include/gmock/gmock.h"
+#include "components/history/core/browser/history_types.h"
 #include "url/gurl.h"
 
-class MockInstantServiceObserver : public InstantServiceObserver {
- public:
-  MOCK_METHOD1(DefaultSearchProviderChanged, void(bool));
-};
-
-class InstantServiceTest : public InstantUnitTestBase {
- protected:
-  void SetUp() override {
-    InstantUnitTestBase::SetUp();
-
-    instant_service_observer_.reset(new MockInstantServiceObserver());
-    instant_service_->AddObserver(instant_service_observer_.get());
-  }
-
-  void TearDown() override {
-    instant_service_->RemoveObserver(instant_service_observer_.get());
-    InstantUnitTestBase::TearDown();
-  }
-
-  std::unique_ptr<MockInstantServiceObserver> instant_service_observer_;
-};
-
-TEST_F(InstantServiceTest, DispatchDefaultSearchProviderChanged) {
-  EXPECT_CALL(*instant_service_observer_.get(),
-              DefaultSearchProviderChanged(false)).Times(1);
-
-  const std::string new_base_url = "https://bar.com/";
-  SetUserSelectedDefaultSearchProvider(new_base_url);
-}
-
-TEST_F(InstantServiceTest, DontDispatchGoogleURLUpdatedForNonGoogleURLs) {
-  EXPECT_CALL(*instant_service_observer_.get(),
-              DefaultSearchProviderChanged(false)).Times(1);
-  const std::string new_dsp_url = "https://bar.com/";
-  SetUserSelectedDefaultSearchProvider(new_dsp_url);
-  testing::Mock::VerifyAndClearExpectations(instant_service_observer_.get());
-
-  EXPECT_CALL(*instant_service_observer_.get(),
-              DefaultSearchProviderChanged(false)).Times(0);
-  const std::string new_base_url = "https://www.google.es/";
-  NotifyGoogleBaseURLUpdate(new_base_url);
-}
-
-TEST_F(InstantServiceTest, DispatchGoogleURLUpdated) {
-  EXPECT_CALL(*instant_service_observer_.get(),
-              DefaultSearchProviderChanged(true)).Times(1);
-
-  const std::string new_base_url = "https://www.google.es/";
-  NotifyGoogleBaseURLUpdate(new_base_url);
-}
+using InstantServiceTest = InstantUnitTestBase;
 
 TEST_F(InstantServiceTest, GetSuggestionFromClientSide) {
   history::MostVisitedURLList url_list;
diff --git a/chrome/browser/search/instant_unittest_base.cc b/chrome/browser/search/instant_unittest_base.cc
index f6512dd..7c1ed94 100644
--- a/chrome/browser/search/instant_unittest_base.cc
+++ b/chrome/browser/search/instant_unittest_base.cc
@@ -77,11 +77,6 @@
   TemplateURLServiceFactory::GetForProfile(profile())->GoogleBaseURLChanged();
 }
 
-bool InstantUnitTestBase::IsInstantServiceObserver(
-    const InstantServiceObserver* observer) const {
-  return instant_service_->observers_.HasObserver(observer);
-}
-
 TestingProfile* InstantUnitTestBase::CreateProfile() {
   TestingProfile* profile = BrowserWithTestWindowTest::CreateProfile();
   TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
diff --git a/chrome/browser/search/instant_unittest_base.h b/chrome/browser/search/instant_unittest_base.h
index e489fe0..2956d2d7 100644
--- a/chrome/browser/search/instant_unittest_base.h
+++ b/chrome/browser/search/instant_unittest_base.h
@@ -13,8 +13,6 @@
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "components/search_engines/template_url_service.h"
 
-class InstantServiceObserver;
-
 // This class provides an extension on top of BrowserWithTestWindowTest, and
 // adds some utility methods which can be useful for various unit tests for
 // Embedded Search / Instant implementation classes.
@@ -38,8 +36,6 @@
   // tests, so this is required.
   void NotifyGoogleBaseURLUpdate(const std::string& new_google_base_url);
 
-  bool IsInstantServiceObserver(const InstantServiceObserver* observer) const;
-
   InstantService* instant_service_;
   TemplateURLService* template_url_service_;
   std::unique_ptr<base::FieldTrialList> field_trial_list_;
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index 95ffd49a..9f089667 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -91,15 +91,6 @@
   return GURL(ref.ReplaceSearchTerms(search_terms_args, search_terms_data));
 }
 
-// |url| should either have a secure scheme or have a non-HTTPS base URL that
-// the user specified using --google-base-url. (This allows testers to use
-// --google-base-url to point at non-HTTPS servers, which eases testing.)
-bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
-  return template_url->HasSearchTermsReplacementKey(url) &&
-         (url.SchemeIsCryptographic() ||
-          google_util::StartsWithCommandLineGoogleBaseURL(url));
-}
-
 // Returns true if |url| can be used as an Instant URL for |profile|.
 bool IsInstantURL(const GURL& url, Profile* profile) {
   if (!IsInstantExtendedAPIEnabled())
@@ -119,9 +110,17 @@
   if (!template_url)
     return false;
 
-  if (!IsSuitableURLForInstant(url, template_url))
+  if (!template_url->HasSearchTermsReplacementKey(url))
     return false;
 
+  // |url| should either have a secure scheme or have a non-HTTPS base URL that
+  // the user specified using --google-base-url. (This allows testers to use
+  // --google-base-url to point at non-HTTPS servers, which eases testing.)
+  if (!url.SchemeIsCryptographic() &&
+      !google_util::StartsWithCommandLineGoogleBaseURL(url)) {
+    return false;
+  }
+
   const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
   UIThreadSearchTermsData search_terms_data(profile);
   const GURL instant_url = TemplateURLRefToGURL(
@@ -222,8 +221,6 @@
   NewTabURLState state;
 };
 
-}  // namespace
-
 base::string16 ExtractSearchTermsFromURL(Profile* profile, const GURL& url) {
   const TemplateURL* template_url =
       GetDefaultSearchProviderTemplateURL(profile);
@@ -234,6 +231,8 @@
   return search_terms;
 }
 
+}  // namespace
+
 bool ShouldAssignURLToInstantRenderer(const GURL& url, Profile* profile) {
   return url.is_valid() &&
          profile &&
@@ -329,38 +328,6 @@
          profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
 }
 
-GURL GetInstantURL(Profile* profile, bool force_instant_results) {
-  if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile))
-    return GURL();
-
-  const TemplateURL* template_url =
-      GetDefaultSearchProviderTemplateURL(profile);
-  if (!template_url)
-    return GURL();
-
-  GURL instant_url = TemplateURLRefToGURL(
-      template_url->instant_url_ref(), UIThreadSearchTermsData(profile),
-      true, force_instant_results);
-  if (!instant_url.is_valid() ||
-      !template_url->HasSearchTermsReplacementKey(instant_url))
-    return GURL();
-
-  // Extended mode requires HTTPS.  Force it unless the base URL was overridden
-  // on the command line, in which case we allow HTTP (see comments on
-  // IsSuitableURLForInstant()).
-  if (!instant_url.SchemeIsCryptographic() &&
-      !google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) {
-    GURL::Replacements replacements;
-    replacements.SetSchemeStr(url::kHttpsScheme);
-    instant_url = instant_url.ReplaceComponents(replacements);
-  }
-
-  if (!IsURLAllowedForSupervisedUser(instant_url, profile))
-    return GURL();
-
-  return instant_url;
-}
-
 // Returns URLs associated with the default search engine for |profile|.
 std::vector<GURL> GetSearchURLs(Profile* profile) {
   std::vector<GURL> result;
@@ -379,10 +346,6 @@
   return NewTabURLDetails::ForProfile(profile).url;
 }
 
-GURL GetSearchResultPrefetchBaseURL(Profile* profile) {
-  return GetInstantURL(profile, true);
-}
-
 GURL GetEffectiveURLForInstant(const GURL& url, Profile* profile) {
   CHECK(ShouldAssignURLToInstantRenderer(url, profile))
       << "Error granting Instant access.";
diff --git a/chrome/browser/search/search.h b/chrome/browser/search/search.h
index 993a3ac..5959d66 100644
--- a/chrome/browser/search/search.h
+++ b/chrome/browser/search/search.h
@@ -34,9 +34,6 @@
 // Returns whether the suggest is enabled for the given |profile|.
 bool IsSuggestPrefEnabled(Profile* profile);
 
-// Extracts and returns search terms from |url|.
-base::string16 ExtractSearchTermsFromURL(Profile* profile, const GURL& url);
-
 // Returns true if |url| should be rendered in the Instant renderer process.
 bool ShouldAssignURLToInstantRenderer(const GURL& url, Profile* profile);
 
@@ -75,26 +72,9 @@
 // by Instant.
 bool IsInstantNTPURL(const GURL& url, Profile* profile);
 
-// Returns the Instant URL of the default search engine. Returns an empty GURL
-// if the engine doesn't have an Instant URL, or if it shouldn't be used (say
-// because it doesn't satisfy the requirements for extended mode or if Instant
-// is disabled through preferences). Callers must check that the returned URL is
-// valid before using it. |force_instant_results| forces a search page to update
-// results incrementally even if that is otherwise disabled by google.com
-// preferences.
-// NOTE: This method expands the default search engine's instant_url template,
-// so it shouldn't be called from SearchTermsData or other such code that would
-// lead to an infinite recursion.
-GURL GetInstantURL(Profile* profile, bool force_instant_results);
-
 // Returns URLs associated with the default search engine for |profile|.
 std::vector<GURL> GetSearchURLs(Profile* profile);
 
-// Returns the default search engine base page URL to prefetch search results.
-// Returns an empty URL if 'prefetch_results' flag is set to false in field
-// trials.
-GURL GetSearchResultPrefetchBaseURL(Profile* profile);
-
 
 // Transforms the input |url| into its "effective URL". |url| must be an
 // Instant URL, i.e. ShouldAssignURLToInstantRenderer must return true. The
diff --git a/chrome/browser/search/search_engine_base_url_tracker_unittest.cc b/chrome/browser/search/search_engine_base_url_tracker_unittest.cc
new file mode 100644
index 0000000..5c7e398
--- /dev/null
+++ b/chrome/browser/search/search_engine_base_url_tracker_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/search/search_engine_base_url_tracker.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/test/mock_callback.h"
+#include "chrome/browser/search/instant_unittest_base.h"
+#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
+#include "url/gurl.h"
+
+using SearchEngineBaseURLTrackerTest = InstantUnitTestBase;
+
+TEST_F(SearchEngineBaseURLTrackerTest, DispatchDefaultSearchProviderChanged) {
+  base::MockCallback<SearchEngineBaseURLTracker::BaseURLChangedCallback>
+      callback;
+  SearchEngineBaseURLTracker tracker(
+      template_url_service_,
+      base::MakeUnique<UIThreadSearchTermsData>(profile()), callback.Get());
+
+  // Changing the search provider should invoke the callback.
+  EXPECT_CALL(
+      callback,
+      Run(SearchEngineBaseURLTracker::ChangeReason::DEFAULT_SEARCH_PROVIDER));
+  SetUserSelectedDefaultSearchProvider("https://bar.com/");
+}
+
+TEST_F(SearchEngineBaseURLTrackerTest, DispatchGoogleURLUpdated) {
+  base::MockCallback<SearchEngineBaseURLTracker::BaseURLChangedCallback>
+      callback;
+  SearchEngineBaseURLTracker tracker(
+      template_url_service_,
+      base::MakeUnique<UIThreadSearchTermsData>(profile()), callback.Get());
+
+  // While Google is the default search provider, changes to the Google base URL
+  // should invoke the callback.
+  EXPECT_CALL(callback,
+              Run(SearchEngineBaseURLTracker::ChangeReason::GOOGLE_BASE_URL));
+  NotifyGoogleBaseURLUpdate("https://www.google.es/");
+}
+
+TEST_F(SearchEngineBaseURLTrackerTest,
+       DontDispatchGoogleURLUpdatedForNonGoogleSearchProvider) {
+  base::MockCallback<SearchEngineBaseURLTracker::BaseURLChangedCallback>
+      callback;
+  SearchEngineBaseURLTracker tracker(
+      template_url_service_,
+      base::MakeUnique<UIThreadSearchTermsData>(profile()), callback.Get());
+
+  // Set up a non-Google default search provider.
+  EXPECT_CALL(
+      callback,
+      Run(SearchEngineBaseURLTracker::ChangeReason::DEFAULT_SEARCH_PROVIDER));
+  SetUserSelectedDefaultSearchProvider("https://bar.com/");
+  testing::Mock::VerifyAndClearExpectations(&callback);
+
+  // Now, a change to the Google base URL should not invoke the callback.
+  EXPECT_CALL(callback, Run(testing::_)).Times(0);
+  NotifyGoogleBaseURLUpdate("https://www.google.es/");
+}
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index 0f3f5db..c4d375c 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -380,11 +380,7 @@
   NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
   EXPECT_TRUE(NavEntryIsInstantNTP(contents,
                                    controller.GetLastCommittedEntry()));
-  // Instant page is not cacheable NTP.
-  NavigateAndCommitActiveTab(GetInstantURL(profile(), false));
-  EXPECT_FALSE(NavEntryIsInstantNTP(contents,
-                                    controller.GetLastCommittedEntry()));
-  // Test Cacheable NTP
+  // Remote NTP.
   NavigateAndCommitActiveTab(GetNewTabPageURL(profile()));
   EXPECT_TRUE(NavEntryIsInstantNTP(contents,
                                    controller.GetLastCommittedEntry()));
@@ -448,81 +444,9 @@
   GURL new_tab_url(chrome::kChromeUINewTabURL);
   EXPECT_TRUE(HandleNewTabURLRewrite(&new_tab_url, profile()));
   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), new_tab_url);
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), false));
 }
 #endif
 
-TEST_F(SearchTest, GetInstantURL) {
-  // No Instant URL because "strk" is missing.
-  SetDefaultInstantTemplateUrl(false);
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), false));
-
-  // Set an Instant URL with a valid search terms replacement key.
-  SetDefaultInstantTemplateUrl(true);
-
-  // Now there should be a valid Instant URL. Note the HTTPS "upgrade".
-  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), false));
-
-  // Enable suggest. No difference.
-  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
-  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), false));
-
-  // Disable suggest. No Instant URL.
-  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
-  EXPECT_EQ(GURL(), GetInstantURL(profile(), false));
-}
-
-TEST_F(SearchTest, InstantSearchEnabledCGI) {
-  // Disable Instant Search.
-  // Make sure {google:forceInstantResults} is not set in the Instant URL.
-  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), false));
-
-  // Enable Instant Search.
-  // Make sure {google:forceInstantResults} is set in the Instant URL.
-  EXPECT_EQ(GURL("https://foo.com/instant?ion=1&foo=foo#foo=foo&strk"),
-            GetInstantURL(profile(), true));
-}
-
-TEST_F(SearchTest, CommandLineOverrides) {
-  TemplateURLService* template_url_service =
-      TemplateURLServiceFactory::GetForProfile(profile());
-  TemplateURLData data;
-  data.SetShortName(base::ASCIIToUTF16("Google"));
-  data.SetURL("{google:baseURL}search?q={searchTerms}");
-  data.instant_url = "{google:baseURL}webhp?strk";
-  data.search_terms_replacement_key = "strk";
-  TemplateURL* template_url =
-      template_url_service->Add(base::MakeUnique<TemplateURL>(data));
-  template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
-
-  // By default, Instant Extended forces the instant URL to be HTTPS, so even if
-  // we set a Google base URL that is HTTP, we should get an HTTPS URL.
-  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
-  GURL instant_url(GetInstantURL(profile(), false));
-  ASSERT_TRUE(instant_url.is_valid());
-  EXPECT_EQ("https://www.foo.com/webhp?strk", instant_url.spec());
-
-  // However, if the Google base URL is specified on the command line, the
-  // instant URL should just use it, even if it's HTTP.
-  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kGoogleBaseURL, "http://www.bar.com/");
-  instant_url = GetInstantURL(profile(), false);
-  ASSERT_TRUE(instant_url.is_valid());
-  EXPECT_EQ("http://www.bar.com/webhp?strk", instant_url.spec());
-
-  // If we specify extra search query params, they should be inserted into the
-  // query portion of the instant URL.
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kExtraSearchQueryParams, "a=b");
-  instant_url = GetInstantURL(profile(), false);
-  ASSERT_TRUE(instant_url.is_valid());
-  EXPECT_EQ("http://www.bar.com/webhp?a=b&strk", instant_url.spec());
-}
-
 TEST_F(SearchTest, IsNTPURL) {
   GURL invalid_url;
   GURL ntp_url(chrome::kChromeUINewTabURL);
@@ -531,7 +455,7 @@
   EXPECT_FALSE(IsNTPURL(invalid_url, profile()));
   // No margin.
   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
-  GURL remote_ntp_url(GetInstantURL(profile(), false));
+  GURL remote_ntp_url(GetNewTabPageURL(profile()));
   GURL remote_ntp_service_worker_url("https://foo.com/newtab-serviceworker.js");
   GURL search_url_with_search_terms("https://foo.com/url?strk&bar=abc");
   GURL search_url_without_search_terms("https://foo.com/url?strk&bar");
@@ -558,35 +482,6 @@
   EXPECT_EQ("http://foo.com/url?bar=", search_urls[1].spec());
 }
 
-TEST_F(SearchTest, GetSearchResultPrefetchBaseURL) {
-  EXPECT_EQ(GURL("https://foo.com/instant?ion=1&foo=foo#foo=foo&strk"),
-            GetSearchResultPrefetchBaseURL(profile()));
-}
-
-struct ExtractSearchTermsTestCase {
-  const char* url;
-  const char* expected_result;
-  const char* comment;
-};
-
-TEST_F(SearchTest, ExtractSearchTermsFromURL) {
-  const ExtractSearchTermsTestCase kTestCases[] = {
-    {chrome::kChromeSearchLocalNtpUrl,           "",    "NTP url"},
-    {"https://foo.com/instant?strk",             "",    "Invalid search url"},
-    {"https://foo.com/instant#strk",             "",    "Invalid search url"},
-    {"https://foo.com/alt#quux=foo",             "foo", "Valid search url"},
-    {"https://foo.com/alt#quux=foo&strk",        "foo", "Valid search url"}
-  };
-
-  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
-    const ExtractSearchTermsTestCase& test = kTestCases[i];
-    EXPECT_EQ(test.expected_result,
-              base::UTF16ToASCII(
-                  ExtractSearchTermsFromURL(profile(), GURL(test.url))))
-        << test.url << " " << test.comment;
-  }
-}
-
 // Regression test for https://crbug.com/605720: Set up a search provider backed
 // by localhost on a specific port, like browsertests do.  The chrome-search://
 // URLs generated in this mode should not have ports.
diff --git a/chrome/browser/signin/chrome_signin_client_unittest.cc b/chrome/browser/signin/chrome_signin_client_unittest.cc
index 704c7b7..0d74a6c 100644
--- a/chrome/browser/signin/chrome_signin_client_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_client_unittest.cc
@@ -140,9 +140,10 @@
   explicit MockSigninManager(SigninClient* client)
       : SigninManager(client, nullptr, &fake_service_, nullptr) {}
 
-  MOCK_METHOD2(DoSignOut,
+  MOCK_METHOD3(DoSignOut,
                void(signin_metrics::ProfileSignout,
-                    signin_metrics::SignoutDelete));
+                    signin_metrics::SignoutDelete,
+                    bool revoke_all_tokens));
 
   AccountTrackerService fake_service_;
 };
@@ -183,7 +184,8 @@
       .Times(1);
   EXPECT_CALL(*client_, LockForceSigninProfile(browser()->profile()->GetPath()))
       .Times(1);
-  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric)).Times(1);
+  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric, true))
+      .Times(1);
 
   manager_->SignOut(source_metric, delete_metric);
 }
@@ -201,7 +203,8 @@
       .Times(0);
   EXPECT_CALL(*client_, LockForceSigninProfile(browser()->profile()->GetPath()))
       .Times(1);
-  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric)).Times(1);
+  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric, true))
+      .Times(1);
   manager_->SignOut(source_metric, delete_metric);
 
   ::testing::Mock::VerifyAndClearExpectations(manager_.get());
@@ -210,7 +213,8 @@
       .Times(1);
   EXPECT_CALL(*client_, LockForceSigninProfile(browser()->profile()->GetPath()))
       .Times(1);
-  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric)).Times(1);
+  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric, true))
+      .Times(1);
   manager_->SignOut(source_metric, delete_metric);
 }
 
@@ -228,7 +232,8 @@
       .Times(0);
   EXPECT_CALL(*client_, LockForceSigninProfile(browser()->profile()->GetPath()))
       .Times(0);
-  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric)).Times(1);
+  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric, true))
+      .Times(1);
   manager_->SignOut(source_metric, delete_metric);
 }
 
@@ -249,7 +254,8 @@
       .Times(0);
   EXPECT_CALL(*client_, LockForceSigninProfile(browser()->profile()->GetPath()))
       .Times(0);
-  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric)).Times(1);
+  EXPECT_CALL(*manager_, DoSignOut(source_metric, delete_metric, true))
+      .Times(1);
   manager_->SignOut(source_metric, delete_metric);
 }
 
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc
index 993c8280..b5037476 100644
--- a/chrome/browser/signin/dice_response_handler.cc
+++ b/chrome/browser/signin/dice_response_handler.cc
@@ -302,8 +302,9 @@
     if (signed_out_account == current_account) {
       VLOG(1) << "[Dice] Signing out all accounts.";
       RecordDiceResponseHeader(kSignoutPrimary);
-      signin_manager_->SignOut(signin_metrics::SERVER_FORCED_DISABLE,
-                               signin_metrics::SignoutDelete::IGNORE_METRIC);
+      signin_manager_->SignOutAndRemoveAllAccounts(
+          signin_metrics::SERVER_FORCED_DISABLE,
+          signin_metrics::SignoutDelete::IGNORE_METRIC);
       // Cancel all Dice token fetches currently in flight.
       token_fetchers_.clear();
       return;
diff --git a/chrome/browser/signin/force_signin_verifier.cc b/chrome/browser/signin/force_signin_verifier.cc
index 0311d85..0fb7ca9 100644
--- a/chrome/browser/signin/force_signin_verifier.cc
+++ b/chrome/browser/signin/force_signin_verifier.cc
@@ -154,7 +154,7 @@
   // signin process should take care of the signout.
   if (signin_manager_->AuthInProgress())
     return;
-  signin_manager_->SignOut(
+  signin_manager_->SignOutAndRemoveAllAccounts(
       signin_metrics::AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN,
       signin_metrics::SignoutDelete::IGNORE_METRIC);
 }
diff --git a/chrome/browser/signin/signin_error_notifier_ash.cc b/chrome/browser/signin/signin_error_notifier_ash.cc
index 40efd9ef..4b1055cc 100644
--- a/chrome/browser/signin/signin_error_notifier_ash.cc
+++ b/chrome/browser/signin/signin_error_notifier_ash.cc
@@ -29,6 +29,7 @@
 #include "components/user_manager/user_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center_style.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_delegate.h"
 
@@ -142,11 +143,13 @@
   Notification notification(
       message_center::NOTIFICATION_TYPE_SIMPLE,
       l10n_util::GetStringUTF16(IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE),
-      GetMessageBody(), ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-                            IDR_NOTIFICATION_ALERT),
-      notifier_id,
-      base::string16(),  // display_source
+      GetMessageBody(),
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+          IDR_NOTIFICATION_ALERT),
+      notifier_id, l10n_util::GetStringUTF16(IDS_SIGNIN_ERROR_DISPLAY_SOURCE),
       GURL(notification_id_), notification_id_, data, delegate);
+  notification.set_accent_color(
+      message_center::kSystemNotificationColorCriticalWarning);
   notification.SetSystemPriority();
 
   // Update or add the notification.
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc
index 74be90fe..33b36b8 100644
--- a/chrome/browser/ssl/security_state_tab_helper.cc
+++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -190,7 +190,6 @@
         break;
       case safe_browsing::SB_THREAT_TYPE_URL_PHISHING:
       case safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING:
-      case safe_browsing::SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING:
         return security_state::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING;
       case safe_browsing::SB_THREAT_TYPE_URL_MALWARE:
       case safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE:
@@ -208,6 +207,8 @@
         }
         break;
 #endif
+      case safe_browsing::
+          DEPRECATED_SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING:
       case safe_browsing::SB_THREAT_TYPE_URL_BINARY_MALWARE:
       case safe_browsing::SB_THREAT_TYPE_EXTENSION:
       case safe_browsing::SB_THREAT_TYPE_BLACKLISTED_RESOURCE:
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 6a321ea..713ffe2 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -5419,7 +5419,6 @@
             base::RetainedRef(browser()->profile()->GetRequestContext())));
   }
 
- protected:
   // Set up the cert verifier to return the error passed in as the cert_error
   // parameter.
   void SetUpCertVerifier(net::CertStatus cert_error) {
@@ -5531,26 +5530,59 @@
   DISALLOW_COPY_AND_ASSIGN(SSLUIMITMSoftwareTest);
 };
 
+// The SSLUIMITMSoftwareEnabled and Disabled test classes exist so that the
+// scoped feature list can be instantiated in the set up method of the class
+// rather than in the test itself. Bug crbug.com/713390 was causing some of the
+// tests in SSLUIMITMSoftwareTest to be flaky. Refactoring these tests so that
+// the scoped feature list initialization is done in the set up method fixes
+// this flakiness.
+
+class SSLUIMITMSoftwareEnabledTest : public SSLUIMITMSoftwareTest {
+ public:
+  SSLUIMITMSoftwareEnabledTest() {}
+  ~SSLUIMITMSoftwareEnabledTest() override {}
+
+  void SetUpOnMainThread() override {
+    SSLUIMITMSoftwareTest::SetUpOnMainThread();
+    scoped_feature_list_.InitFromCommandLine(
+        "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSLUIMITMSoftwareEnabledTest);
+};
+
+class SSLUIMITMSoftwareDisabledTest : public SSLUIMITMSoftwareTest {
+ public:
+  SSLUIMITMSoftwareDisabledTest() {}
+  ~SSLUIMITMSoftwareDisabledTest() override {}
+
+  void SetUpOnMainThread() override {
+    SSLUIMITMSoftwareTest::SetUpOnMainThread();
+    scoped_feature_list_.InitFromCommandLine(
+        std::string() /* enabled */, "MITMSoftwareInterstitial" /* disabled */);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(SSLUIMITMSoftwareDisabledTest);
+};
+
 }  // namespace
 
 // Tests that the MITM software interstitial is not displayed when the feature
 // is disabled by Finch.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, DisabledWithFinch) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      std::string() /* enabled */, "MITMSoftwareInterstitial" /* disabled */);
-
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareDisabledTest, DisabledWithFinch) {
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   TestNoMITMSoftwareInterstitial();
 }
 
 // Tests that the MITM software interstitial is displayed when the feature is
 // enabled by Finch.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, EnabledWithFinch) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
-
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest, EnabledWithFinch) {
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   TestMITMSoftwareInterstitial();
 }
@@ -5559,14 +5591,10 @@
 // cert on the list but not the organization name, the MITM software
 // interstitial will not be displayed.
 IN_PROC_BROWSER_TEST_F(
-    SSLUIMITMSoftwareTest,
+    SSLUIMITMSoftwareEnabledTest,
     CertificateCommonNameMatchOnly_NoMITMSoftwareInterstitial) {
   base::HistogramTester histograms;
 
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
-
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   ASSERT_TRUE(https_server()->Start());
 
@@ -5610,14 +5638,10 @@
 // software cert on the list but not the common name, the MITM software
 // interstitial will not be displayed.
 IN_PROC_BROWSER_TEST_F(
-    SSLUIMITMSoftwareTest,
+    SSLUIMITMSoftwareEnabledTest,
     CertificateOrganizationMatchOnly_NoMITMSoftwareInterstitial) {
   base::HistogramTester histograms;
 
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
-
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   ASSERT_TRUE(https_server()->Start());
 
@@ -5659,14 +5683,10 @@
 
 // Tests that if the certificate does not match any entry on the list of known
 // MITM software, the MITM software interstitial will not be displayed.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest,
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest,
                        NonMatchingCertificate_NoMITMSoftwareInterstitial) {
   base::HistogramTester histograms;
 
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
-
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   ASSERT_TRUE(https_server()->Start());
 
@@ -5708,12 +5728,8 @@
 
 // Tests that if there is more than one error on the certificate the MITM
 // software interstitial will not be displayed.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest,
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest,
                        TwoCertErrors_NoMITMSoftwareInterstitial) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
-
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID |
                     net::CERT_STATUS_COMMON_NAME_INVALID);
   TestNoMITMSoftwareInterstitial();
@@ -5721,25 +5737,18 @@
 
 // Tests that a certificate error other than |CERT_STATUS_AUTHORITY_INVALID|
 // will not trigger the MITM software interstitial.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest,
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest,
                        WrongCertError_NoMITMSoftwareInterstitial) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
-
   SetUpCertVerifier(net::CERT_STATUS_COMMON_NAME_INVALID);
   TestNoMITMSoftwareInterstitial();
 }
 
 // Tests that if the error on the certificate served is overridable the MITM
 // software interstitial will not be displayed.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest,
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest,
                        OverridableError_NoMITMSoftwareInterstitial) {
   base::HistogramTester histograms;
 
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
 
   ASSERT_TRUE(https_server()->Start());
@@ -5772,10 +5781,7 @@
 
 // Tests that the correct strings are displayed on the interstitial in the
 // enterprise managed case.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, EnterpriseManaged) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest, EnterpriseManaged) {
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   SSLErrorHandler::SetEnterpriseManagedForTesting(true);
   ASSERT_TRUE(SSLErrorHandler::IsEnterpriseManagedFlagSetForTesting());
@@ -5805,10 +5811,7 @@
 
 // Tests that the correct strings are displayed on the interstitial in the
 // non-enterprise managed case.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest, NotEnterpriseManaged) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest, NotEnterpriseManaged) {
   SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   SSLErrorHandler::SetEnterpriseManagedForTesting(false);
   ASSERT_TRUE(SSLErrorHandler::IsEnterpriseManagedFlagSetForTesting());
@@ -5837,12 +5840,9 @@
 
 // Tests that the MITM software interstitial does not render on iOS, where it
 // is disabled by build.
-IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareTest,
+IN_PROC_BROWSER_TEST_F(SSLUIMITMSoftwareEnabledTest,
                        DisabledByBuild_NoMITMSoftwareInterstitial) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "MITMSoftwareInterstitial" /* enabled */, std::string() /* disabled */);
-
+  SetUpCertVerifier(net::CERT_STATUS_AUTHORITY_INVALID);
   TestNoMITMSoftwareInterstitial();
 }
 
diff --git a/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc b/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc
index a74ec05..24319b5d 100644
--- a/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_preferences_sync_test.cc
@@ -127,7 +127,7 @@
   ASSERT_TRUE(AwaitEncryptionComplete(0));
   ASSERT_TRUE(AwaitEncryptionComplete(1));
   ASSERT_TRUE(StringPrefMatchChecker(prefs::kHomePage).Wait());
-  ASSERT_TRUE(BooleanPrefMatches(prefs::kHomePageIsNewTabPage));
+  ASSERT_TRUE(BooleanPrefMatchChecker(prefs::kHomePageIsNewTabPage).Wait());
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest,
diff --git a/chrome/browser/task_manager/providers/web_contents/background_contents_task.cc b/chrome/browser/task_manager/providers/web_contents/background_contents_task.cc
index 7d1199ff..f55ee9f 100644
--- a/chrome/browser/task_manager/providers/web_contents/background_contents_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/background_contents_task.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/task_manager/providers/web_contents/background_contents_task.h"
 
+#include <string>
+
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/background/background_contents_service.h"
@@ -12,8 +14,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/view_type_utils.h"
 #include "extensions/common/extension_set.h"
@@ -59,11 +59,9 @@
     const base::string16& title,
     BackgroundContents* background_contents)
     : RendererTask(
-        AdjustAndLocalizeTitle(title, background_contents->GetURL().spec()),
-        GetDefaultIcon(),
-        background_contents->web_contents(),
-        background_contents->web_contents()->GetRenderProcessHost()) {
-}
+          AdjustAndLocalizeTitle(title, background_contents->GetURL().spec()),
+          GetDefaultIcon(),
+          background_contents->web_contents()) {}
 
 BackgroundContentsTask::~BackgroundContentsTask() {
 }
diff --git a/chrome/browser/task_manager/providers/web_contents/extension_task.cc b/chrome/browser/task_manager/providers/web_contents/extension_task.cc
index 4ceb7b1..a6eaec1 100644
--- a/chrome/browser/task_manager/providers/web_contents/extension_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/extension_task.cc
@@ -45,8 +45,7 @@
                              extensions::ViewType view_type)
     : RendererTask(GetExtensionTitle(web_contents, extension, view_type),
                    GetDefaultIcon(),
-                   web_contents,
-                   web_contents->GetRenderProcessHost()),
+                   web_contents),
       view_type_(view_type) {
   LoadExtensionIcon(extension);
 }
diff --git a/chrome/browser/task_manager/providers/web_contents/guest_task.cc b/chrome/browser/task_manager/providers/web_contents/guest_task.cc
index 88b4a6df..a25d92a 100644
--- a/chrome/browser/task_manager/providers/web_contents/guest_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/guest_task.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/task_manager/providers/web_contents/guest_task.h"
 
 #include "components/guest_view/browser/guest_view_base.h"
-#include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace task_manager {
@@ -13,9 +12,7 @@
 GuestTask::GuestTask(content::WebContents* web_contents)
     : RendererTask(GetCurrentTitle(web_contents),
                    GetFaviconFromWebContents(web_contents),
-                   web_contents,
-                   web_contents->GetRenderProcessHost()) {
-}
+                   web_contents) {}
 
 GuestTask::~GuestTask() {
 }
diff --git a/chrome/browser/task_manager/providers/web_contents/prerender_task.cc b/chrome/browser/task_manager/providers/web_contents/prerender_task.cc
index 680d7cff..c0efd6e 100644
--- a/chrome/browser/task_manager/providers/web_contents/prerender_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/prerender_task.cc
@@ -6,7 +6,6 @@
 
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_skia.h"
@@ -41,9 +40,7 @@
     : RendererTask(
           PrefixTitle(RendererTask::GetTitleFromWebContents(web_contents)),
           GetPrerenderIcon(),
-          web_contents,
-          web_contents->GetRenderProcessHost()) {
-}
+          web_contents) {}
 
 PrerenderTask::~PrerenderTask() {
 }
diff --git a/chrome/browser/task_manager/providers/web_contents/printing_task.cc b/chrome/browser/task_manager/providers/web_contents/printing_task.cc
index 15bbf3f4..dfb5a07 100644
--- a/chrome/browser/task_manager/providers/web_contents/printing_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/printing_task.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/task_manager/providers/web_contents/printing_task.h"
 
 #include "chrome/grit/generated_resources.h"
-#include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace task_manager {
@@ -20,11 +19,9 @@
 
 PrintingTask::PrintingTask(content::WebContents* web_contents)
     : RendererTask(
-        PrefixTitle(RendererTask::GetTitleFromWebContents(web_contents)),
-        RendererTask::GetFaviconFromWebContents(web_contents),
-        web_contents,
-        web_contents->GetRenderProcessHost()) {
-}
+          PrefixTitle(RendererTask::GetTitleFromWebContents(web_contents)),
+          RendererTask::GetFaviconFromWebContents(web_contents),
+          web_contents) {}
 
 PrintingTask::~PrintingTask() {
 }
diff --git a/chrome/browser/task_manager/providers/web_contents/renderer_task.cc b/chrome/browser/task_manager/providers/web_contents/renderer_task.cc
index 187b4e5..2bf8ad3 100644
--- a/chrome/browser/task_manager/providers/web_contents/renderer_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/renderer_task.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/task_manager/providers/web_contents/renderer_task.h"
 
+#include <string>
 #include <utility>
 
 #include "base/i18n/rtl.h"
@@ -16,6 +17,7 @@
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/task_manager/task_manager_observer.h"
 #include "chrome/grit/generated_resources.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
@@ -57,6 +59,22 @@
 
 RendererTask::RendererTask(const base::string16& title,
                            const gfx::ImageSkia* icon,
+                           content::WebContents* web_contents)
+    : RendererTask(title,
+                   icon,
+                   web_contents,
+                   web_contents->GetMainFrame()->GetProcess()) {}
+
+RendererTask::RendererTask(const base::string16& title,
+                           const gfx::ImageSkia* icon,
+                           content::RenderFrameHost* subframe)
+    : RendererTask(title,
+                   icon,
+                   content::WebContents::FromRenderFrameHost(subframe),
+                   subframe->GetProcess()) {}
+
+RendererTask::RendererTask(const base::string16& title,
+                           const gfx::ImageSkia* icon,
                            content::WebContents* web_contents,
                            content::RenderProcessHost* render_process_host)
     : Task(title,
diff --git a/chrome/browser/task_manager/providers/web_contents/renderer_task.h b/chrome/browser/task_manager/providers/web_contents/renderer_task.h
index 57b1c4e..2fbf6149 100644
--- a/chrome/browser/task_manager/providers/web_contents/renderer_task.h
+++ b/chrome/browser/task_manager/providers/web_contents/renderer_task.h
@@ -17,6 +17,7 @@
 class ProcessResourceUsage;
 
 namespace content {
+class RenderFrameHost;
 class RenderProcessHost;
 class WebContents;
 }  // namespace content
@@ -30,8 +31,10 @@
  public:
   RendererTask(const base::string16& title,
                const gfx::ImageSkia* icon,
-               content::WebContents* web_contents,
-               content::RenderProcessHost* render_process_host);
+               content::WebContents* web_contents);
+  RendererTask(const base::string16& title,
+               const gfx::ImageSkia* icon,
+               content::RenderFrameHost* subframe);
   ~RendererTask() override;
 
   // An abstract method that will be called when the event
@@ -102,6 +105,11 @@
                                                   bool is_background);
 
  private:
+  RendererTask(const base::string16& title,
+               const gfx::ImageSkia* icon,
+               content::WebContents* web_contents,
+               content::RenderProcessHost* render_process_host);
+
   // The WebContents of the task this object represents.
   content::WebContents* web_contents_;
 
diff --git a/chrome/browser/task_manager/providers/web_contents/subframe_task.cc b/chrome/browser/task_manager/providers/web_contents/subframe_task.cc
index 4f772bd..7b0200e 100644
--- a/chrome/browser/task_manager/providers/web_contents/subframe_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/subframe_task.cc
@@ -4,13 +4,14 @@
 
 #include "chrome/browser/task_manager/providers/web_contents/subframe_task.h"
 
+#include <string>
+
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/site_instance.h"
-#include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
@@ -22,10 +23,7 @@
 SubframeTask::SubframeTask(content::RenderFrameHost* render_frame_host,
                            content::WebContents* web_contents,
                            RendererTask* main_task)
-    : RendererTask(base::string16(),
-                   nullptr,
-                   web_contents,
-                   render_frame_host->GetProcess()),
+    : RendererTask(base::string16(), nullptr, render_frame_host),
       site_instance_(render_frame_host->GetSiteInstance()),
       main_task_(main_task) {
   set_title(GetTitle());
diff --git a/chrome/browser/task_manager/providers/web_contents/tab_contents_task.cc b/chrome/browser/task_manager/providers/web_contents/tab_contents_task.cc
index 098200d..6153fc2b 100644
--- a/chrome/browser/task_manager/providers/web_contents/tab_contents_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/tab_contents_task.cc
@@ -22,12 +22,10 @@
 
 }  // namespace
 
-
 TabContentsTask::TabContentsTask(content::WebContents* web_contents)
     : RendererTask(base::string16(),
                    RendererTask::GetFaviconFromWebContents(web_contents),
-                   web_contents,
-                   web_contents->GetRenderProcessHost()) {
+                   web_contents) {
   set_title(GetCurrentTitle());
 }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 38deca5..ee575e1 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -146,8 +146,6 @@
     "protocol_dialog_delegate.h",
     "proximity_auth/proximity_auth_error_bubble.h",
     "screen_capture_notification_ui.h",
-    "search/instant_tab.cc",
-    "search/instant_tab.h",
     "search/new_tab_page_interceptor_service.cc",
     "search/new_tab_page_interceptor_service.h",
     "search/new_tab_page_interceptor_service_factory.cc",
@@ -510,6 +508,7 @@
     "//components/dom_distiller/content/browser",
     "//components/dom_distiller/webui",
     "//components/domain_reliability",
+    "//components/download/content/factory",
     "//components/download/content/public",
     "//components/favicon/content",
     "//components/favicon/core",
@@ -2837,14 +2836,12 @@
         "cocoa/location_bar/location_bar_decoration.mm",
         "cocoa/location_bar/location_bar_view_mac.h",
         "cocoa/location_bar/location_bar_view_mac.mm",
-        "cocoa/location_bar/location_icon_decoration.h",
-        "cocoa/location_bar/location_icon_decoration.mm",
         "cocoa/location_bar/manage_passwords_decoration.h",
         "cocoa/location_bar/manage_passwords_decoration.mm",
+        "cocoa/location_bar/page_info_bubble_decoration.h",
+        "cocoa/location_bar/page_info_bubble_decoration.mm",
         "cocoa/location_bar/save_credit_card_decoration.h",
         "cocoa/location_bar/save_credit_card_decoration.mm",
-        "cocoa/location_bar/security_state_bubble_decoration.h",
-        "cocoa/location_bar/security_state_bubble_decoration.mm",
         "cocoa/location_bar/selected_keyword_decoration.h",
         "cocoa/location_bar/selected_keyword_decoration.mm",
         "cocoa/location_bar/star_decoration.h",
diff --git a/chrome/browser/ui/android/infobars/permission_infobar.cc b/chrome/browser/ui/android/infobars/permission_infobar.cc
index 9a78e975..7e37cbc 100644
--- a/chrome/browser/ui/android/infobars/permission_infobar.cc
+++ b/chrome/browser/ui/android/infobars/permission_infobar.cc
@@ -12,7 +12,6 @@
 #include "base/android/jni_string.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/permissions/permission_infobar_delegate.h"
 #include "chrome/browser/ui/android/infobars/confirm_infobar.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "jni/PermissionInfoBar_jni.h"
@@ -22,56 +21,6 @@
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
 
-std::unique_ptr<infobars::InfoBar> CreatePermissionInfoBar(
-    std::unique_ptr<PermissionInfoBarDelegate> delegate) {
-  return base::WrapUnique(new PermissionInfoBar(std::move(delegate)));
-}
-
-PermissionInfoBar::PermissionInfoBar(
-    std::unique_ptr<PermissionInfoBarDelegate> delegate)
-    : ConfirmInfoBar(std::move(delegate)) {}
-
-PermissionInfoBar::~PermissionInfoBar() = default;
-
-PermissionInfoBarDelegate* PermissionInfoBar::GetDelegate() {
-  return delegate()->AsPermissionInfoBarDelegate();
-}
-
-ScopedJavaLocalRef<jobject> PermissionInfoBar::CreateRenderInfoBar(
-    JNIEnv* env) {
-  base::string16 ok_button_text =
-      GetTextFor(PermissionInfoBarDelegate::BUTTON_OK);
-  base::string16 cancel_button_text =
-      GetTextFor(PermissionInfoBarDelegate::BUTTON_CANCEL);
-  PermissionInfoBarDelegate* delegate = GetDelegate();
-  base::string16 message_text = delegate->GetMessageText();
-  base::string16 link_text = delegate->GetLinkText();
-
-  ScopedJavaLocalRef<jobject> java_bitmap;
-  if (delegate->GetIconId() == infobars::InfoBarDelegate::kNoIconID &&
-      !delegate->GetIcon().IsEmpty()) {
-    java_bitmap = gfx::ConvertToJavaBitmap(delegate->GetIcon().ToSkBitmap());
-  }
-
-  std::vector<int> content_settings{delegate->content_settings_types()};
-  return CreateRenderInfoBarHelper(
-      env, GetEnumeratedIconId(), GetTab()->GetJavaObject(), java_bitmap,
-      message_text, link_text, ok_button_text, cancel_button_text,
-      content_settings, delegate->ShouldShowPersistenceToggle());
-}
-
-void PermissionInfoBar::ProcessButton(int action) {
-  // Check if the delegate asked us to display a persistence toggle. If so,
-  // inform it of the toggle state.
-  PermissionInfoBarDelegate* delegate = GetDelegate();
-  if (delegate->ShouldShowPersistenceToggle()) {
-    delegate->set_persist(
-        IsSwitchOn(base::android::AttachCurrentThread(), GetJavaInfoBar()));
-  }
-
-  ConfirmInfoBar::ProcessButton(action);
-}
-
 ScopedJavaLocalRef<jobject> PermissionInfoBar::CreateRenderInfoBarHelper(
     JNIEnv* env,
     int enumerated_icon_id,
diff --git a/chrome/browser/ui/android/infobars/permission_infobar.h b/chrome/browser/ui/android/infobars/permission_infobar.h
index bb68091..3118eba 100644
--- a/chrome/browser/ui/android/infobars/permission_infobar.h
+++ b/chrome/browser/ui/android/infobars/permission_infobar.h
@@ -5,18 +5,15 @@
 #ifndef CHROME_BROWSER_UI_ANDROID_INFOBARS_PERMISSION_INFOBAR_H_
 #define CHROME_BROWSER_UI_ANDROID_INFOBARS_PERMISSION_INFOBAR_H_
 
+#include <vector>
+
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
-#include "chrome/browser/ui/android/infobars/confirm_infobar.h"
 
-class PermissionInfoBarDelegate;
-
-class PermissionInfoBar : public ConfirmInfoBar {
+// TODO(timloh): Rename GroupedPermissionInfoBar to PermissionInfoBar and move
+// these functions into it.
+class PermissionInfoBar {
  public:
-  explicit PermissionInfoBar(
-      std::unique_ptr<PermissionInfoBarDelegate> delegate);
-  ~PermissionInfoBar() override;
-
   static base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBarHelper(
       JNIEnv* env,
       int enumerated_icon_id,
@@ -32,16 +29,7 @@
   static bool IsSwitchOn(JNIEnv* env,
                          const base::android::JavaRef<jobject>& info_bar_obj);
 
- protected:
-  PermissionInfoBarDelegate* GetDelegate();
-
-  // InfoBarAndroid overrides.
-  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
-      JNIEnv* env) override;
-
  private:
-  void ProcessButton(int action) override;
-
   DISALLOW_COPY_AND_ASSIGN(PermissionInfoBar);
 };
 
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc
index 1bee91ba..30bae24 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc
@@ -64,8 +64,10 @@
                 GetRecentAndSuggestedAppsFromPlayStore)
           : nullptr;
 
-  if (app_instance == nullptr || query.empty())
+  if (app_instance == nullptr || query.empty()) {
+    ClearResults();
     return;
+  }
 
   app_instance->GetRecentAndSuggestedAppsFromPlayStore(
       base::UTF16ToUTF8(query), max_results_,
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index bc21033..9beb9fe 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -61,7 +61,6 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
-#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -70,7 +69,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
-#include "content/public/browser/media_session.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/url_constants.h"
@@ -520,13 +518,6 @@
   chromeos::system::InputDeviceSettings::Get()->ToggleTouchpad();
 }
 
-void ChromeShellDelegate::SuspendMediaSessions() {
-  for (TabContentsIterator it; !it.done(); it.Next()) {
-    content::MediaSession::Get(*it)->Suspend(
-        content::MediaSession::SuspendType::SYSTEM);
-  }
-}
-
 std::unique_ptr<keyboard::KeyboardUI> ChromeShellDelegate::CreateKeyboardUI() {
   return base::MakeUnique<ChromeKeyboardUI>(
       ProfileManager::GetActiveUserProfile());
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index bc9a615..51362261 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -57,7 +57,6 @@
   void SetTouchscreenEnabled(bool enabled,
                              ash::TouchscreenEnabledSource source) override;
   void ToggleTouchpad() override;
-  void SuspendMediaSessions() override;
   ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
 
   // content::NotificationObserver override:
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
index 7710135..99dc07d8 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -43,21 +43,6 @@
 // The time delta between clicks in which clicks to launch V2 apps are ignored.
 const int kClickSuppressionInMS = 1000;
 
-// Check if a browser can be used for activation. This addresses a special use
-// case in the M31 multi profile mode where a user activates a V1 app which only
-// exists yet on another users desktop, but they expect to get only their own
-// app items and not the ones from other users through activation.
-// TODO(skuhne): Remove this function and replace the call with
-// ChromeLauncherController::IsBrowserFromActiveUser(browser) once this
-// experiment goes away.
-bool CanBrowserBeUsedForDirectActivation(Browser* browser,
-                                         ChromeLauncherController* launcher) {
-  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
-          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_OFF)
-    return true;
-  return multi_user_util::IsProfileFromActiveUser(browser->profile());
-}
-
 }  // namespace
 
 // static
@@ -192,7 +177,8 @@
           app_id());
   for (size_t i = 0; i < content.size(); i++) {
     Browser* browser = chrome::FindBrowserWithWebContents(content[i]);
-    if (!browser || !IsBrowserFromActiveUser(browser))
+    if (!browser ||
+        !multi_user_util::IsProfileFromActiveUser(browser->profile()))
       continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     int index = tab_strip->GetIndexOfWebContents(content[i]);
@@ -221,7 +207,7 @@
     return items;
 
   for (auto* browser : *BrowserList::GetInstance()) {
-    if (!IsBrowserFromActiveUser(browser))
+    if (!multi_user_util::IsProfileFromActiveUser(browser->profile()))
       continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     for (int index = 0; index < tab_strip->count(); index++) {
@@ -256,7 +242,7 @@
            browser_list->begin_last_active();
        it != browser_list->end_last_active(); ++it) {
     Browser* browser = *it;
-    if (!CanBrowserBeUsedForDirectActivation(browser, controller))
+    if (!multi_user_util::IsProfileFromActiveUser(browser->profile()))
       continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     // We start to enumerate from the active index.
@@ -275,8 +261,7 @@
   for (BrowserList::const_iterator it = browser_list->begin();
        it != browser_list->end(); ++it) {
     Browser* browser = *it;
-    if (!CanBrowserBeUsedForDirectActivation(
-            browser, ChromeLauncherController::instance()))
+    if (!multi_user_util::IsProfileFromActiveUser(browser->profile()))
       continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     for (int index = 0; index < tab_strip->count(); index++) {
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index ea45b33..72ea1de33 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -293,6 +293,8 @@
   if (GetAppWindowForTask(task_id))
     return;
 
+  // TODO(msw): Set shelf item types earlier to avoid ShelfWindowWatcher races.
+  // (maybe use Widget::InitParams::mus_properties in cash too crbug.com/750334)
   window->SetProperty<int>(ash::kShelfItemTypeKey, ash::TYPE_APP);
   window->SetProperty(aura::client::kAppType,
                       static_cast<int>(ash::AppType::ARC_APP));
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 87b6297d..1b5f9d7 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -167,7 +167,8 @@
   // content which might change and as such change the application type.
   // The browser window may not exist in unit tests.
   if (!browser || !browser->window() || !browser->window()->GetNativeWindow() ||
-      !IsBrowserFromActiveUser(browser) || IsSettingsBrowser(browser)) {
+      !multi_user_util::IsProfileFromActiveUser(browser->profile()) ||
+      IsSettingsBrowser(browser)) {
     return;
   }
 
@@ -368,7 +369,7 @@
 bool BrowserShortcutLauncherItemController::IsBrowserRepresentedInBrowserList(
     Browser* browser) {
   // Only Ash desktop browser windows for the active user are represented.
-  if (!browser || !IsBrowserFromActiveUser(browser))
+  if (!browser || !multi_user_util::IsProfileFromActiveUser(browser->profile()))
     return false;
 
   // V1 App popup windows may have their own item.
@@ -389,7 +390,7 @@
   for (auto* browser : *BrowserList::GetInstance()) {
     // Make sure that the browser is from the current user, has a proper window,
     // and the window was already shown.
-    if (!IsBrowserFromActiveUser(browser))
+    if (!multi_user_util::IsProfileFromActiveUser(browser->profile()))
       continue;
     if (!browser->window()->GetNativeWindow()->IsVisible() &&
         !browser->window()->IsMinimized()) {
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
index 2928c00..26572e2 100644
--- a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
+#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -110,7 +111,7 @@
   // processed.
   Browser* browser = chrome::FindBrowserWithWebContents(contents);
   if (app_state == ChromeLauncherController::APP_STATE_REMOVED ||
-      (browser && IsBrowserFromActiveUser(browser)))
+      (browser && multi_user_util::IsProfileFromActiveUser(browser->profile())))
     launcher_controller_->UpdateAppState(contents, app_state);
 }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 3324976..96c63df 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -174,9 +174,7 @@
 }
 
 void ChromeLauncherControllerUserSwitchObserver::AddUser(Profile* profile) {
-  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
-    chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
+  chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
   controller_->AdditionalUserAddedToSession(profile->GetOriginalProfile());
 }
 
@@ -230,7 +228,7 @@
   // Create our v1/v2 application / browser monitors which will inform the
   // launcher of status changes.
   if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
+      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_ON) {
     // If running in separated destkop mode, we create the multi profile version
     // of status monitor.
     browser_status_monitor_.reset(new MultiProfileBrowserStatusMonitor(this));
@@ -504,22 +502,18 @@
 ash::ShelfAction ChromeLauncherController::ActivateWindowOrMinimizeIfActive(
     ui::BaseWindow* window,
     bool allow_minimize) {
-  // In separated desktop mode we might have to teleport a window back to the
-  // current user.
-  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
-    aura::Window* native_window = window->GetNativeWindow();
-    const AccountId& current_account_id =
-        multi_user_util::GetAccountIdFromProfile(profile());
-    chrome::MultiUserWindowManager* manager =
-        chrome::MultiUserWindowManager::GetInstance();
-    if (!manager->IsWindowOnDesktopOfUser(native_window, current_account_id)) {
-      ash::MultiProfileUMA::RecordTeleportAction(
-          ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_LAUNCHER);
-      manager->ShowWindowForUser(native_window, current_account_id);
-      window->Activate();
-      return ash::SHELF_ACTION_WINDOW_ACTIVATED;
-    }
+  // We might have to teleport a window back to the current user.
+  aura::Window* native_window = window->GetNativeWindow();
+  const AccountId& current_account_id =
+      multi_user_util::GetAccountIdFromProfile(profile());
+  chrome::MultiUserWindowManager* manager =
+      chrome::MultiUserWindowManager::GetInstance();
+  if (!manager->IsWindowOnDesktopOfUser(native_window, current_account_id)) {
+    ash::MultiProfileUMA::RecordTeleportAction(
+        ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_LAUNCHER);
+    manager->ShowWindowForUser(native_window, current_account_id);
+    window->Activate();
+    return ash::SHELF_ACTION_WINDOW_ACTIVATED;
   }
 
   const app_list::AppListPresenterImpl* app_list_presenter =
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.cc
index 0dc278f..ed4b6764 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.cc
@@ -15,15 +15,6 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 
-bool IsBrowserFromActiveUser(Browser* browser) {
-  // If running multi user mode with separate desktops, we have to check if the
-  // browser is from the active user.
-  if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
-    return true;
-  return multi_user_util::IsProfileFromActiveUser(browser->profile());
-}
-
 const extensions::Extension* GetExtensionForAppID(const std::string& app_id,
                                                   Profile* profile) {
   return extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h
index 2be8368..abb4b54 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h
@@ -11,11 +11,6 @@
 class Extension;
 }
 
-class Browser;
-
-// Returns true if |browser| is owned by the active user.
-bool IsBrowserFromActiveUser(Browser* browser);
-
 // Returns the extension identified by |app_id|.
 const extensions::Extension* GetExtensionForAppID(const std::string& app_id,
                                                   Profile* profile);
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
index a876bc9..6a142eb 100644
--- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
@@ -46,34 +46,28 @@
 
 ExtensionAppWindowLauncherController::ExtensionAppWindowLauncherController(
     ChromeLauncherController* owner)
-    : AppWindowLauncherController(owner) {
-  AppWindowRegistry* registry = AppWindowRegistry::Get(owner->profile());
-  registry_.insert(registry);
-  registry->AddObserver(this);
+    : AppWindowLauncherController(owner),
+      registry_(AppWindowRegistry::Get(owner->profile())) {
+  registry_->AddObserver(this);
 }
 
 ExtensionAppWindowLauncherController::~ExtensionAppWindowLauncherController() {
-  for (extensions::AppWindowRegistry* iter : registry_)
-    iter->RemoveObserver(this);
+  registry_->RemoveObserver(this);
 
   for (const auto& iter : window_to_shelf_id_map_)
     iter.first->RemoveObserver(this);
 }
 
-void ExtensionAppWindowLauncherController::AdditionalUserAddedToSession(
-    Profile* profile) {
-  // TODO(skuhne): This was added for the legacy side by side mode in M32. If
-  // this mode gets no longer pursued this special case can be removed.
-  if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_MIXED)
-    return;
-
-  AppWindowRegistry* registry = AppWindowRegistry::Get(profile);
-  if (registry_.find(registry) != registry_.end())
-    return;
-
-  registry->AddObserver(this);
-  registry_.insert(registry);
+AppWindowLauncherItemController*
+ExtensionAppWindowLauncherController::ControllerForWindow(
+    aura::Window* window) {
+  const auto window_iter = window_to_shelf_id_map_.find(window);
+  if (window_iter == window_to_shelf_id_map_.end())
+    return nullptr;
+  const auto controller_iter = app_controller_map_.find(window_iter->second);
+  if (controller_iter == app_controller_map_.end())
+    return nullptr;
+  return controller_iter->second;
 }
 
 void ExtensionAppWindowLauncherController::OnAppWindowAdded(
@@ -110,6 +104,8 @@
   DCHECK(!shelf_id.IsNull());
 
   window->SetProperty(ash::kShelfIDKey, new std::string(shelf_id.Serialize()));
+  // TODO(msw): Set shelf item types earlier to avoid ShelfWindowWatcher races.
+  // (maybe use Widget::InitParams::mus_properties in cash too crbug.com/750334)
   window->SetProperty<int>(
       ash::kShelfItemTypeKey,
       app_window->window_type_is_panel() ? ash::TYPE_APP_PANEL : ash::TYPE_APP);
@@ -184,17 +180,3 @@
     aura::Window* window) {
   return window_to_shelf_id_map_.find(window) != window_to_shelf_id_map_.end();
 }
-
-// Private Methods
-
-AppWindowLauncherItemController*
-ExtensionAppWindowLauncherController::ControllerForWindow(
-    aura::Window* window) {
-  const auto window_iter = window_to_shelf_id_map_.find(window);
-  if (window_iter == window_to_shelf_id_map_.end())
-    return nullptr;
-  const auto controller_iter = app_controller_map_.find(window_iter->second);
-  if (controller_iter == app_controller_map_.end())
-    return nullptr;
-  return controller_iter->second;
-}
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h
index d5f24a1..fc6f688 100644
--- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h
@@ -24,7 +24,6 @@
 }
 
 class ChromeLauncherController;
-class Profile;
 class ExtensionAppWindowLauncherItemController;
 
 // AppWindowLauncherController observes the app window registry and the
@@ -40,7 +39,6 @@
   ~ExtensionAppWindowLauncherController() override;
 
   // AppWindowLauncherController:
-  void AdditionalUserAddedToSession(Profile* profile) override;
   AppWindowLauncherItemController* ControllerForWindow(
       aura::Window* window) override;
 
@@ -67,10 +65,8 @@
   using AppControllerMap =
       std::map<ash::ShelfID, ExtensionAppWindowLauncherItemController*>;
 
-  // A set of unowned AppWindowRegistry pointers for loaded users.
-  // Note that this will only be used with multiple users in the side by side
-  // mode.
-  std::set<extensions::AppWindowRegistry*> registry_;
+  // The AppWindowRegistry for the active user (represented by |owner()|).
+  extensions::AppWindowRegistry* registry_;
 
   // Map of shelf id to controller.
   AppControllerMap app_controller_map_;
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc
index b3b55d1f..aa65fb8 100644
--- a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc
@@ -59,8 +59,14 @@
     if (multi_user_util::IsProfileFromActiveUser(profile) &&
         !IsRegisteredApp(app_window->GetNativeWindow()) &&
         (app_window->GetBaseWindow()->IsMinimized() ||
-         app_window->GetNativeWindow()->IsVisible()))
+         app_window->GetNativeWindow()->IsVisible())) {
+      if (app_window->window_type_is_panel()) {
+        // Panels are not registered; show by restoring the shelf item type.
+        app_window->GetNativeWindow()->SetProperty<int>(ash::kShelfItemTypeKey,
+                                                        ash::TYPE_APP_PANEL);
+      }
       RegisterApp(app_window);
+    }
   }
 }
 
diff --git a/chrome/browser/ui/ash/media_client.cc b/chrome/browser/ui/ash/media_client.cc
index 8cc61b1f..5af3991d 100644
--- a/chrome/browser/ui/ash/media_client.cc
+++ b/chrome/browser/ui/ash/media_client.cc
@@ -18,8 +18,10 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/browser/media_session.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/service_manager_connection.h"
@@ -179,6 +181,13 @@
   media_controller_->NotifyCaptureState(std::move(state));
 }
 
+void MediaClient::SuspendMediaSessions() {
+  for (TabContentsIterator it; !it.done(); it.Next()) {
+    content::MediaSession::Get(*it)->Suspend(
+        content::MediaSession::SuspendType::SYSTEM);
+  }
+}
+
 void MediaClient::OnRequestUpdate(int render_process_id,
                                   int render_frame_id,
                                   content::MediaStreamType stream_type,
diff --git a/chrome/browser/ui/ash/media_client.h b/chrome/browser/ui/ash/media_client.h
index cfcc72db..c566745 100644
--- a/chrome/browser/ui/ash/media_client.h
+++ b/chrome/browser/ui/ash/media_client.h
@@ -17,11 +17,12 @@
   MediaClient();
   ~MediaClient() override;
 
-  // ash::MediaClient:
+  // ash::mojom::MediaClient:
   void HandleMediaNextTrack() override;
   void HandleMediaPlayPause() override;
   void HandleMediaPrevTrack() override;
   void RequestCaptureState() override;
+  void SuspendMediaSessions() override;
 
   // MediaCaptureDevicesDispatcher::Observer:
   void OnRequestUpdate(int render_process_id,
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc
index 684dd9b..593d6dc4 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc
@@ -75,8 +75,8 @@
   multi_user_window_manager_ =
       new chrome::MultiUserWindowManagerChromeOS(AccountId::FromUserEmail("A"));
   multi_user_window_manager_->Init();
-  chrome::MultiUserWindowManager::SetInstanceForTest(multi_user_window_manager_,
-        chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
+  chrome::MultiUserWindowManager::SetInstanceForTest(
+      multi_user_window_manager_);
   EXPECT_TRUE(multi_user_window_manager_);
 }
 
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
index 7c048fc0..9f4ac11c 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
@@ -4,8 +4,9 @@
 
 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
 
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
 #include "ash/system/system_notifier.h"
-#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notifier_settings.h"
@@ -21,7 +22,8 @@
 
 bool MultiUserNotificationBlockerChromeOS::ShouldShowNotification(
     const message_center::Notification& notification) const {
-  if (!IsActive())
+  if (!ash::Shell::HasInstance() ||
+      !ash::Shell::Get()->shell_delegate()->IsMultiProfilesEnabled())
     return true;
 
   if (ash::system_notifier::IsAshSystemNotifier(notification.notifier_id()))
@@ -51,8 +53,3 @@
   }
   NotifyBlockingStateChanged();
 }
-
-bool MultiUserNotificationBlockerChromeOS::IsActive() const {
-  return chrome::MultiUserWindowManager::GetMultiProfileMode() ==
-      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED;
-}
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h
index 1849b0c..7456c4a2 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h
@@ -33,9 +33,6 @@
       const message_center::Notification& notification) const override;
 
  private:
-  // Returns true if this blocker is actively working.
-  bool IsActive() const;
-
   AccountId active_account_id_;
   std::map<AccountId, bool> quiet_modes_;
 
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
index 76fe8bcd..9a39c6b 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -94,7 +94,7 @@
   void SwitchActiveUser(const std::string& name) {
     const AccountId account_id(AccountId::FromUserEmail(name));
     if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
-        chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
+        chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_ON) {
       static_cast<chrome::MultiUserWindowManagerChromeOS*>(
           chrome::MultiUserWindowManager::GetInstance())
           ->ActiveUserChanged(fake_user_manager_->FindUser(account_id));
@@ -157,7 +157,7 @@
 };
 
 TEST_F(MultiUserNotificationBlockerChromeOSTest, Basic) {
-  ASSERT_EQ(chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED,
+  ASSERT_EQ(chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_ON,
             chrome::MultiUserWindowManager::GetMultiProfileMode());
 
   message_center::NotifierId notifier_id(
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_util.cc b/chrome/browser/ui/ash/multi_user/multi_user_util.cc
index b00fb43..c225bad 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_util.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_util.cc
@@ -46,8 +46,12 @@
 }
 
 bool IsProfileFromActiveUser(Profile* profile) {
-  return GetAccountIdFromProfile(profile) ==
-         user_manager::UserManager::Get()->GetActiveUser()->GetAccountId();
+  // There may be no active user in tests.
+  const user_manager::User* active_user =
+      user_manager::UserManager::Get()->GetActiveUser();
+  if (!active_user)
+    return true;
+  return GetAccountIdFromProfile(profile) == active_user->GetAccountId();
 }
 
 const AccountId GetCurrentAccountId() {
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
index cfc9964..30adc76 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
@@ -41,21 +41,13 @@
   // TODO(crbug.com/557406): Enable this component in Mash.
   if (!ash_util::IsRunningInMash() &&
       ash::Shell::Get()->shell_delegate()->IsMultiProfilesEnabled()) {
-    if (!g_instance) {
-      MultiUserWindowManagerChromeOS* manager =
-          new MultiUserWindowManagerChromeOS(user_manager::UserManager::Get()
-                                                 ->GetActiveUser()
-                                                 ->GetAccountId());
-      g_instance = manager;
-      manager->Init();
-      multi_user_mode_ = MULTI_PROFILE_MODE_SEPARATED;
-      mode = ash::MultiProfileUMA::SESSION_SEPARATE_DESKTOP_MODE;
-    } else {
-      // The side by side mode is using the Single user window manager since all
-      // windows are unmanaged side by side.
-      multi_user_mode_ = MULTI_PROFILE_MODE_MIXED;
-      mode = ash::MultiProfileUMA::SESSION_SIDE_BY_SIDE_MODE;
-    }
+    MultiUserWindowManagerChromeOS* manager =
+        new MultiUserWindowManagerChromeOS(
+            user_manager::UserManager::Get()->GetActiveUser()->GetAccountId());
+    g_instance = manager;
+    manager->Init();
+    multi_user_mode_ = MULTI_PROFILE_MODE_ON;
+    mode = ash::MultiProfileUMA::SESSION_SEPARATE_DESKTOP_MODE;
   }
   ash::MultiProfileUMA::RecordSessionMode(mode);
 
@@ -75,7 +67,7 @@
 // satic
 bool MultiUserWindowManager::ShouldShowAvatar(aura::Window* window) {
   // Note: In case of the M-31 mode the window manager won't exist.
-  if (GetMultiProfileMode() == MULTI_PROFILE_MODE_SEPARATED) {
+  if (GetMultiProfileMode() == MULTI_PROFILE_MODE_ON) {
     // If the window is shown on a different desktop than the user, it should
     // have the avatar icon
     MultiUserWindowManager* instance = GetInstance();
@@ -94,12 +86,11 @@
 }
 
 void MultiUserWindowManager::SetInstanceForTest(
-    MultiUserWindowManager* instance,
-    MultiProfileMode mode) {
+    MultiUserWindowManager* instance) {
   if (g_instance)
     DeleteInstance();
   g_instance = instance;
-  multi_user_mode_ = mode;
+  multi_user_mode_ = MULTI_PROFILE_MODE_ON;
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h
index 79ae0a5..c4bdc49c2 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h
@@ -60,8 +60,7 @@
   enum MultiProfileMode {
     MULTI_PROFILE_MODE_UNINITIALIZED,  // Not initialized yet.
     MULTI_PROFILE_MODE_OFF,            // Single user mode.
-    MULTI_PROFILE_MODE_SEPARATED,      // Each user has their own desktop.
-    MULTI_PROFILE_MODE_MIXED           // All users mix windows freely.
+    MULTI_PROFILE_MODE_ON,             // Each user has their own desktop.
   };
 
   // Creates an instance of the MultiUserWindowManager.
@@ -86,10 +85,8 @@
   // Removes the instance.
   static void DeleteInstance();
 
-  // A function to set an |instance| of a created MultiUserWinwdowManager object
-  // with a given |mode| for test purposes.
-  static void SetInstanceForTest(MultiUserWindowManager* instance,
-                                 MultiProfileMode mode);
+  // Sets the singleton instance to |instance| and enables multi-user-mode.
+  static void SetInstanceForTest(MultiUserWindowManager* instance);
 
   // Assigns an owner to a passed window. Note that this window's parent should
   // be a direct child of the root window.
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index 8fe27cd..28a27ae 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -529,8 +529,8 @@
   WindowToEntryMap::iterator it = window_to_entry_.find(window);
   it->second->set_show_for_user(account_id);
 
-  // Show avatar icon on the teleported window for separated mode.
-  if (GetMultiProfileMode() == MULTI_PROFILE_MODE_SEPARATED) {
+  // Show avatar icon on the teleported window.
+  if (GetMultiProfileMode() == MULTI_PROFILE_MODE_ON) {
     // Tests could either not have a UserManager or the UserManager does not
     // know the window owner.
     const user_manager::User* const window_owner =
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index 7f327df..a54fe2db 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -329,8 +329,8 @@
   multi_user_window_manager_->Init();
   multi_user_window_manager_->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED);
-  chrome::MultiUserWindowManager::SetInstanceForTest(multi_user_window_manager_,
-        chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
+  chrome::MultiUserWindowManager::SetInstanceForTest(
+      multi_user_window_manager_);
   EXPECT_TRUE(multi_user_window_manager_);
   chromeos::WallpaperManager::Initialize();
 }
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc
index c4d1227..e5653662 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc
@@ -21,8 +21,7 @@
       current_account_id_(desktop_owner) {
   // Register this object with the system (which will take ownership). It will
   // be deleted by ChromeLauncherController::~ChromeLauncherController().
-  chrome::MultiUserWindowManager::SetInstanceForTest(
-      this, chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
+  chrome::MultiUserWindowManager::SetInstanceForTest(this);
 }
 
 TestMultiUserWindowManager::~TestMultiUserWindowManager() {
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
index ee39a321..7f50e97 100644
--- a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
+#include "ui/app_list/presenter/app_list.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/layer_tree_owner.h"
 #include "ui/display/display.h"
@@ -112,7 +113,7 @@
       animation_step_(ANIMATION_STEP_HIDE_OLD_USER),
       screen_cover_(GetScreenCover(NULL)),
       windows_by_account_id_() {
-  ash::Shell::Get()->DismissAppList();
+  ash::Shell::Get()->app_list()->Dismiss();
   BuildUserToWindowsListMap();
   AdvanceUserTransitionAnimation();
 
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 960a3cb..7f5410b 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -50,6 +50,7 @@
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/download/download_core_service.h"
 #include "chrome/browser/download/download_core_service_factory.h"
+#include "chrome/browser/extensions/api/tab_capture/offscreen_tab.h"
 #include "chrome/browser/extensions/api/tabs/tabs_event_router.h"
 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
 #include "chrome/browser/extensions/browser_extension_window_controller.h"
@@ -552,9 +553,14 @@
   // This cannot be fixed in ProfileDestroyer::DestroyProfileWhenAppropriate(),
   // because the ProfileManager needs to be able to destroy all profiles when
   // it is destroyed. See crbug.com/527035
+  //
+  // A profile used to render an offscreen tab should not be destroyed while
+  // that tab is still alive.  The offscreen tab is not associated with a
+  // browser (similar to the user manager window case). See crbug.com/664351
   if (profile_->IsOffTheRecord() &&
       !BrowserList::IsIncognitoSessionActiveForProfile(profile_) &&
-      !profile_->GetOriginalProfile()->IsSystemProfile()) {
+      !profile_->GetOriginalProfile()->IsSystemProfile() &&
+      !extensions::OffscreenTabsOwner::IsOffscreenProfile(profile_)) {
     if (profile_->IsGuestSession()) {
 // ChromeOS handles guest data independently.
 #if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index d971fe47..4993c7e 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -82,7 +82,9 @@
 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#include "chrome/browser/feature_engagement/bookmark/bookmark_tracker.h"
+#include "chrome/browser/feature_engagement/bookmark/bookmark_tracker_factory.h"
 #include "chrome/browser/feature_engagement/new_tab/new_tab_tracker.h"
 #include "chrome/browser/feature_engagement/new_tab/new_tab_tracker_factory.h"
 #endif
@@ -327,7 +329,7 @@
       CloseWindow(browser_);
       break;
     case IDC_NEW_TAB:
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
       // This is not in NewTab() to avoid tracking programmatic creation of new
       // tabs by extensions.
       feature_engagement::NewTabTrackerFactory::GetInstance()
@@ -412,9 +414,19 @@
       SavePage(browser_);
       break;
     case IDC_BOOKMARK_PAGE:
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+      feature_engagement::BookmarkTrackerFactory::GetInstance()
+          ->GetForProfile(profile())
+          ->OnBookmarkAdded();
+#endif
       BookmarkCurrentPageAllowingExtensionOverrides(browser_);
       break;
     case IDC_BOOKMARK_ALL_TABS:
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+      feature_engagement::BookmarkTrackerFactory::GetInstance()
+          ->GetForProfile(profile())
+          ->OnBookmarkAdded();
+#endif
       BookmarkAllTabs(browser_);
       break;
     case IDC_VIEW_SOURCE:
diff --git a/chrome/browser/ui/browser_finder_chromeos_unittest.cc b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
index 01d26591..48c4de3b 100644
--- a/chrome/browser/ui/browser_finder_chromeos_unittest.cc
+++ b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
@@ -52,8 +52,7 @@
           new chrome::MultiUserWindowManagerChromeOS(test_account_id1_);
       multi_user_window_manager_->Init();
       chrome::MultiUserWindowManager::SetInstanceForTest(
-          multi_user_window_manager_,
-          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
+          multi_user_window_manager_);
     }
     return multi_user_window_manager_;
   }
diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc
index 6052d7f..7834d4f 100644
--- a/chrome/browser/ui/browser_instant_controller.cc
+++ b/chrome/browser/ui/browser_instant_controller.cc
@@ -10,6 +10,8 @@
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/search/search_model.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
@@ -80,17 +82,21 @@
       instant_(this) {
   browser_->search_model()->AddObserver(this);
 
-  InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(profile());
-  instant_service->AddObserver(this);
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile());
+  // TemplateURLService can be null in tests.
+  if (template_url_service) {
+    search_engine_base_url_tracker_ =
+        base::MakeUnique<SearchEngineBaseURLTracker>(
+            template_url_service,
+            base::MakeUnique<UIThreadSearchTermsData>(profile()),
+            base::Bind(&BrowserInstantController::OnSearchEngineBaseURLChanged,
+                       base::Unretained(this)));
+  }
 }
 
 BrowserInstantController::~BrowserInstantController() {
   browser_->search_model()->RemoveObserver(this);
-
-  InstantService* instant_service =
-      InstantServiceFactory::GetForProfile(profile());
-  instant_service->RemoveObserver(this);
 }
 
 Profile* BrowserInstantController::profile() const {
@@ -110,8 +116,8 @@
   instant_.SearchModeChanged(old_origin, new_origin);
 }
 
-void BrowserInstantController::DefaultSearchProviderChanged(
-    bool google_base_url_domain_changed) {
+void BrowserInstantController::OnSearchEngineBaseURLChanged(
+    SearchEngineBaseURLTracker::ChangeReason change_reason) {
   InstantService* instant_service =
       InstantServiceFactory::GetForProfile(profile());
   if (!instant_service)
@@ -131,6 +137,9 @@
     if (!instant_service->IsInstantProcess(rph->GetID()))
       continue;
 
+    bool google_base_url_domain_changed =
+        change_reason ==
+        SearchEngineBaseURLTracker::ChangeReason::GOOGLE_BASE_URL;
     SearchModel* model = SearchTabHelper::FromWebContents(contents)->model();
     if (google_base_url_domain_changed &&
         model->origin() == SearchModel::Origin::NTP) {
diff --git a/chrome/browser/ui/browser_instant_controller.h b/chrome/browser/ui/browser_instant_controller.h
index e5bc27f..8d33256 100644
--- a/chrome/browser/ui/browser_instant_controller.h
+++ b/chrome/browser/ui/browser_instant_controller.h
@@ -5,9 +5,11 @@
 #ifndef CHROME_BROWSER_UI_BROWSER_INSTANT_CONTROLLER_H_
 #define CHROME_BROWSER_UI_BROWSER_INSTANT_CONTROLLER_H_
 
+#include <memory>
+
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "chrome/browser/search/instant_service_observer.h"
+#include "chrome/browser/search/search_engine_base_url_tracker.h"
 #include "chrome/browser/ui/search/instant_controller.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
 
@@ -18,8 +20,7 @@
 class WebContents;
 }
 
-class BrowserInstantController : public SearchModelObserver,
-                                 public InstantServiceObserver {
+class BrowserInstantController : public SearchModelObserver {
  public:
   explicit BrowserInstantController(Browser* browser);
   ~BrowserInstantController() override;
@@ -40,14 +41,15 @@
   void ModelChanged(SearchModel::Origin old_origin,
                     SearchModel::Origin new_origin) override;
 
-  // InstantServiceObserver:
-  void DefaultSearchProviderChanged(
-      bool google_base_url_domain_changed) override;
+  void OnSearchEngineBaseURLChanged(
+      SearchEngineBaseURLTracker::ChangeReason change_reason);
 
   Browser* const browser_;
 
   InstantController instant_;
 
+  std::unique_ptr<SearchEngineBaseURLTracker> search_engine_base_url_tracker_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserInstantController);
 };
 
diff --git a/chrome/browser/ui/browser_instant_controller_unittest.cc b/chrome/browser/ui/browser_instant_controller_unittest.cc
index 7d87d7a..d3da648 100644
--- a/chrome/browser/ui/browser_instant_controller_unittest.cc
+++ b/chrome/browser/ui/browser_instant_controller_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/run_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/search/instant_service.h"
-#include "chrome/browser/search/instant_service_observer.h"
 #include "chrome/browser/search/instant_unittest_base.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/browser_instant_controller.h"
@@ -209,22 +208,6 @@
   }
 }
 
-TEST_F(BrowserInstantControllerTest, BrowserWindowLifecycle) {
-  std::unique_ptr<BrowserWindow> window(CreateBrowserWindow());
-  Browser::CreateParams params(profile(), true);
-  params.window = window.get();
-  std::unique_ptr<Browser> browser(new Browser(params));
-  InstantServiceObserver* bic;
-  bic = browser->instant_controller();
-  EXPECT_TRUE(IsInstantServiceObserver(bic))
-    << "New BrowserInstantController should register as InstantServiceObserver";
-
-  browser.reset(NULL);
-  window.reset(NULL);
-  EXPECT_FALSE(IsInstantServiceObserver(bic))
-    << "New BrowserInstantController should register as InstantServiceObserver";
-}
-
 }  // namespace
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm b/chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm
index e08d57f6..8f122c2 100644
--- a/chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm
+++ b/chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm
@@ -11,6 +11,7 @@
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #include "ui/views/bubble/bubble_dialog_delegate.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -70,7 +71,7 @@
   BrowserWindowController* window_controller =
       [BrowserWindowController browserWindowControllerForWindow:window];
   LocationBarViewMac* location_bar = [window_controller locationBarBridge];
-  return location_bar ? location_bar->GetPageInfoDecoration() : nullptr;
+  return location_bar ? location_bar->page_info_decoration() : nullptr;
 }
 
 void KeepBubbleAnchored(views::BubbleDialogDelegateView* bubble,
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
index 5223f60..45adedf4 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller_unittest.mm
@@ -102,7 +102,8 @@
   base::scoped_nsobject<DownloadShelfController> shelf_;
 };
 
-TEST_F(DownloadItemControllerTest, ShelfNotifiedOfOpenedDownload) {
+// TODO(crbug.com/762405): Disabled because it's flaky (crashing).
+TEST_F(DownloadItemControllerTest, DISABLED_ShelfNotifiedOfOpenedDownload) {
   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
   [[(id)shelf_ expect] downloadWasOpened:[OCMArg any]];
   download_item_->NotifyObserversDownloadOpened();
@@ -114,7 +115,8 @@
   download_item_.reset();
 }
 
-TEST_F(DownloadItemControllerTest, NormalDownload) {
+// TODO(crbug.com/762405): Disabled because it's flaky (crashing).
+TEST_F(DownloadItemControllerTest, DISABLED_NormalDownload) {
   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
 
   [item verifyProgressViewIsVisible:true];
@@ -132,7 +134,8 @@
   [item verifyDangerousDownloadPromptIsVisible:true];
 }
 
-TEST_F(DownloadItemControllerTest, NormalDownloadBecomesDangerous) {
+// TODO(crbug.com/762405): Disabled because it's flaky (crashing).
+TEST_F(DownloadItemControllerTest, DISABLED_NormalDownloadBecomesDangerous) {
   base::scoped_nsobject<DownloadItemController> item(CreateItemController());
 
   [item verifyProgressViewIsVisible:true];
diff --git a/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm b/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm
index 6f26067f..fd8f3e7 100644
--- a/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/external_protocol_dialog_cocoa.mm
@@ -10,6 +10,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/tab_contents/tab_util.h"
+#import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -54,16 +55,17 @@
   NSButton* allowButton = [alert_
       addButtonWithTitle:l10n_util::GetNSStringFWithFixup(
                    IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT, appName)];
-  [allowButton setKeyEquivalent:@""];  // disallow as default
+  [allowButton setKeyEquivalent:kKeyEquivalentReturn];  // set as default
   [alert_ addButtonWithTitle:
       l10n_util::GetNSStringWithFixup(
                    IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT)];
 
   [alert_ setShowsSuppressionButton:YES];
   [[alert_ suppressionButton]
-      setTitle:l10n_util::GetNSStringFWithFixup(
-                   IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT, appName)];
+      setTitle:l10n_util::GetNSStringWithFixup(
+                   IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)];
 
+  [[alert_ window] setInitialFirstResponder:allowButton];
   [alert_ beginSheetModalForWindow:nil  // nil here makes it app-modal
                      modalDelegate:self
                     didEndSelector:@selector(alertEnded:returnCode:contextInfo:)
@@ -100,13 +102,14 @@
   if (web_contents) {
     Profile* profile =
         Profile::FromBrowserContext(web_contents->GetBrowserContext());
-    bool isChecked = [[alert_ suppressionButton] state] == NSOnState;
+    bool isChecked = [[alert_ suppressionButton] state] == NSOnState &&
+                     blockState == ExternalProtocolHandler::DONT_BLOCK;
     // Set the "don't warn me again" info.
-    if (isChecked)
+    if (isChecked) {
       ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState,
                                              profile);
+    }
 
-    ExternalProtocolHandler::RecordCheckboxStateMetrics(isChecked);
     ExternalProtocolHandler::RecordHandleStateMetrics(isChecked, blockState);
 
     if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
diff --git a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h
index 474952e..bea7747 100644
--- a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h
+++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h
@@ -60,6 +60,11 @@
   // Whether or not we are in fullscreen mode.
   BOOL inFullscreenMode_;
 
+  // Whether the menu bar is currently locked in the visible position (while
+  // the mouse is over the toolbar). AppKit counts lock/unlock calls, so it's
+  // important that locks/unlocks are balanced.
+  BOOL menubarLocked_;
+
   // Updates the fullscreen toolbar layout for changes in the menubar. This
   // object is only set when the browser is in fullscreen mode.
   base::scoped_nsobject<FullscreenMenubarTracker> menubarTracker_;
diff --git a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm
index 9859fc6..e832ae31 100644
--- a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm
@@ -17,13 +17,28 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 
+@interface NSMenu (PrivateAPI)
+- (void)_lockMenuPosition;
+- (void)_unlockMenuPosition;
+@end
+
 namespace {
 
 // Visibility fractions for the menubar and toolbar.
 const CGFloat kHideFraction = 0.0;
 const CGFloat kShowFraction = 1.0;
 
-}  // end namespace
+void LockMenu() {
+  if ([NSMenu instancesRespondToSelector:@selector(_lockMenuPosition)])
+    [[NSApp mainMenu] _lockMenuPosition];
+}
+
+void UnlockMenu() {
+  if ([NSMenu instancesRespondToSelector:@selector(_unlockMenuPosition)])
+    [[NSApp mainMenu] _unlockMenuPosition];
+}
+
+}  // namespace
 
 @implementation FullscreenToolbarController
 
@@ -169,6 +184,16 @@
 }
 
 - (void)updateToolbarLayout {
+  if ([mouseTracker_ mouseInsideTrackingArea]) {
+    if (!menubarLocked_)
+      LockMenu();
+    menubarLocked_ = YES;
+  } else {
+    if (menubarLocked_)
+      UnlockMenu();
+    menubarLocked_ = NO;
+  }
+
   [browserController_ layoutSubviews];
   animationController_->ToolbarDidUpdate();
   [mouseTracker_ updateTrackingArea];
diff --git a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_unittest.mm b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_unittest.mm
index 152b6185..424d038 100644
--- a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_unittest.mm
@@ -85,6 +85,11 @@
 
 @end
 
+@interface NSMenu (PrivateAPI)
+- (void)_lockMenuPosition;
+- (void)_unlockMenuPosition;
+@end
+
 namespace {
 
 class FullscreenToolbarControllerTest : public testing::Test {
@@ -297,4 +302,11 @@
   [locks releaseToolbarVisibilityForOwner:owner.get() withAnimation:NO];
 }
 
+// Verify that private methods used by FullscreenToolbarController still exist.
+TEST_F(FullscreenToolbarControllerTest, PrivateAPIs) {
+  EXPECT_TRUE([NSMenu instancesRespondToSelector:@selector(_lockMenuPosition)]);
+  EXPECT_TRUE(
+      [NSMenu instancesRespondToSelector:@selector(_unlockMenuPosition)]);
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
index da0b9d2e..44a1738 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
@@ -298,8 +298,18 @@
 
   // Under MD, dialogs have no arrow and anchor to corner of the location bar
   // frame, not a specific point within it. See http://crbug.com/566115.
+
+  // Inset the omnibox frame by 1 DIP. This is done because the border stroke of
+  // the omnibox is inside its frame, but bubbles have no border stroke. The
+  // bubble border is part of the shadow drawn by the window server; outside the
+  // bubble frame. Here, only the X direction is inset. In the Y direction,
+  // that 1 DIP "gap" must be kept, otherwise the "border" stroke from the
+  // window server shadow would be drawn inside the omnibox.
+  constexpr CGFloat kStrokeInsetX = 1;
+  constexpr CGFloat kStrokeInsetY = 0;
+  const NSRect frame = NSInsetRect([self bounds], kStrokeInsetX, kStrokeInsetY);
+
   BOOL isLeftDecoration = [[self cell] isLeftDecoration:decoration];
-  const NSRect frame = [self bounds];
   NSPoint point = NSMakePoint(isLeftDecoration ? NSMinX(frame) : NSMaxX(frame),
                               NSMaxY(frame));
   return [self convertPoint:point toView:nil];
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
index d672438..9afe74d 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
@@ -10,8 +10,7 @@
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
-#import "chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
 #import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
@@ -108,21 +107,13 @@
   // TODO(shess): This really wants a |LocationBarViewMac|, but only a
   // few methods reference it, so this works well enough.  But
   // something better would be nice.
-  LocationIconDecoration location_icon_decoration(NULL);
-  location_icon_decoration.SetVisible(true);
-  location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
-  [cell addLeadingDecoration:&location_icon_decoration];
-  EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
-            LocationBarDecoration::kOmittedWidth);
-
-  SecurityStateBubbleDecoration security_state_bubble_decoration(
-      &location_icon_decoration, nullptr);
-  security_state_bubble_decoration.SetVisible(true);
-  security_state_bubble_decoration.SetImage(
+  PageInfoBubbleDecoration page_info_bubble_decoration(nullptr);
+  page_info_bubble_decoration.SetVisible(true);
+  page_info_bubble_decoration.SetImage(
       [NSImage imageNamed:@"NSApplicationIcon"]);
-  security_state_bubble_decoration.SetLabel(@"Application");
-  [cell addLeadingDecoration:&security_state_bubble_decoration];
-  EXPECT_NE(security_state_bubble_decoration.GetWidthForSpace(kVeryWide),
+  page_info_bubble_decoration.SetLabel(@"Application");
+  [cell addLeadingDecoration:&page_info_bubble_decoration];
+  EXPECT_NE(page_info_bubble_decoration.GetWidthForSpace(kVeryWide),
             LocationBarDecoration::kOmittedWidth);
 
   StarDecoration star_decoration(NULL);
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
index d41c19f..3939d11 100644
--- a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.h
@@ -47,6 +47,9 @@
   // Returns the text color when the theme is dark.
   virtual NSColor* GetDarkModeTextColor();
 
+  // Returns false if the |label_| is nil or empty.
+  bool HasLabel() const;
+
   // Image drawn in the left side of the bubble.
   base::scoped_nsobject<NSImage> image_;
 
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
index 68a9010..edfc6df 100644
--- a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
@@ -23,6 +23,8 @@
 // Padding between the icon/label and bubble edges.
 const CGFloat kBubblePadding = 7.0;
 
+const CGFloat kImageOnlyPadding = 10.0;
+
 // Padding between the icon and label.
 const CGFloat kIconLabelPadding = 4.0;
 
@@ -32,8 +34,8 @@
 // Inset for the background frame.
 const CGFloat kBackgroundFrameYInset = 2.0;
 
-// Left margin for the background frame.
-const CGFloat kBackgroundFrameLeftMargin = 1.0;
+// Margin for the background frame.
+const CGFloat kBackgroundFrameXMargin = 1.0;
 
 }  // namespace
 
@@ -48,12 +50,13 @@
 
 CGFloat BubbleDecoration::GetWidthForImageAndLabel(NSImage* image,
                                                    NSString* label) {
-  if (!image && !label)
+  bool has_label = label && label.length;
+  if (!image && !has_label)
     return kOmittedWidth;
 
   const CGFloat image_width = image ? [image size].width : 0.0;
-  if (!label)
-    return kBubblePadding + image_width;
+  if (!has_label)
+    return kImageOnlyPadding + image_width;
 
   // The bubble needs to take up an integral number of pixels.
   // Generally -sizeWithAttributes: seems to overestimate rather than
@@ -100,13 +103,13 @@
 
 NSRect BubbleDecoration::GetBackgroundFrame(NSRect frame) {
   NSRect background_frame = NSInsetRect(frame, 0.0, kBackgroundFrameYInset);
-  const CGFloat divider_padding = DividerPadding();
+  const CGFloat divider_padding = HasLabel() ? DividerPadding() : 0.0;
   if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) {
-    background_frame.origin.x += divider_padding;
-    background_frame.size.width -= divider_padding + kBackgroundFrameLeftMargin;
+    background_frame.origin.x += divider_padding - kBackgroundFrameXMargin;
+    background_frame.size.width -= divider_padding + kBackgroundFrameXMargin;
   } else {
-    background_frame.origin.x += kBackgroundFrameLeftMargin;
-    background_frame.size.width -= divider_padding;
+    background_frame.origin.x += kBackgroundFrameXMargin;
+    background_frame.size.width -= divider_padding + kBackgroundFrameXMargin;
   }
   return background_frame;
 }
@@ -131,16 +134,16 @@
       text_left_offset = NSMaxX(image_rect) + kIconLabelPadding;
   }
 
-  // Draw the divider.
-  DrawDivider(control_view, decoration_frame, 1.0);
+  if (HasLabel()) {
+    // Draw the divider.
+    DrawDivider(control_view, decoration_frame, 1.0);
 
-  // Set the text color.
-  bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
-  NSColor* text_color =
-      in_dark_mode ? GetDarkModeTextColor() : GetBackgroundBorderColor();
-  SetTextColor(text_color);
+    // Set the text color.
+    bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
+    NSColor* text_color =
+        in_dark_mode ? GetDarkModeTextColor() : GetBackgroundBorderColor();
+    SetTextColor(text_color);
 
-  if (label_) {
     NSRect text_rect = frame;
     text_rect.origin.x = text_left_offset;
     text_rect.size.width = text_right_offset - text_left_offset;
@@ -188,3 +191,7 @@
 void BubbleDecoration::SetRetinaBaselineOffset(CGFloat offset) {
   retina_baseline_offset_ = offset;
 }
+
+bool BubbleDecoration::HasLabel() const {
+  return label_ && [label_ length];
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
index 970c579..a7d9c76d 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
@@ -26,14 +26,13 @@
 class ContentSettingDecoration;
 class KeywordHintDecoration;
 class LocationBarDecoration;
-class LocationIconDecoration;
 class ManagePasswordsDecoration;
 class Profile;
 class SaveCreditCardDecoration;
 class SelectedKeywordDecoration;
 class StarDecoration;
 class TranslateDecoration;
-class SecurityStateBubbleDecoration;
+class PageInfoBubbleDecoration;
 class ZoomDecoration;
 class ZoomDecorationTest;
 
@@ -41,6 +40,16 @@
 class LocationBarViewMacTest;
 }
 
+// Enumeration of the type of verbose that is displayed on the page info
+// decoration.
+enum class PageInfoVerboseType {
+  kNone = 0,
+  kSecurity,
+  kEVCert,
+  kChrome,
+  kExtension
+};
+
 // A C++ bridge class that represents the location bar UI element to
 // the portable code.  Wires up an OmniboxViewMac instance to
 // the location bar text field, which handles most of the work.
@@ -110,7 +119,7 @@
   // Get the point in window coordinates for the page info bubble anchor.
   NSPoint GetPageInfoBubblePoint() const;
 
-  // Get the point in window coordinates in the security icon at which infobar
+  // Get the point in window coordinates in the page info icon at which infobar
   // arrows should point.
   NSPoint GetInfoBarAnchorPoint() const;
 
@@ -154,19 +163,11 @@
   const ToolbarModel* GetToolbarModel() const override;
   content::WebContents* GetWebContents() override;
 
-  bool ShouldShowEVBubble() const;
+  PageInfoVerboseType GetPageInfoVerboseType() const;
 
-  // Returns true if the URL is an extension URL and the extension bubble should
-  // be shown.
-  bool ShouldShowExtensionBubble() const;
-
-  // Returns true if the the URL is a chrome:// URL and the Chrome bubble should
-  // be shown.
-  bool ShouldShowChromeBubble() const;
-
-  // Returns true if the security state decoration should be displayed. The
-  // security state should only be shown for valid and invalid HTTPS states.
-  bool ShouldShowSecurityState() const;
+  // Returns true if the page info decoration should display security verbose.
+  // The verbose should only be shown for valid and invalid HTTPS states.
+  bool HasSecurityVerboseText() const;
 
   NSImage* GetKeywordImage(const base::string16& keyword);
 
@@ -178,8 +179,9 @@
   // Returns true if the location bar is dark.
   bool IsLocationBarDark() const;
 
-  // Returns the decoration for the page info bubble.
-  LocationBarDecoration* GetPageInfoDecoration() const;
+  PageInfoBubbleDecoration* page_info_decoration() const {
+    return page_info_decoration_.get();
+  }
 
   ManagePasswordsDecoration* manage_passwords_decoration() {
     return manage_passwords_decoration_.get();
@@ -213,6 +215,8 @@
 
   void OnEditBookmarksEnabledChanged();
 
+  void UpdatePageInfoText();
+
   // Updates visibility of the content settings icons based on the current
   // tab contents state.
   bool RefreshContentSettingsDecorations();
@@ -225,15 +229,13 @@
   // Returns whether any updates were made.
   bool UpdateZoomDecoration(bool default_zoom_changed);
 
-  // Updates the security state bubble decoration.
-  void UpdateSecurityState(bool tab_changed);
+  // Animates |page_info_decoration_| in or out if applicable. Otherwise,
+  // show it without animation.
+  void AnimatePageInfoIfPossible(bool tab_changed);
 
-  // Returns true if the security state can animate for the |level|.
+  // Returns true if the |page_info_decoration_| can animate for the |level|.
   bool CanAnimateSecurityLevel(security_state::SecurityLevel level) const;
 
-  // Returns true if |level| is SECURE or EV_SECURE.
-  bool IsSecureConnection(security_state::SecurityLevel level) const;
-
   // Returns pointers to all of the LocationBarDecorations owned by this
   // LocationBarViewMac. This helper function is used for positioning and
   // re-positioning accessibility views.
@@ -248,16 +250,12 @@
 
   AutocompleteTextField* field_;  // owned by tab controller
 
-  // A decoration that shows an icon to the left of the address.
-  std::unique_ptr<LocationIconDecoration> location_icon_decoration_;
-
   // A decoration that shows the keyword-search bubble on the left.
   std::unique_ptr<SelectedKeywordDecoration> selected_keyword_decoration_;
 
-  // A decoration that shows a security icon and the security state in a
-  // bubble on the left.
-  std::unique_ptr<SecurityStateBubbleDecoration>
-      security_state_bubble_decoration_;
+  // A decoration that shows an icon to the left of the address. If applicable,
+  // it'll also show information about the current page.
+  std::unique_ptr<PageInfoBubbleDecoration> page_info_decoration_;
 
   // Save credit card icon on the right side of the omnibox.
   std::unique_ptr<SaveCreditCardDecoration> save_credit_card_decoration_;
@@ -291,10 +289,9 @@
   bool location_bar_visible_;
 
   // True if there's enough room for the omnibox to show the security verbose.
-  // If the verbose is displaying the EV cert, then this should always be true.
   bool is_width_available_for_security_verbose_;
 
-  // The security level of the location bar icon.
+  // The security level that's displayed on |page_info_decoration_|.
   security_state::SecurityLevel security_level_;
 
   DISALLOW_COPY_AND_ASSIGN(LocationBarViewMac);
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index 45b4339..08e9f15 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -31,10 +31,9 @@
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
 #import "chrome/browser/ui/cocoa/location_bar/content_setting_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/manage_passwords_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/save_credit_card_decoration.h"
-#import "chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/translate_decoration.h"
@@ -62,6 +61,7 @@
 #include "content/public/common/url_constants.h"
 #include "skia/ext/skia_utils_mac.h"
 #import "ui/base/cocoa/cocoa_base_utils.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/color_palette.h"
@@ -96,11 +96,8 @@
       ChromeOmniboxEditController(command_updater),
       omnibox_view_(new OmniboxViewMac(this, profile, command_updater, field)),
       field_(field),
-      location_icon_decoration_(new LocationIconDecoration(this)),
       selected_keyword_decoration_(new SelectedKeywordDecoration()),
-      security_state_bubble_decoration_(
-          new SecurityStateBubbleDecoration(location_icon_decoration_.get(),
-                                            this)),
+      page_info_decoration_(new PageInfoBubbleDecoration(this)),
       save_credit_card_decoration_(
           new SaveCreditCardDecoration(command_updater)),
       star_decoration_(new StarDecoration(command_updater)),
@@ -316,11 +313,11 @@
 }
 
 NSPoint LocationBarViewMac::GetPageInfoBubblePoint() const {
-  return [field_ bubblePointForDecoration:GetPageInfoDecoration()];
+  return [field_ bubblePointForDecoration:page_info_decoration_.get()];
 }
 
 NSPoint LocationBarViewMac::GetInfoBarAnchorPoint() const {
-  return [field_ arrowAnchorPointForDecoration:GetPageInfoDecoration()];
+  return [field_ arrowAnchorPointForDecoration:page_info_decoration_.get()];
 }
 
 void LocationBarViewMac::OnDecorationsChanged() {
@@ -344,9 +341,8 @@
   // the constructor.  I am still wrestling with how best to deal with
   // right-hand decorations, which are not a static set.
   [cell clearDecorations];
-  [cell addLeadingDecoration:location_icon_decoration_.get()];
   [cell addLeadingDecoration:selected_keyword_decoration_.get()];
-  [cell addLeadingDecoration:security_state_bubble_decoration_.get()];
+  [cell addLeadingDecoration:page_info_decoration_.get()];
   [cell addTrailingDecoration:star_decoration_.get()];
   [cell addTrailingDecoration:translate_decoration_.get()];
   [cell addTrailingDecoration:zoom_decoration_.get()];
@@ -360,10 +356,9 @@
   [cell addTrailingDecoration:keyword_hint_decoration_.get()];
 
   // By default only the location icon is visible.
-  location_icon_decoration_->SetVisible(true);
   selected_keyword_decoration_->SetVisible(false);
   keyword_hint_decoration_->SetVisible(false);
-  security_state_bubble_decoration_->SetVisible(false);
+  page_info_decoration_->SetVisible(true);
 
   // Get the keyword to use for keyword-search and hinting.
   const base::string16 keyword = omnibox_view_->model()->keyword();
@@ -376,18 +371,16 @@
 
   const bool is_keyword_hint = omnibox_view_->model()->is_keyword_hint();
 
-  // This is true for EV certificate since the certificate should be
-  // displayed, even if the width is narrow.
+  page_info_decoration_->SetFullLabel(nil);
+
   CGFloat available_width =
       [cell availableWidthInFrame:[[cell controlView] frame]];
-  is_width_available_for_security_verbose_ =
-      available_width >= kMinURLWidth || ShouldShowEVBubble() ||
-      ShouldShowExtensionBubble() || ShouldShowChromeBubble();
+  is_width_available_for_security_verbose_ = available_width >= kMinURLWidth;
 
   if (!keyword.empty() && !is_keyword_hint) {
     // Switch from location icon to keyword mode.
-    location_icon_decoration_->SetVisible(false);
     selected_keyword_decoration_->SetVisible(true);
+    page_info_decoration_->SetVisible(false);
     selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword);
     // Note: the first time through this code path the
     // |selected_keyword_decoration_| has no image set because under Material
@@ -397,48 +390,12 @@
   } else if (!keyword.empty() && is_keyword_hint) {
     keyword_hint_decoration_->SetKeyword(short_name, is_extension_keyword);
     keyword_hint_decoration_->SetVisible(true);
-  } else if (ShouldShowEVBubble()) {
-    // Switch from location icon to show the EV bubble instead.
-    location_icon_decoration_->SetVisible(false);
-    security_state_bubble_decoration_->SetVisible(true);
-
-    base::string16 label(GetToolbarModel()->GetEVCertName());
-    security_state_bubble_decoration_->SetFullLabel(
-        base::SysUTF16ToNSString(label));
-  } else if (ShouldShowExtensionBubble()) {
-    // Switch from location icon to show the extension bubble instead.
-    location_icon_decoration_->SetVisible(false);
-    security_state_bubble_decoration_->SetVisible(true);
-
-    base::string16 label(
-        GetExtensionName(GetToolbarModel()->GetURL(), GetWebContents()));
-    security_state_bubble_decoration_->SetFullLabel(
-        base::SysUTF16ToNSString(label));
-  } else if (ShouldShowChromeBubble()) {
-    // Switch from location icon to show Chrome bubble instead.
-    location_icon_decoration_->SetVisible(false);
-    security_state_bubble_decoration_->SetVisible(true);
-    security_state_bubble_decoration_->SetFullLabel(
-        l10n_util::GetNSString(IDS_SHORT_PRODUCT_NAME));
-  } else if (ShouldShowSecurityState() ||
-             security_state_bubble_decoration_->AnimatingOut()) {
-    bool is_security_state_visible =
-        is_width_available_for_security_verbose_ ||
-        security_state_bubble_decoration_->AnimatingOut();
-    location_icon_decoration_->SetVisible(!is_security_state_visible);
-    security_state_bubble_decoration_->SetVisible(is_security_state_visible);
-
-    // Don't change the label if the bubble is in the process of animating
-    // out the old one.
-    base::string16 label(GetToolbarModel()->GetSecureVerboseText());
-    if (!security_state_bubble_decoration_->AnimatingOut()) {
-      security_state_bubble_decoration_->SetFullLabel(
-          base::SysUTF16ToNSString(label));
-    }
+  } else {
+    UpdatePageInfoText();
   }
 
-  if (!security_state_bubble_decoration_->IsVisible())
-    security_state_bubble_decoration_->ResetAnimation();
+  if (!page_info_decoration_->IsVisible())
+    page_info_decoration_->ResetAnimation();
 
   // These need to change anytime the layout changes.
   // TODO(shess): Anytime the field editor might have changed, the
@@ -468,7 +425,7 @@
   RefreshContentSettingsDecorations();
   if (contents) {
     omnibox_view_->OnTabChanged(contents);
-    UpdateSecurityState(contents);
+    AnimatePageInfoIfPossible(contents);
   } else {
     omnibox_view_->Update();
   }
@@ -482,17 +439,17 @@
 
 void LocationBarViewMac::UpdateLocationIcon() {
   SkColor vector_icon_color = GetLocationBarIconColor();
-  const gfx::VectorIcon& vector_icon_id = ShouldShowEVBubble()
-                                              ? toolbar::kHttpsValidIcon
-                                              : omnibox_view_->GetVectorIcon();
+  const gfx::VectorIcon& vector_icon_id =
+      GetPageInfoVerboseType() == PageInfoVerboseType::kEVCert
+          ? toolbar::kHttpsValidIcon
+          : omnibox_view_->GetVectorIcon();
 
   NSImage* image = NSImageFromImageSkiaWithColorSpace(
       gfx::CreateVectorIcon(vector_icon_id, kDefaultIconSize,
                             vector_icon_color),
       base::mac::GetSRGBColorSpace());
-  location_icon_decoration_->SetImage(image);
-  security_state_bubble_decoration_->SetImage(image);
-  security_state_bubble_decoration_->SetLabelColor(vector_icon_color);
+  page_info_decoration_->SetImage(image);
+  page_info_decoration_->SetLabelColor(vector_icon_color);
 
   Layout();
 }
@@ -520,7 +477,7 @@
 }
 
 void LocationBarViewMac::OnChanged() {
-  UpdateSecurityState(false);
+  AnimatePageInfoIfPossible(false);
   UpdateLocationIcon();
 }
 
@@ -536,30 +493,29 @@
   return browser_->tab_strip_model()->GetActiveWebContents();
 }
 
-bool LocationBarViewMac::ShouldShowEVBubble() const {
-  return GetToolbarModel()->GetSecurityLevel(false) ==
-         security_state::EV_SECURE;
-}
-
-bool LocationBarViewMac::ShouldShowExtensionBubble() const {
-  return !GetOmniboxView()->IsEditingOrEmpty() &&
-         GetToolbarModel()->GetURL().SchemeIs(extensions::kExtensionScheme);
-}
-
-bool LocationBarViewMac::ShouldShowChromeBubble() const {
-  return !GetOmniboxView()->IsEditingOrEmpty() &&
-         GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme);
-}
-
-bool LocationBarViewMac::ShouldShowSecurityState() const {
+PageInfoVerboseType LocationBarViewMac::GetPageInfoVerboseType() const {
   if (omnibox_view_->IsEditingOrEmpty() ||
       omnibox_view_->model()->is_keyword_hint()) {
-    return false;
+    return PageInfoVerboseType::kNone;
+  } else if (GetToolbarModel()->GetSecurityLevel(false) ==
+             security_state::EV_SECURE) {
+    return PageInfoVerboseType::kEVCert;
+  } else if (GetToolbarModel()->GetURL().SchemeIs(
+                 extensions::kExtensionScheme)) {
+    return PageInfoVerboseType::kExtension;
+  } else if (GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme)) {
+    return PageInfoVerboseType::kChrome;
+  } else {
+    return PageInfoVerboseType::kSecurity;
   }
+}
+
+bool LocationBarViewMac::HasSecurityVerboseText() const {
+  if (GetPageInfoVerboseType() != PageInfoVerboseType::kSecurity)
+    return false;
 
   security_state::SecurityLevel security =
       GetToolbarModel()->GetSecurityLevel(false);
-
   return security == security_state::EV_SECURE ||
          security == security_state::SECURE ||
          security == security_state::DANGEROUS ||
@@ -570,13 +526,6 @@
   return [[field_ window] inIncognitoModeWithSystemTheme];
 }
 
-LocationBarDecoration* LocationBarViewMac::GetPageInfoDecoration() const {
-  if (security_state_bubble_decoration_->IsVisible())
-    return security_state_bubble_decoration_.get();
-
-  return location_icon_decoration_.get();
-}
-
 NSImage* LocationBarViewMac::GetKeywordImage(const base::string16& keyword) {
   const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile(
       profile())->GetTemplateURLForKeyword(keyword);
@@ -599,7 +548,7 @@
   if (in_dark_mode)
     return kMaterialDarkVectorIconColor;
 
-  if (ShouldShowEVBubble())
+  if (GetPageInfoVerboseType() == PageInfoVerboseType::kEVCert)
     return gfx::kGoogleGreen700;
 
   security_state::SecurityLevel security_level =
@@ -627,6 +576,29 @@
   OnChanged();
 }
 
+void LocationBarViewMac::UpdatePageInfoText() {
+  // Don't change the label if the bubble is in the process of animating
+  // out the old one.
+  if (page_info_decoration_->AnimatingOut())
+    return;
+
+  base::string16 label;
+  PageInfoVerboseType type = GetPageInfoVerboseType();
+  if (type == PageInfoVerboseType::kEVCert) {
+    label = GetToolbarModel()->GetEVCertName();
+  } else if (type == PageInfoVerboseType::kExtension) {
+    label = GetExtensionName(GetToolbarModel()->GetURL(), GetWebContents());
+  } else if (type == PageInfoVerboseType::kChrome) {
+    label = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
+  } else if (type == PageInfoVerboseType::kSecurity &&
+             HasSecurityVerboseText()) {
+    if (is_width_available_for_security_verbose_)
+      label = GetToolbarModel()->GetSecureVerboseText();
+  }
+
+  page_info_decoration_->SetFullLabel(base::SysUTF16ToNSString(label));
+}
+
 bool LocationBarViewMac::RefreshContentSettingsDecorations() {
   const bool input_in_progress = GetToolbarModel()->input_in_progress();
   WebContents* web_contents = input_in_progress ?
@@ -663,55 +635,39 @@
       IsLocationBarDark());
 }
 
-void LocationBarViewMac::UpdateSecurityState(bool tab_changed) {
+void LocationBarViewMac::AnimatePageInfoIfPossible(bool tab_changed) {
   using SecurityLevel = security_state::SecurityLevel;
   SecurityLevel new_security_level = GetToolbarModel()->GetSecurityLevel(false);
+  bool is_new_security_level = security_level_ != new_security_level;
+  security_level_ = new_security_level;
 
   if (tab_changed)
-    security_state_bubble_decoration_->ResetAnimation();
+    page_info_decoration_->ResetAnimation();
 
-  // If there's enough space, but the secure state decoration had animated
-  // out, animate it back in. Otherwise, if the security state has changed,
-  // animate the decoration if animation is enabled and the state changed is
-  // not from a tab switch.
-  if ((ShouldShowSecurityState() || ShouldShowExtensionBubble() ||
-       ShouldShowChromeBubble()) &&
-      is_width_available_for_security_verbose_) {
-    if (tab_changed) {
-      security_state_bubble_decoration_->ShowWithoutAnimation();
-    } else {
-      bool is_secure_to_secure = IsSecureConnection(new_security_level) &&
-                                 IsSecureConnection(security_level_);
-      bool is_new_security_level =
-          security_level_ != new_security_level && !is_secure_to_secure;
-      if (!is_new_security_level &&
-          security_state_bubble_decoration_->HasAnimatedOut()) {
-        security_state_bubble_decoration_->AnimateIn(false);
-      } else if (!CanAnimateSecurityLevel(new_security_level)) {
-        security_state_bubble_decoration_->ShowWithoutAnimation();
-      } else if (is_new_security_level) {
-        security_state_bubble_decoration_->AnimateIn();
-      }
-    }
-  } else if (!is_width_available_for_security_verbose_ ||
-             (!tab_changed && CanAnimateSecurityLevel(security_level_))) {
-    security_state_bubble_decoration_->AnimateOut();
+  // Animation is only applicable for the security verbose and if the icon
+  // isn't updated from a tab switch.
+  if (GetPageInfoVerboseType() != PageInfoVerboseType::kSecurity ||
+      !HasSecurityVerboseText() || tab_changed) {
+    page_info_decoration_->ShowWithoutAnimation();
+    return;
   }
 
-  security_level_ = new_security_level;
+  if (is_width_available_for_security_verbose_) {
+    if (!is_new_security_level && page_info_decoration_->HasAnimatedOut())
+      page_info_decoration_->AnimateIn(false);
+    else if (!CanAnimateSecurityLevel(new_security_level))
+      page_info_decoration_->ShowWithoutAnimation();
+    else if (is_new_security_level)
+      page_info_decoration_->AnimateIn();
+  } else {
+    page_info_decoration_->AnimateOut();
+  }
 }
 
 bool LocationBarViewMac::CanAnimateSecurityLevel(
     security_state::SecurityLevel level) const {
-  return !GetOmniboxView()->IsEditingOrEmpty() &&
-         (level == security_state::DANGEROUS ||
-          level == security_state::HTTP_SHOW_WARNING);
-}
-
-bool LocationBarViewMac::IsSecureConnection(
-    security_state::SecurityLevel level) const {
-  return level == security_state::SECURE ||
-         level == security_state::EV_SECURE;
+  return level == security_state::DANGEROUS ||
+         level == security_state::HTTP_SHOW_WARNING;
 }
 
 void LocationBarViewMac::UpdateAccessibilityView(
@@ -762,9 +718,8 @@
   // TODO(ellyjones): page actions and keyword hints are not included right
   // now. Keyword hints have no useful tooltip (issue 752592), and page actions
   // are likewise.
-  decorations.push_back(location_icon_decoration_.get());
   decorations.push_back(selected_keyword_decoration_.get());
-  decorations.push_back(security_state_bubble_decoration_.get());
+  decorations.push_back(page_info_decoration_.get());
   decorations.push_back(save_credit_card_decoration_.get());
   decorations.push_back(star_decoration_.get());
   decorations.push_back(translate_decoration_.get());
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac_unittest.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac_unittest.mm
index e44792d..799a6837 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac_unittest.mm
@@ -11,13 +11,34 @@
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "components/toolbar/test_toolbar_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
+class LocationBarViewMacToolbarModel : public TestToolbarModel {
+  base::string16 GetSecureVerboseText() const override {
+    if (IsOfflinePage())
+      return base::ASCIIToUTF16("test");
+
+    switch (GetSecurityLevel(false)) {
+      case security_state::HTTP_SHOW_WARNING:
+      case security_state::EV_SECURE:
+      case security_state::SECURE:
+      case security_state::DANGEROUS:
+        return base::ASCIIToUTF16("test");
+      default:
+        return base::string16();
+    }
+  }
+
+  base::string16 GetEVCertName() const override {
+    return base::ASCIIToUTF16("test cert");
+  }
+};
+
 // Mocks the OmniboxView so that we can set if the omnibox is empty or not.
 class MockOmniboxView : public OmniboxViewMac {
  public:
@@ -67,49 +88,50 @@
 
  private:
   // The toolbar model used for testing.
-  TestToolbarModel toolbar_model_;
+  LocationBarViewMacToolbarModel toolbar_model_;
 
   DISALLOW_COPY_AND_ASSIGN(TestingLocationBarViewMac);
 };
 
-// Testing class for TestingSecurityStateBubbleDecoration.
-class TestingSecurityStateBubbleDecoration
-    : public SecurityStateBubbleDecoration {
+// Testing class for TestingPageInfoBubbleDecoration.
+class TestingPageInfoBubbleDecoration : public PageInfoBubbleDecoration {
  public:
-  TestingSecurityStateBubbleDecoration(LocationIconDecoration* location_icon,
-                                       LocationBarViewMac* owner)
-      : SecurityStateBubbleDecoration(location_icon, owner) {}
+  explicit TestingPageInfoBubbleDecoration(LocationBarViewMac* owner)
+      : PageInfoBubbleDecoration(owner) {}
 
   void AnimateIn(bool image_fade = true) override {
     has_animated_ = true;
     is_showing_ = true;
-    SecurityStateBubbleDecoration::AnimateIn(image_fade);
+    PageInfoBubbleDecoration::AnimateIn(image_fade);
   }
 
   void AnimateOut() override {
     has_animated_ = true;
     is_showing_ = false;
-    SecurityStateBubbleDecoration::AnimateOut();
+    PageInfoBubbleDecoration::AnimateOut();
   }
 
   void ShowWithoutAnimation() override {
-    is_showing_ = true;
     has_animated_ = false;
-    SecurityStateBubbleDecoration::ShowWithoutAnimation();
+    is_showing_ = true;
+    PageInfoBubbleDecoration::ShowWithoutAnimation();
   }
 
+  bool HasAnimatedOut() const override { return !is_showing_; }
+
+  bool AnimatingOut() const override { return false; }
+
   void ResetAnimation() override {
-    is_showing_ = false;
     has_animated_ = false;
-    SecurityStateBubbleDecoration::ResetAnimation();
+    PageInfoBubbleDecoration::ResetAnimation();
   }
 
   bool has_animated() const { return has_animated_; };
 
-  bool is_showing() const { return is_showing_; };
-
   void ResetAnimationFlag() { has_animated_ = false; }
 
+  void ResetIsShowing() { is_showing_ = false; }
+
  private:
   // True if the decoration has animated.
   bool has_animated_ = false;
@@ -117,7 +139,7 @@
   // True if the decoration is showing.
   bool is_showing_ = false;
 
-  DISALLOW_COPY_AND_ASSIGN(TestingSecurityStateBubbleDecoration);
+  DISALLOW_COPY_AND_ASSIGN(TestingPageInfoBubbleDecoration);
 };
 
 class LocationBarViewMacTest : public CocoaProfileTest {
@@ -135,10 +157,8 @@
         field_.get(), browser()->command_controller()->command_updater(),
         browser()->profile(), browser()));
 
-    location_bar_->security_state_bubble_decoration_.reset(
-        new TestingSecurityStateBubbleDecoration(
-            location_bar_->location_icon_decoration_.get(),
-            location_bar_.get()));
+    location_bar_->page_info_decoration_.reset(
+        new TestingPageInfoBubbleDecoration(location_bar_.get()));
     decoration()->disable_animations_during_testing_ = true;
 
     omnibox_view_ = new MockOmniboxView(
@@ -153,14 +173,18 @@
     CocoaProfileTest::TearDown();
   }
 
-  TestingSecurityStateBubbleDecoration* decoration() const {
-    TestingSecurityStateBubbleDecoration* decoration =
-        static_cast<TestingSecurityStateBubbleDecoration*>(
-            location_bar_->security_state_bubble_decoration_.get());
+  TestingPageInfoBubbleDecoration* decoration() const {
+    TestingPageInfoBubbleDecoration* decoration =
+        static_cast<TestingPageInfoBubbleDecoration*>(
+            location_bar_->page_info_decoration_.get());
 
     return decoration;
   }
 
+  bool IsDecorationLabelEmpty() const {
+    return !decoration()->full_label_ || ![decoration()->full_label_ length];
+  }
+
   TestingLocationBarViewMac* location_bar() const {
     return location_bar_.get();
   }
@@ -173,9 +197,9 @@
 
   AutocompleteTextField* field() const { return field_.get(); }
 
-  void UpdateSecurityState(bool tab_changed) {
+  void AnimatePageInfoIfPossible(bool tab_changed) {
     location_bar_->Layout();
-    location_bar_->UpdateSecurityState(tab_changed);
+    location_bar_->AnimatePageInfoIfPossible(tab_changed);
   }
 
  protected:
@@ -196,159 +220,157 @@
 
 // Tests the security decoration's visibility and animation without any tab or
 // width changes.
-TEST_F(LocationBarViewMacTest, ShowAndAnimateSecurityDecoration) {
+TEST_F(LocationBarViewMacTest, ShowAndAnimatePageInfoDecoration) {
   // Set the security level to DANGEROUS. The decoration should animate in.
   location_bar()->SetSecurityLevel(security_state::DANGEROUS);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Set the security level to NONE. The decoration should animate out.
   location_bar()->SetSecurityLevel(security_state::NONE);
-  UpdateSecurityState(false);
-  EXPECT_FALSE(decoration()->is_showing());
-  EXPECT_TRUE(decoration()->has_animated());
+  AnimatePageInfoIfPossible(false);
+  EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_TRUE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Set the security level to SECURE. The decoration should show, but not
   // animate.
   location_bar()->SetSecurityLevel(security_state::SECURE);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Set the security level to EV_SECURE. The decoration should still show,
   // but not animate.
   location_bar()->SetSecurityLevel(security_state::EV_SECURE);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Set the security level to NONE. The decoration should still hide without
   // animating out.
   location_bar()->SetSecurityLevel(security_state::NONE);
-  UpdateSecurityState(false);
-  EXPECT_FALSE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_TRUE(IsDecorationLabelEmpty());
 }
 
 // Tests the security decoration's visibility and animation when the omnibox
 // is updated from a switched tab.
-TEST_F(LocationBarViewMacTest, SecurityDecorationWithTabChanges) {
+TEST_F(LocationBarViewMacTest, PageInfoDecorationWithTabChanges) {
   // Show nonsecure decoration.
   location_bar()->SetSecurityLevel(security_state::HTTP_SHOW_WARNING);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
 
   decoration()->ResetAnimationFlag();
 
   // Switch to a tab with no decoration.
   location_bar()->SetSecurityLevel(security_state::NONE);
-  UpdateSecurityState(true);
-  EXPECT_FALSE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(true);
   EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_TRUE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Switch back to the tab with the nonsecure decoration.
   location_bar()->SetSecurityLevel(security_state::HTTP_SHOW_WARNING);
-  UpdateSecurityState(true);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(true);
   EXPECT_FALSE(decoration()->has_animated());
 
   decoration()->ResetAnimationFlag();
 
   // Show the secure decoration.
   location_bar()->SetSecurityLevel(security_state::SECURE);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_FALSE(decoration()->has_animated());
 
   decoration()->ResetAnimationFlag();
 
   // Switch to a tab with no decoration.
   location_bar()->SetSecurityLevel(security_state::NONE);
-  UpdateSecurityState(true);
-  EXPECT_FALSE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(true);
   EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_TRUE(IsDecorationLabelEmpty());
 }
 
 // Tests the security decoration's visibility and animation when the omnibox
 // is empty.
-TEST_F(LocationBarViewMacTest, SecurityDecorationWithEmptyOmnibox) {
+TEST_F(LocationBarViewMacTest, PageInfoDecorationWithEmptyOmnibox) {
   // Set the omnibox to empty and then set the security level to nonsecure.
   // The decoration should not appear.
   omnibox_view()->set_is_empty(true);
-  location_bar()->SetSecurityLevel(security_state::HTTP_SHOW_WARNING);
-  UpdateSecurityState(false);
-  EXPECT_FALSE(decoration()->is_showing());
+  location_bar()->SetSecurityLevel(security_state::DANGEROUS);
+  AnimatePageInfoIfPossible(false);
   EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_TRUE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Set the omnibox to nonempty. The decoration should now appear.
   omnibox_view()->set_is_empty(false);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  decoration()->ResetIsShowing();
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 }
 
 // Tests to see that the security decoration animates out when the omnibox's
 // width becomes narrow.
-TEST_F(LocationBarViewMacTest, SecurityDecorationWidthChanges) {
+TEST_F(LocationBarViewMacTest, PageInfoDecorationWidthChanges) {
   // Show the nonsecure decoration.
   location_bar()->SetSecurityLevel(security_state::HTTP_SHOW_WARNING);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Make the omnibox narrow.
   [field() setFrame:NSMakeRect(0, 0, 119, 30)];
-  UpdateSecurityState(false);
-  EXPECT_FALSE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
+  EXPECT_TRUE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Make the omnibox wide again.
   [field() setFrame:NSMakeRect(0, 0, 500, 30)];
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Show secure decoration.
   location_bar()->SetSecurityLevel(security_state::SECURE);
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_FALSE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Make the omnibox narrow.
   [field() setFrame:NSMakeRect(0, 0, 119, 30)];
-  UpdateSecurityState(false);
-  EXPECT_FALSE(decoration()->is_showing());
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
+  EXPECT_TRUE(IsDecorationLabelEmpty());
 
   decoration()->ResetAnimationFlag();
 
   // Make the omnibox wide again.
-  [field() setFrame:NSMakeRect(0, 0, 500, 30)];
-  UpdateSecurityState(false);
-  EXPECT_TRUE(decoration()->is_showing());
+  [field() setFrame:NSMakeRect(0, 0, 600, 30)];
+  AnimatePageInfoIfPossible(false);
   EXPECT_TRUE(decoration()->has_animated());
+  EXPECT_FALSE(IsDecorationLabelEmpty());
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h
deleted file mode 100644
index e97d075..0000000
--- a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/macros.h"
-#include "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
-
-class LocationBarViewMac;
-
-// LocationIconDecoration is used to display an icon to the left of
-// the address.
-
-class LocationIconDecoration : public ImageDecoration {
- public:
-  explicit LocationIconDecoration(LocationBarViewMac* owner);
-  ~LocationIconDecoration() override;
-
-  // Allow dragging the current URL.
-  bool IsDraggable() override;
-  NSPasteboard* GetDragPasteboard() override;
-  NSImage* GetDragImage() override;
-  NSRect GetDragImageFrame(NSRect frame) override;
-
-  // Show the page info panel on click.
-  bool OnMousePressed(NSRect frame, NSPoint location) override;
-  bool AcceptsMousePress() override;
-  bool HasHoverAndPressEffect() override;
-  NSString* GetToolTip() override;
-  NSString* GetAccessibilityLabel() override;
-  NSPoint GetBubblePointInFrame(NSRect frame) override;
-  NSRect GetBackgroundFrame(NSRect frame) override;
-
- private:
-  NSRect drag_frame_;
-  // The location bar view that owns us.
-  LocationBarViewMac* owner_;
-
-  DISALLOW_COPY_AND_ASSIGN(LocationIconDecoration);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_ICON_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm
deleted file mode 100644
index dd326030..0000000
--- a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
-
-#include "base/strings/sys_string_conversions.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/browser.h"
-#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
-#import "chrome/browser/ui/cocoa/drag_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#include "chrome/browser/ui/page_info/page_info_dialog.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/favicon/content/content_favicon_driver.h"
-#include "content/public/browser/web_contents.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/gfx/image/image.h"
-
-using content::WebContents;
-
-// The info-bubble point should look like it points to the bottom of the lock
-// icon. Determined with Pixie.app.
-const CGFloat kBubblePointYOffset = 2.0;
-
-// Insets for the background frame.
-const CGFloat kBackgroundFrameXInset = 1.0;
-const CGFloat kBackgroundFrameYInset = 2.0;
-
-LocationIconDecoration::LocationIconDecoration(LocationBarViewMac* owner)
-    : drag_frame_(NSZeroRect), owner_(owner) {
-}
-
-LocationIconDecoration::~LocationIconDecoration() {
-}
-
-bool LocationIconDecoration::IsDraggable() {
-  // Without a tab it will be impossible to get the information needed
-  // to perform a drag.
-  if (!owner_->GetWebContents())
-    return false;
-
-  // Do not drag if the user has been editing the location bar, or the
-  // location bar is at the NTP.
-  return (!owner_->GetOmniboxView()->IsEditingOrEmpty());
-}
-
-NSPasteboard* LocationIconDecoration::GetDragPasteboard() {
-  WebContents* tab = owner_->GetWebContents();
-  DCHECK(tab);  // See |IsDraggable()|.
-
-  NSString* url = base::SysUTF8ToNSString(tab->GetURL().spec());
-  NSString* title = base::SysUTF16ToNSString(tab->GetTitle());
-
-  NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
-  [pboard declareURLPasteboardWithAdditionalTypes:
-        [NSArray arrayWithObject:NSFilesPromisePboardType]
-                                            owner:nil];
-  [pboard setDataForURL:url title:title];
-
-  [pboard setPropertyList:[NSArray arrayWithObject:@"webloc"]
-                  forType:NSFilesPromisePboardType];
-
-  return pboard;
-}
-
-NSImage* LocationIconDecoration::GetDragImage() {
-  content::WebContents* web_contents = owner_->GetWebContents();
-  NSImage* favicon =
-      favicon::ContentFaviconDriver::FromWebContents(web_contents)
-          ->GetFavicon()
-          .AsNSImage();
-  NSImage* iconImage = favicon ? favicon : GetImage();
-
-  NSImage* image =
-      drag_util::DragImageForBookmark(iconImage,
-                                      web_contents->GetTitle(),
-                                      bookmarks::kDefaultBookmarkWidth);
-  NSSize imageSize = [image size];
-  drag_frame_ = NSMakeRect(0, 0, imageSize.width, imageSize.height);
-  return image;
-}
-
-NSRect LocationIconDecoration::GetDragImageFrame(NSRect frame) {
-  // If GetDragImage has never been called, drag_frame_ has not been calculated.
-  if (NSIsEmptyRect(drag_frame_))
-    GetDragImage();
-  return drag_frame_;
-}
-
-NSPoint LocationIconDecoration::GetBubblePointInFrame(NSRect frame) {
-  const NSRect draw_frame = GetDrawRectInFrame(frame);
-  return NSMakePoint(NSMidX(draw_frame),
-                     NSMaxY(draw_frame) - kBubblePointYOffset);
-}
-
-NSRect LocationIconDecoration::GetBackgroundFrame(NSRect frame) {
-  return NSInsetRect(frame, kBackgroundFrameXInset, kBackgroundFrameYInset);
-}
-
-bool LocationIconDecoration::AcceptsMousePress() {
-  // The search icon does not accept mouse presses.
-  return !owner_->GetOmniboxView()->IsEditingOrEmpty();
-}
-
-bool LocationIconDecoration::HasHoverAndPressEffect() {
-  // The search icon should not show a hover/pressed background.
-  return !owner_->GetOmniboxView()->IsEditingOrEmpty();
-}
-
-bool LocationIconDecoration::OnMousePressed(NSRect frame, NSPoint location) {
-  // Do not show page info if the user has been editing the location
-  // bar, or the location bar is at the NTP.
-  if (owner_->GetOmniboxView()->IsEditingOrEmpty())
-    return true;
-
-  return ShowPageInfoDialog(owner_->GetWebContents());
-}
-
-NSString* LocationIconDecoration::GetToolTip() {
-  return owner_->GetOmniboxView()->IsEditingOrEmpty() ?
-      nil : l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_LOCATION_ICON);
-}
-
-NSString* LocationIconDecoration::GetAccessibilityLabel() {
-  // This button should always be labelled even when the omnibox is being
-  // edited.
-  return l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_LOCATION_ICON);
-}
diff --git a/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h
new file mode 100644
index 0000000..cec38db9
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h
@@ -0,0 +1,130 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SECURITY_STATE_BUBBLE_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SECURITY_STATE_BUBBLE_DECORATION_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/cocoa/location_bar/bubble_decoration.h"
+#include "ui/compositor/layer_animation_observer.h"
+#include "ui/gfx/animation/animation_delegate.h"
+#include "ui/gfx/animation/slide_animation.h"
+
+// Draws the verbose state bubble, which contains the security icon and a label
+// describing its security state. If an EV cert is available, the icon will be
+// a lock and the label will contain the certificate's name. The
+// |location_icon| is used to fulfill drag-related calls.
+
+class LocationBarViewMac;
+class LocationIconDecoration;
+
+namespace {
+class PageInfoBubbleDecorationTest;
+}
+
+namespace {
+class LocationBarViewMacTest;
+}
+
+class PageInfoBubbleDecoration : public BubbleDecoration,
+                                 public gfx::AnimationDelegate {
+ public:
+  explicit PageInfoBubbleDecoration(LocationBarViewMac* owner);
+  ~PageInfoBubbleDecoration() override;
+
+  // |GetWidthForSpace()| will set |full_label| as the label, if it
+  // fits, else it will set an elided version.
+  void SetFullLabel(NSString* full_label);
+
+  // Set the color of the label.
+  void SetLabelColor(SkColor color);
+
+  // Methods that animate in and out the chip. Virtual for testing.
+  virtual void AnimateIn(bool image_fade = true);
+  virtual void AnimateOut();
+
+  // Shows the chip without animation. Virtual for testing.
+  virtual void ShowWithoutAnimation();
+
+  // Returns true if the chip has fully animated in.
+  bool HasAnimatedIn() const;
+
+  // Returns true if the chip has fully animated out. Virtual for testing.
+  virtual bool HasAnimatedOut() const;
+
+  // Returns true if the chip is in the process of animating out. Virtual for
+  // testing.
+  virtual bool AnimatingOut() const;
+
+  // Resets the animation. Virtual for testing.
+  virtual void ResetAnimation();
+
+  // LocationBarDecoration:
+  CGFloat GetWidthForSpace(CGFloat width) override;
+  void DrawInFrame(NSRect frame, NSView* control_view) override;
+  bool IsDraggable() override;
+  NSPasteboard* GetDragPasteboard() override;
+  NSImage* GetDragImage() override;
+  NSRect GetDragImageFrame(NSRect frame) override;
+  bool OnMousePressed(NSRect frame, NSPoint location) override;
+  bool AcceptsMousePress() override;
+  NSPoint GetBubblePointInFrame(NSRect frame) override;
+  NSString* GetToolTip() override;
+  NSString* GetAccessibilityLabel() override;
+  NSRect GetRealFocusRingBounds(NSRect apparent_frame) const override;
+
+  // BubbleDecoration:
+  NSColor* GetBackgroundBorderColor() override;
+
+  // gfx::AnimationDelegate:
+  void AnimationProgressed(const gfx::Animation* animation) override;
+
+ protected:
+  NSColor* GetDarkModeTextColor() override;
+
+ private:
+  friend class ::LocationBarViewMacTest;
+  friend class ::PageInfoBubbleDecorationTest;
+
+  // Returns the animation progress. If not in MD, the animation progress
+  // should always be 1.0.
+  CGFloat GetAnimationProgress() const;
+
+  // Helper method that calculates and returns the width of the label and icon
+  // within |width|.
+  CGFloat GetWidthForText(CGFloat width);
+
+  LocationIconDecoration* location_icon_;  // weak, owned by location bar.
+
+  // The real label. BubbleDecoration's label may be elided.
+  base::scoped_nsobject<NSString> full_label_;
+
+  // The color of the label's text. The default color is kGoogleGreen700.
+  SkColor label_color_;
+
+  // True if the image should fade when the verbose animates in.
+  bool image_fade_;
+
+  // The animation of the decoration.
+  gfx::SlideAnimation animation_;
+
+  LocationBarViewMac* owner_;  // weak
+
+  // Distance in points to inset the right edge of the focus ring by. This is
+  // used by |GetRealFocusRingBounds| to prevent the focus ring from including
+  // the divider bar. This is recomputed every time this object is drawn.
+  int focus_ring_right_inset_ = 0;
+
+  // Used to disable find bar animations when testing.
+  bool disable_animations_during_testing_;
+
+  // The frame of the drag-and-drop image.
+  NSRect drag_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(PageInfoBubbleDecoration);
+};
+
+#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SECURITY_STATE_BUBBLE_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.mm
new file mode 100644
index 0000000..e421b3c
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.mm
@@ -0,0 +1,387 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
+
+#include <cmath>
+
+#import "base/mac/mac_util.h"
+#include "base/strings/sys_string_conversions.h"
+#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
+#import "chrome/browser/ui/cocoa/drag_util.h"
+#include "chrome/browser/ui/cocoa/l10n_util.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
+#include "chrome/browser/ui/page_info/page_info_dialog.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/favicon/content/content_favicon_driver.h"
+#include "skia/ext/skia_utils_mac.h"
+#import "third_party/mozilla/NSPasteboard+Utils.h"
+#import "ui/base/cocoa/nsview_additions.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/image/image_skia_util_mac.h"
+#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
+#include "ui/gfx/text_elider.h"
+
+// TODO(spqchan): Decorations that don't fit in the available space are
+// omitted. See crbug.com/638427.
+
+namespace {
+
+// Padding between the label and icon/divider.
+CGFloat kLabelPadding = 4.0;
+
+// Inset for the background.
+const CGFloat kBackgroundYInset = 4.0;
+
+// The offset of the text's baseline on a retina screen.
+const CGFloat kRetinaBaselineOffset = 0.5;
+
+// The info-bubble point should look like it points to the bottom of the lock
+// icon. Determined with Pixie.app.
+const CGFloat kPageInfoBubblePointYOffset = 2.0;
+
+// Minimum acceptable width for the ev bubble.
+const CGFloat kMinElidedBubbleWidth = 150.0;
+
+// Maximum amount of available space to make the bubble, subject to
+// |kMinElidedBubbleWidth|.
+const float kMaxBubbleFraction = 0.5;
+
+// Duration of animation in ms.
+const NSTimeInterval kInAnimationDuration = 330;
+const NSTimeInterval kOutAnimationDuration = 250;
+
+// Transformation values at the beginning of the animation.
+const CGFloat kStartScale = 0.25;
+const CGFloat kStartx_offset = 15.0;
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////
+// PageInfoBubbleDecoration, public:
+
+PageInfoBubbleDecoration::PageInfoBubbleDecoration(LocationBarViewMac* owner)
+    : label_color_(gfx::kGoogleGreen700),
+      image_fade_(true),
+      animation_(this),
+      owner_(owner),
+      disable_animations_during_testing_(false) {
+  // On Retina the text label is 1px above the Omnibox textfield's text
+  // baseline. If the Omnibox textfield also drew the label the baselines
+  // would align.
+  SetRetinaBaselineOffset(kRetinaBaselineOffset);
+
+  base::scoped_nsobject<NSMutableParagraphStyle> style(
+      [[NSMutableParagraphStyle alloc] init]);
+  [style setLineBreakMode:NSLineBreakByClipping];
+  if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
+    [style setAlignment:NSRightTextAlignment];
+  [attributes_ setObject:style forKey:NSParagraphStyleAttributeName];
+  animation_.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
+}
+
+PageInfoBubbleDecoration::~PageInfoBubbleDecoration() {
+  // Just in case the timer is still holding onto the animation object, force
+  // cleanup so it can't get back to |this|.
+}
+
+void PageInfoBubbleDecoration::SetFullLabel(NSString* label) {
+  full_label_.reset([label copy]);
+  SetLabel(full_label_);
+}
+
+void PageInfoBubbleDecoration::SetLabelColor(SkColor color) {
+  label_color_ = color;
+}
+
+void PageInfoBubbleDecoration::AnimateIn(bool image_fade) {
+  image_fade_ = image_fade;
+  if (HasAnimatedIn())
+    animation_.Reset();
+
+  animation_.SetSlideDuration(kInAnimationDuration);
+  animation_.Show();
+}
+
+void PageInfoBubbleDecoration::AnimateOut() {
+  if (!HasAnimatedIn())
+    return;
+
+  animation_.SetSlideDuration(kOutAnimationDuration);
+  animation_.Hide();
+}
+
+void PageInfoBubbleDecoration::ShowWithoutAnimation() {
+  animation_.Reset(1.0);
+}
+
+bool PageInfoBubbleDecoration::HasAnimatedIn() const {
+  return animation_.IsShowing() && animation_.GetCurrentValue() == 1.0;
+}
+
+bool PageInfoBubbleDecoration::HasAnimatedOut() const {
+  return !animation_.IsShowing() && animation_.GetCurrentValue() == 0.0;
+}
+
+bool PageInfoBubbleDecoration::AnimatingOut() const {
+  return !animation_.IsShowing() && animation_.GetCurrentValue() != 0.0;
+}
+
+void PageInfoBubbleDecoration::ResetAnimation() {
+  animation_.Reset();
+}
+
+//////////////////////////////////////////////////////////////////
+// PageInfoBubbleDecoration::LocationBarDecoration:
+
+CGFloat PageInfoBubbleDecoration::GetWidthForSpace(CGFloat width) {
+  CGFloat icon_width = GetWidthForImageAndLabel(image_, nil);
+  CGFloat text_width = GetWidthForText(width) - icon_width;
+  return (text_width * GetAnimationProgress()) + icon_width;
+}
+
+void PageInfoBubbleDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
+  const NSRect decoration_frame = NSInsetRect(frame, 0.0, kBackgroundYInset);
+  CGFloat text_left_offset = NSMinX(decoration_frame);
+  CGFloat text_right_offset = NSMaxX(decoration_frame);
+  const BOOL is_rtl = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
+  focus_ring_right_inset_ = 0;
+  if (image_) {
+    // The image should fade in if we're animating in.
+    CGFloat image_alpha =
+        image_fade_ && animation_.IsShowing() ? GetAnimationProgress() : 1.0;
+
+    NSRect image_rect = GetImageRectInFrame(decoration_frame);
+    [image_ drawInRect:image_rect
+              fromRect:NSZeroRect  // Entire image
+             operation:NSCompositeSourceOver
+              fraction:image_alpha
+        respectFlipped:YES
+                 hints:nil];
+    if (is_rtl) {
+      text_left_offset += DividerPadding();
+      text_right_offset = NSMinX(image_rect);
+    } else {
+      text_right_offset -= DividerPadding();
+      text_left_offset = NSMaxX(image_rect);
+    }
+  }
+
+  // Set the text color and draw the text.
+  if (HasLabel()) {
+    bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
+    NSColor* text_color =
+        in_dark_mode ? skia::SkColorToSRGBNSColor(kMaterialDarkModeTextColor)
+                     : GetBackgroundBorderColor();
+    SetTextColor(text_color);
+
+    // Transform the coordinate system to adjust the baseline on Retina.
+    // This is the only way to get fractional adjustments.
+    gfx::ScopedNSGraphicsContextSaveGState save_graphics_state;
+    CGFloat line_width = [control_view cr_lineWidth];
+    if (line_width < 1) {
+      NSAffineTransform* transform = [NSAffineTransform transform];
+      [transform translateXBy:0 yBy:kRetinaBaselineOffset];
+      [transform concat];
+    }
+
+    base::scoped_nsobject<NSAttributedString> text([[NSAttributedString alloc]
+        initWithString:label_
+            attributes:attributes_]);
+
+    // Calculate the text frame based on the text height and offsets.
+    NSRect text_rect = frame;
+    CGFloat textHeight = [text size].height;
+
+    text_rect.origin.x = text_left_offset;
+    text_rect.origin.y = std::round(NSMidY(text_rect) - textHeight / 2.0) - 1;
+    text_rect.size.width = text_right_offset - text_left_offset;
+    text_rect.size.height = textHeight;
+    text_rect = NSInsetRect(text_rect, kLabelPadding, 0);
+
+    NSAffineTransform* transform = [NSAffineTransform transform];
+    CGFloat progress = GetAnimationProgress();
+
+    // Apply transformations so that the text animation:
+    // - Scales from 0.75 to 1.
+    // - Translates the X position to its origin after it got scaled, and
+    //   before moving in a position from from -15 to 0
+    // - Translates the Y position so that the text is centered vertically.
+    double scale = gfx::Tween::DoubleValueBetween(progress, kStartScale, 1.0);
+
+    double x_origin_offset = NSMinX(text_rect) * (1 - scale);
+    double y_origin_offset = NSMinY(text_rect) * (1 - scale);
+    double start_x_offset = is_rtl ? -kStartx_offset : kStartx_offset;
+    double x_offset =
+        gfx::Tween::DoubleValueBetween(progress, start_x_offset, 0);
+    double y_offset = NSHeight(text_rect) * (1 - scale) / 2.0;
+
+    [transform translateXBy:x_offset + x_origin_offset
+                        yBy:y_offset + y_origin_offset];
+    [transform scaleBy:scale];
+    [transform concat];
+
+    // Draw the label.
+    [text drawInRect:text_rect];
+
+    // Draw the divider.
+    if (state() == DecorationMouseState::NONE && !active()) {
+      DrawDivider(control_view, decoration_frame, GetAnimationProgress());
+      focus_ring_right_inset_ = DividerPadding() + line_width;
+    } else {
+      // When mouse-hovered, the divider isn't drawn, but the padding for it is
+      // still present to separate the button from the location bar text.
+      focus_ring_right_inset_ = DividerPadding();
+    }
+  }
+}
+
+bool PageInfoBubbleDecoration::IsDraggable() {
+  // Without a tab it will be impossible to get the information needed
+  // to perform a drag.
+  if (!owner_->GetWebContents())
+    return false;
+
+  // Do not drag if the user has been editing the location bar, or the
+  // location bar is at the NTP.
+  return (!owner_->GetOmniboxView()->IsEditingOrEmpty());
+}
+
+NSPasteboard* PageInfoBubbleDecoration::GetDragPasteboard() {
+  content::WebContents* tab = owner_->GetWebContents();
+  DCHECK(tab);  // See |IsDraggable()|.
+
+  NSString* url = base::SysUTF8ToNSString(tab->GetURL().spec());
+  NSString* title = base::SysUTF16ToNSString(tab->GetTitle());
+
+  NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+  [pboard declareURLPasteboardWithAdditionalTypes:@[ NSFilesPromisePboardType ]
+                                            owner:nil];
+  [pboard setDataForURL:url title:title];
+
+  [pboard setPropertyList:@[ @"webloc" ] forType:NSFilesPromisePboardType];
+
+  return pboard;
+}
+
+NSImage* PageInfoBubbleDecoration::GetDragImage() {
+  content::WebContents* web_contents = owner_->GetWebContents();
+  NSImage* favicon =
+      favicon::ContentFaviconDriver::FromWebContents(web_contents)
+          ->GetFavicon()
+          .AsNSImage();
+  NSImage* icon_image = favicon ? favicon : GetImage();
+
+  NSImage* image = drag_util::DragImageForBookmark(
+      icon_image, web_contents->GetTitle(), bookmarks::kDefaultBookmarkWidth);
+  NSSize image_size = [image size];
+  drag_frame_ = NSMakeRect(0, 0, image_size.width, image_size.height);
+  return image;
+}
+
+NSRect PageInfoBubbleDecoration::GetDragImageFrame(NSRect frame) {
+  // If GetDragImage has never been called, drag_frame_ has not been calculated.
+  if (NSIsEmptyRect(drag_frame_))
+    GetDragImage();
+  return drag_frame_;
+}
+
+bool PageInfoBubbleDecoration::OnMousePressed(NSRect frame, NSPoint location) {
+  // Do not show page info if the user has been editing the location
+  // bar, or the location bar is at the NTP.
+  if (owner_->GetOmniboxView()->IsEditingOrEmpty())
+    return true;
+
+  return ShowPageInfoDialog(owner_->GetWebContents());
+}
+
+bool PageInfoBubbleDecoration::AcceptsMousePress() {
+  return !owner_->GetOmniboxView()->IsEditingOrEmpty();
+}
+
+NSPoint PageInfoBubbleDecoration::GetBubblePointInFrame(NSRect frame) {
+  NSRect image_rect = GetImageRectInFrame(frame);
+  return NSMakePoint(NSMidX(image_rect),
+                     NSMaxY(image_rect) - kPageInfoBubblePointYOffset);
+}
+
+NSString* PageInfoBubbleDecoration::GetToolTip() {
+  return l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_LOCATION_ICON);
+}
+
+NSString* PageInfoBubbleDecoration::GetAccessibilityLabel() {
+  NSString* tooltip_icon_text =
+      l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_LOCATION_ICON);
+  if ([full_label_ length] == 0)
+    return tooltip_icon_text;
+  return [NSString
+      stringWithFormat:@"%@. %@", full_label_.get(), tooltip_icon_text];
+}
+
+NSRect PageInfoBubbleDecoration::GetRealFocusRingBounds(NSRect bounds) const {
+  bounds.size.width -= focus_ring_right_inset_;
+  return bounds;
+}
+
+//////////////////////////////////////////////////////////////////
+// PageInfoBubbleDecoration::BubbleDecoration:
+
+NSColor* PageInfoBubbleDecoration::GetBackgroundBorderColor() {
+  return skia::SkColorToSRGBNSColor(
+      SkColorSetA(label_color_, 255.0 * GetAnimationProgress()));
+}
+
+NSColor* PageInfoBubbleDecoration::GetDarkModeTextColor() {
+  return [NSColor whiteColor];
+}
+
+//////////////////////////////////////////////////////////////////
+// PageInfoBubbleDecoration::AnimationDelegate:
+
+void PageInfoBubbleDecoration::AnimationProgressed(
+    const gfx::Animation* animation) {
+  owner_->Layout();
+}
+
+//////////////////////////////////////////////////////////////////
+// PageInfoBubbleDecoration, private:
+
+CGFloat PageInfoBubbleDecoration::GetAnimationProgress() const {
+  if (disable_animations_during_testing_)
+    return 1.0;
+
+  return animation_.GetCurrentValue();
+}
+
+CGFloat PageInfoBubbleDecoration::GetWidthForText(CGFloat width) {
+  // Limit with to not take up too much of the available width, but
+  // also don't let it shrink too much.
+  width = std::max(width * kMaxBubbleFraction, kMinElidedBubbleWidth);
+
+  // Use the full label if it fits.
+  NSImage* image = GetImage();
+  const CGFloat all_width = GetWidthForImageAndLabel(image, full_label_);
+  if (all_width <= width) {
+    SetLabel(full_label_);
+    return all_width;
+  }
+
+  // Width left for laying out the label.
+  const CGFloat width_left = width - GetWidthForImageAndLabel(image, @"");
+
+  // Middle-elide the label to fit |width_left|.  This leaves the
+  // prefix and the trailing country code in place.
+  NSString* elided_label = base::SysUTF16ToNSString(gfx::ElideText(
+      base::SysNSStringToUTF16(full_label_),
+      gfx::FontList(gfx::Font(GetFont())), width_left, gfx::ELIDE_MIDDLE));
+
+  // Use the elided label.
+  SetLabel(elided_label);
+  return GetWidthForImageAndLabel(image, elided_label);
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration_unittest.mm
new file mode 100644
index 0000000..c77cc28d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration_unittest.mm
@@ -0,0 +1,56 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
+
+#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class PageInfoBubbleDecorationTest : public CocoaTest {
+ public:
+  PageInfoBubbleDecorationTest() : decoration_(nullptr) {
+    decoration_.disable_animations_during_testing_ = true;
+  }
+
+  PageInfoBubbleDecoration decoration_;
+};
+
+// Test that the decoration gets smaller when there's not enough space
+// to fit, within bounds.
+TEST_F(PageInfoBubbleDecorationTest, MiddleElide) {
+  NSString* kLongString = @"A very long string with spaces";
+  const CGFloat kWide = 1000.0;         // Wide enough to fit everything.
+  const CGFloat kNarrow = 10.0;         // Too narrow for anything.
+  const CGFloat kMinimumWidth = 100.0;  // Never should get this small.
+
+  const NSSize kImageSize = NSMakeSize(20.0, 20.0);
+  base::scoped_nsobject<NSImage> image(
+      [[NSImage alloc] initWithSize:kImageSize]);
+
+  decoration_.SetImage(image);
+  decoration_.SetFullLabel(kLongString);
+
+  // Lots of space, decoration not omitted.
+  EXPECT_NE(decoration_.GetWidthForSpace(kWide),
+            LocationBarDecoration::kOmittedWidth);
+
+  // If the available space is of the same magnitude as the required
+  // space, the decoration doesn't eat it all up.
+  const CGFloat long_width = decoration_.GetWidthForSpace(kWide);
+  EXPECT_NE(decoration_.GetWidthForSpace(long_width + 20.0),
+            LocationBarDecoration::kOmittedWidth);
+  EXPECT_LT(decoration_.GetWidthForSpace(long_width + 20.0), long_width);
+
+  // If there is very little space, the decoration is still relatively
+  // big.
+  EXPECT_NE(decoration_.GetWidthForSpace(kNarrow),
+            LocationBarDecoration::kOmittedWidth);
+  EXPECT_GT(decoration_.GetWidthForSpace(kNarrow), kMinimumWidth);
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h
deleted file mode 100644
index 0e85c39..0000000
--- a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SECURITY_STATE_BUBBLE_DECORATION_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SECURITY_STATE_BUBBLE_DECORATION_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/macros.h"
-#include "chrome/browser/ui/cocoa/location_bar/bubble_decoration.h"
-#include "ui/compositor/layer_animation_observer.h"
-#include "ui/gfx/animation/animation_delegate.h"
-#include "ui/gfx/animation/slide_animation.h"
-
-// Draws the verbose state bubble, which contains the security icon and a label
-// describing its security state. If an EV cert is available, the icon will be
-// a lock and the label will contain the certificate's name. The
-// |location_icon| is used to fulfill drag-related calls.
-
-class LocationBarViewMac;
-class LocationIconDecoration;
-
-namespace {
-class SecurityStateBubbleDecorationTest;
-}
-
-namespace {
-class LocationBarViewMacTest;
-}
-
-class SecurityStateBubbleDecoration : public BubbleDecoration,
-                                      public gfx::AnimationDelegate {
- public:
-  SecurityStateBubbleDecoration(LocationIconDecoration* location_icon,
-                                LocationBarViewMac* owner);
-  ~SecurityStateBubbleDecoration() override;
-
-  // |GetWidthForSpace()| will set |full_label| as the label, if it
-  // fits, else it will set an elided version.
-  void SetFullLabel(NSString* full_label);
-
-  // Set the color of the label.
-  void SetLabelColor(SkColor color);
-
-  // Methods that animate in and out the chip. Virtual for testing.
-  virtual void AnimateIn(bool image_fade = true);
-  virtual void AnimateOut();
-
-  // Shows the chip without animation. Virtual for testing.
-  virtual void ShowWithoutAnimation();
-
-  // Returns true if the chip has fully animated in.
-  bool HasAnimatedIn() const;
-
-  // Returns true if the chip has fully animated out.
-  bool HasAnimatedOut() const;
-
-  // Returns true if the chip is in the process of animating out.
-  bool AnimatingOut() const;
-
-  // Resets the animation. Virtual for testing.
-  virtual void ResetAnimation();
-
-  // LocationBarDecoration:
-  CGFloat GetWidthForSpace(CGFloat width) override;
-  void DrawInFrame(NSRect frame, NSView* control_view) override;
-  bool IsDraggable() override;
-  NSPasteboard* GetDragPasteboard() override;
-  NSImage* GetDragImage() override;
-  NSRect GetDragImageFrame(NSRect frame) override;
-  bool OnMousePressed(NSRect frame, NSPoint location) override;
-  bool AcceptsMousePress() override;
-  NSPoint GetBubblePointInFrame(NSRect frame) override;
-  NSString* GetToolTip() override;
-  NSString* GetAccessibilityLabel() override;
-  NSRect GetRealFocusRingBounds(NSRect apparent_frame) const override;
-
-  // BubbleDecoration:
-  NSColor* GetBackgroundBorderColor() override;
-
-  // gfx::AnimationDelegate:
-  void AnimationProgressed(const gfx::Animation* animation) override;
-
- protected:
-  NSColor* GetDarkModeTextColor() override;
-
- private:
-  friend class ::LocationBarViewMacTest;
-  friend class ::SecurityStateBubbleDecorationTest;
-
-  // Returns the animation progress. If not in MD, the animation progress
-  // should always be 1.0.
-  CGFloat GetAnimationProgress() const;
-
-  // Helper method that calculates and returns the width of the label and icon
-  // within |width|.
-  CGFloat GetWidthForText(CGFloat width);
-
-  LocationIconDecoration* location_icon_;  // weak, owned by location bar.
-
-  // The real label. BubbleDecoration's label may be elided.
-  base::scoped_nsobject<NSString> full_label_;
-
-  // The color of the label's text. The default color is kGoogleGreen700.
-  SkColor label_color_;
-
-  // True if the image should fade when the verbose animates in.
-  bool image_fade_;
-
-  // The animation of the decoration.
-  gfx::SlideAnimation animation_;
-
-  LocationBarViewMac* owner_;  // weak
-
-  // Distance in points to inset the right edge of the focus ring by. This is
-  // used by |GetRealFocusRingBounds| to prevent the focus ring from including
-  // the divider bar. This is recomputed every time this object is drawn.
-  int focus_ring_right_inset_ = 0;
-
-  // Used to disable find bar animations when testing.
-  bool disable_animations_during_testing_;
-
-  DISALLOW_COPY_AND_ASSIGN(SecurityStateBubbleDecoration);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_SECURITY_STATE_BUBBLE_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm
deleted file mode 100644
index 10b03af..0000000
--- a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.mm
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h"
-
-#include <cmath>
-
-#import "base/mac/mac_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#include "chrome/grit/generated_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-#include "ui/gfx/text_elider.h"
-
-// TODO(spqchan): Decorations that don't fit in the available space are
-// omitted. See crbug.com/638427.
-
-namespace {
-
-// Padding between the label and icon/divider.
-CGFloat kLabelPadding = 4.0;
-
-// Inset for the background.
-const CGFloat kBackgroundYInset = 4.0;
-
-// The offset of the text's baseline on a retina screen.
-const CGFloat kRetinaBaselineOffset = 0.5;
-
-// The info-bubble point should look like it points to the bottom of the lock
-// icon. Determined with Pixie.app.
-const CGFloat kPageInfoBubblePointYOffset = 2.0;
-
-// Minimum acceptable width for the ev bubble.
-const CGFloat kMinElidedBubbleWidth = 150.0;
-
-// Maximum amount of available space to make the bubble, subject to
-// |kMinElidedBubbleWidth|.
-const float kMaxBubbleFraction = 0.5;
-
-// Duration of animation in ms.
-const NSTimeInterval kInAnimationDuration = 330;
-const NSTimeInterval kOutAnimationDuration = 250;
-
-// Transformation values at the beginning of the animation.
-const CGFloat kStartScale = 0.25;
-const CGFloat kStartx_offset = 15.0;
-
-}  // namespace
-
-//////////////////////////////////////////////////////////////////
-// SecurityStateBubbleDecoration, public:
-
-SecurityStateBubbleDecoration::SecurityStateBubbleDecoration(
-    LocationIconDecoration* location_icon,
-    LocationBarViewMac* owner)
-    : location_icon_(location_icon),
-      label_color_(gfx::kGoogleGreen700),
-      image_fade_(true),
-      animation_(this),
-      owner_(owner),
-      disable_animations_during_testing_(false) {
-  // On Retina the text label is 1px above the Omnibox textfield's text
-  // baseline. If the Omnibox textfield also drew the label the baselines
-  // would align.
-  SetRetinaBaselineOffset(kRetinaBaselineOffset);
-
-  base::scoped_nsobject<NSMutableParagraphStyle> style(
-      [[NSMutableParagraphStyle alloc] init]);
-  [style setLineBreakMode:NSLineBreakByClipping];
-  if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
-    [style setAlignment:NSRightTextAlignment];
-  [attributes_ setObject:style forKey:NSParagraphStyleAttributeName];
-  animation_.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
-}
-
-SecurityStateBubbleDecoration::~SecurityStateBubbleDecoration() {
-  // Just in case the timer is still holding onto the animation object, force
-  // cleanup so it can't get back to |this|.
-}
-
-void SecurityStateBubbleDecoration::SetFullLabel(NSString* label) {
-  full_label_.reset([label copy]);
-  SetLabel(full_label_);
-}
-
-void SecurityStateBubbleDecoration::SetLabelColor(SkColor color) {
-  label_color_ = color;
-}
-
-void SecurityStateBubbleDecoration::AnimateIn(bool image_fade) {
-  image_fade_ = image_fade;
-  if (HasAnimatedIn())
-    animation_.Reset();
-
-  animation_.SetSlideDuration(kInAnimationDuration);
-  animation_.Show();
-}
-
-void SecurityStateBubbleDecoration::AnimateOut() {
-  if (!HasAnimatedIn())
-    return;
-
-  animation_.SetSlideDuration(kOutAnimationDuration);
-  animation_.Hide();
-}
-
-void SecurityStateBubbleDecoration::ShowWithoutAnimation() {
-  animation_.Reset(1.0);
-}
-
-bool SecurityStateBubbleDecoration::HasAnimatedIn() const {
-  return animation_.IsShowing() && animation_.GetCurrentValue() == 1.0;
-}
-
-bool SecurityStateBubbleDecoration::HasAnimatedOut() const {
-  return !animation_.IsShowing() && animation_.GetCurrentValue() == 0.0;
-}
-
-bool SecurityStateBubbleDecoration::AnimatingOut() const {
-  return !animation_.IsShowing() && animation_.GetCurrentValue() != 0.0;
-}
-
-void SecurityStateBubbleDecoration::ResetAnimation() {
-  animation_.Reset();
-}
-
-//////////////////////////////////////////////////////////////////
-// SecurityStateBubbleDecoration::LocationBarDecoration:
-
-CGFloat SecurityStateBubbleDecoration::GetWidthForSpace(CGFloat width) {
-  CGFloat location_icon_width = location_icon_->GetWidthForSpace(width);
-  CGFloat text_width = GetWidthForText(width) - location_icon_width;
-  return (text_width * GetAnimationProgress()) + location_icon_width;
-}
-
-void SecurityStateBubbleDecoration::DrawInFrame(NSRect frame,
-                                                NSView* control_view) {
-  const NSRect decoration_frame = NSInsetRect(frame, 0.0, kBackgroundYInset);
-  CGFloat text_left_offset = NSMinX(decoration_frame);
-  CGFloat text_right_offset = NSMaxX(decoration_frame);
-  const BOOL is_rtl = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
-  focus_ring_right_inset_ = 0;
-  if (image_) {
-    // The image should fade in if we're animating in.
-    CGFloat image_alpha =
-        image_fade_ && animation_.IsShowing() ? GetAnimationProgress() : 1.0;
-
-    NSRect image_rect = GetImageRectInFrame(decoration_frame);
-    [image_ drawInRect:image_rect
-              fromRect:NSZeroRect  // Entire image
-             operation:NSCompositeSourceOver
-              fraction:image_alpha
-        respectFlipped:YES
-                 hints:nil];
-    if (is_rtl) {
-      text_left_offset += DividerPadding();
-      text_right_offset = NSMinX(image_rect);
-    } else {
-      text_right_offset -= DividerPadding();
-      text_left_offset = NSMaxX(image_rect);
-    }
-  }
-
-  // Set the text color and draw the text.
-  if (label_) {
-    bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
-    NSColor* text_color =
-        in_dark_mode ? skia::SkColorToSRGBNSColor(kMaterialDarkModeTextColor)
-                     : GetBackgroundBorderColor();
-    SetTextColor(text_color);
-
-    // Transform the coordinate system to adjust the baseline on Retina.
-    // This is the only way to get fractional adjustments.
-    gfx::ScopedNSGraphicsContextSaveGState save_graphics_state;
-    CGFloat line_width = [control_view cr_lineWidth];
-    if (line_width < 1) {
-      NSAffineTransform* transform = [NSAffineTransform transform];
-      [transform translateXBy:0 yBy:kRetinaBaselineOffset];
-      [transform concat];
-    }
-
-    base::scoped_nsobject<NSAttributedString> text([[NSAttributedString alloc]
-        initWithString:label_
-            attributes:attributes_]);
-
-    // Calculate the text frame based on the text height and offsets.
-    NSRect text_rect = frame;
-    CGFloat textHeight = [text size].height;
-
-    text_rect.origin.x = text_left_offset;
-    text_rect.origin.y = std::round(NSMidY(text_rect) - textHeight / 2.0) - 1;
-    text_rect.size.width = text_right_offset - text_left_offset;
-    text_rect.size.height = textHeight;
-    text_rect = NSInsetRect(text_rect, kLabelPadding, 0);
-
-    NSAffineTransform* transform = [NSAffineTransform transform];
-    CGFloat progress = GetAnimationProgress();
-
-    // Apply transformations so that the text animation:
-    // - Scales from 0.75 to 1.
-    // - Translates the X position to its origin after it got scaled, and
-    //   before moving in a position from from -15 to 0
-    // - Translates the Y position so that the text is centered vertically.
-    double scale = gfx::Tween::DoubleValueBetween(progress, kStartScale, 1.0);
-
-    double x_origin_offset = NSMinX(text_rect) * (1 - scale);
-    double y_origin_offset = NSMinY(text_rect) * (1 - scale);
-    double start_x_offset = is_rtl ? -kStartx_offset : kStartx_offset;
-    double x_offset =
-        gfx::Tween::DoubleValueBetween(progress, start_x_offset, 0);
-    double y_offset = NSHeight(text_rect) * (1 - scale) / 2.0;
-
-    [transform translateXBy:x_offset + x_origin_offset
-                        yBy:y_offset + y_origin_offset];
-    [transform scaleBy:scale];
-    [transform concat];
-
-    // Draw the label.
-    [text drawInRect:text_rect];
-
-    // Draw the divider.
-    if (state() == DecorationMouseState::NONE && !active()) {
-      DrawDivider(control_view, decoration_frame, GetAnimationProgress());
-      focus_ring_right_inset_ = DividerPadding() + line_width;
-    } else {
-      // When mouse-hovered, the divider isn't drawn, but the padding for it is
-      // still present to separate the button from the location bar text.
-      focus_ring_right_inset_ = DividerPadding();
-    }
-  }
-}
-
-// Pass mouse operations through to location icon.
-bool SecurityStateBubbleDecoration::IsDraggable() {
-  return location_icon_->IsDraggable();
-}
-
-NSPasteboard* SecurityStateBubbleDecoration::GetDragPasteboard() {
-  return location_icon_->GetDragPasteboard();
-}
-
-NSImage* SecurityStateBubbleDecoration::GetDragImage() {
-  return location_icon_->GetDragImage();
-}
-
-NSRect SecurityStateBubbleDecoration::GetDragImageFrame(NSRect frame) {
-  return GetImageRectInFrame(frame);
-}
-
-bool SecurityStateBubbleDecoration::OnMousePressed(NSRect frame,
-                                                   NSPoint location) {
-  return location_icon_->OnMousePressed(frame, location);
-}
-
-bool SecurityStateBubbleDecoration::AcceptsMousePress() {
-  return true;
-}
-
-NSPoint SecurityStateBubbleDecoration::GetBubblePointInFrame(NSRect frame) {
-  NSRect image_rect = GetImageRectInFrame(frame);
-  return NSMakePoint(NSMidX(image_rect),
-                     NSMaxY(image_rect) - kPageInfoBubblePointYOffset);
-}
-
-NSString* SecurityStateBubbleDecoration::GetToolTip() {
-  return l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_LOCATION_ICON);
-}
-
-NSString* SecurityStateBubbleDecoration::GetAccessibilityLabel() {
-  NSString* tooltip_icon_text =
-      l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_LOCATION_ICON);
-  if ([full_label_ length] == 0)
-    return tooltip_icon_text;
-  return [NSString
-      stringWithFormat:@"%@. %@", full_label_.get(), tooltip_icon_text];
-}
-
-NSRect SecurityStateBubbleDecoration::GetRealFocusRingBounds(
-    NSRect bounds) const {
-  bounds.size.width -= focus_ring_right_inset_;
-  return bounds;
-}
-
-//////////////////////////////////////////////////////////////////
-// SecurityStateBubbleDecoration::BubbleDecoration:
-
-NSColor* SecurityStateBubbleDecoration::GetBackgroundBorderColor() {
-  return skia::SkColorToSRGBNSColor(
-      SkColorSetA(label_color_, 255.0 * GetAnimationProgress()));
-}
-
-NSColor* SecurityStateBubbleDecoration::GetDarkModeTextColor() {
-  return [NSColor whiteColor];
-}
-
-//////////////////////////////////////////////////////////////////
-// SecurityStateBubbleDecoration::AnimationDelegate:
-
-void SecurityStateBubbleDecoration::AnimationProgressed(
-    const gfx::Animation* animation) {
-  owner_->Layout();
-}
-
-//////////////////////////////////////////////////////////////////
-// SecurityStateBubbleDecoration, private:
-
-CGFloat SecurityStateBubbleDecoration::GetAnimationProgress() const {
-  if (disable_animations_during_testing_)
-    return 1.0;
-
-  return animation_.GetCurrentValue();
-}
-
-CGFloat SecurityStateBubbleDecoration::GetWidthForText(CGFloat width) {
-  // Limit with to not take up too much of the available width, but
-  // also don't let it shrink too much.
-  width = std::max(width * kMaxBubbleFraction, kMinElidedBubbleWidth);
-
-  // Use the full label if it fits.
-  NSImage* image = GetImage();
-  const CGFloat all_width = GetWidthForImageAndLabel(image, full_label_);
-  if (all_width <= width) {
-    SetLabel(full_label_);
-    return all_width;
-  }
-
-  // Width left for laying out the label.
-  const CGFloat width_left = width - GetWidthForImageAndLabel(image, @"");
-
-  // Middle-elide the label to fit |width_left|.  This leaves the
-  // prefix and the trailing country code in place.
-  NSString* elided_label = base::SysUTF16ToNSString(gfx::ElideText(
-      base::SysNSStringToUTF16(full_label_),
-      gfx::FontList(gfx::Font(GetFont())), width_left, gfx::ELIDE_MIDDLE));
-
-  // Use the elided label.
-  SetLabel(elided_label);
-  return GetWidthForImageAndLabel(image, elided_label);
-}
diff --git a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm b/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm
deleted file mode 100644
index 41e9f712..0000000
--- a/chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/location_bar/security_state_bubble_decoration.h"
-
-#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-class SecurityStateBubbleDecorationTest : public CocoaTest {
- public:
-  SecurityStateBubbleDecorationTest()
-      : icon_(nullptr), decoration_(&icon_, nullptr) {
-    decoration_.disable_animations_during_testing_ = true;
-  }
-
-  LocationIconDecoration icon_;
-  SecurityStateBubbleDecoration decoration_;
-};
-
-// Test that the decoration gets smaller when there's not enough space
-// to fit, within bounds.
-TEST_F(SecurityStateBubbleDecorationTest, MiddleElide) {
-  NSString* kLongString = @"A very long string with spaces";
-  const CGFloat kWide = 1000.0;         // Wide enough to fit everything.
-  const CGFloat kNarrow = 10.0;         // Too narrow for anything.
-  const CGFloat kMinimumWidth = 100.0;  // Never should get this small.
-
-  const NSSize kImageSize = NSMakeSize(20.0, 20.0);
-  base::scoped_nsobject<NSImage> image(
-      [[NSImage alloc] initWithSize:kImageSize]);
-
-  decoration_.SetImage(image);
-  decoration_.SetFullLabel(kLongString);
-
-  // Lots of space, decoration not omitted.
-  EXPECT_NE(decoration_.GetWidthForSpace(kWide),
-            LocationBarDecoration::kOmittedWidth);
-
-  // If the available space is of the same magnitude as the required
-  // space, the decoration doesn't eat it all up.
-  const CGFloat long_width = decoration_.GetWidthForSpace(kWide);
-  EXPECT_NE(decoration_.GetWidthForSpace(long_width + 20.0),
-            LocationBarDecoration::kOmittedWidth);
-  EXPECT_LT(decoration_.GetWidthForSpace(long_width + 20.0), long_width);
-
-  // If there is very little space, the decoration is still relatively
-  // big.
-  EXPECT_NE(decoration_.GetWidthForSpace(kNarrow),
-            LocationBarDecoration::kOmittedWidth);
-  EXPECT_GT(decoration_.GetWidthForSpace(kNarrow), kMinimumWidth);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
index f101151..4f192f4 100644
--- a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
@@ -23,8 +23,8 @@
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/browser/ui/cocoa/key_equivalent_constants.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/page_info/permission_selector_button.h"
 #include "chrome/browser/ui/page_info/page_info_dialog.h"
 #include "chrome/browser/ui/page_info/permission_menu_model.h"
@@ -280,7 +280,7 @@
   BrowserWindowController* controller = [[self parentWindow] windowController];
   LocationBarViewMac* locationBar = [controller locationBarBridge];
   if (locationBar) {
-    decoration_ = locationBar->GetPageInfoDecoration();
+    decoration_ = locationBar->page_info_decoration();
     decoration_->SetActive(true);
   }
 
diff --git a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm
index afa6c65d..ef88c91 100644
--- a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm
@@ -12,7 +12,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
 #include "content/public/test/test_web_contents_factory.h"
 #include "net/test/test_certificate_data.h"
@@ -330,7 +330,7 @@
   BrowserWindowController* controller =
       [BrowserWindowController browserWindowControllerForWindow:window];
   LocationBarDecoration* decoration =
-      [controller locationBarBridge]->GetPageInfoDecoration();
+      [controller locationBarBridge]->page_info_decoration();
 
   CreateBubble();
   EXPECT_TRUE([[controller_ window] isVisible]);
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
index 6033bb7..1bf1d17 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
@@ -23,8 +23,8 @@
 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #import "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #include "chrome/browser/ui/cocoa/page_info/page_info_utils_cocoa.h"
 #include "chrome/browser/ui/cocoa/page_info/permission_selector_button.h"
 #include "chrome/browser/ui/cocoa/page_info/split_block_button.h"
@@ -177,7 +177,7 @@
   LocationBarViewMac* bridge =
       [[self.parentWindow windowController] locationBarBridge];
   if ([self hasVisibleLocationBar] && bridge) {
-    decoration_ = bridge->GetPageInfoDecoration();
+    decoration_ = bridge->page_info_decoration();
     decoration_->SetActive(true);
   }
 
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
index 15c9fca..4db2b16 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
@@ -18,7 +18,7 @@
 #include "chrome/browser/ui/bubble_anchor_util.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
 #include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/page_info_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/page_info/split_block_button.h"
 #import "chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa.h"
 #import "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
@@ -170,7 +170,7 @@
   BrowserWindowController* controller =
       [BrowserWindowController browserWindowControllerForWindow:window];
   LocationBarDecoration* decoration =
-      [controller locationBarBridge]->GetPageInfoDecoration();
+      [controller locationBarBridge]->page_info_decoration();
 
   [controller_ showWindow:nil];
   EXPECT_TRUE([[controller_ window] isVisible]);
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index f345d28..0d8474f3 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -242,17 +242,12 @@
     DCHECK(originalContentView_);
 
     // Return the original window's tab strip view and content view to their
-    // places. The TabStripView always needs to be in front of the window's
-    // content view and therefore it should always be added after the content
-    // view is set. It needs to be positioned below the avatar button to ensure
-    // that its overlay will not overlap it.
-    [[window contentView] addSubview:originalContentView_
-                          positioned:NSWindowAbove
-                          relativeTo:nil];
+    // places. The TabStripView should be in front of the content view, and the
+    // avatar button, if present, should be in front of the TabStripView.
+    [[window contentView] addSubview:originalContentView_];
     originalContentView_.frame = [[window contentView] bounds];
-    [[window contentView] addSubview:[self tabStripView]
-                          positioned:NSWindowBelow
-                          relativeTo:[self avatarView]];
+    [[window contentView] addSubview:[self tabStripView]];
+    [[window contentView] addSubview:[self avatarView]];
     [[self tabStripView] setInATabDraggingOverlayWindow:NO];
     [[window contentView] updateTrackingAreas];
 
diff --git a/chrome/browser/ui/external_protocol_dialog_delegate.cc b/chrome/browser/ui/external_protocol_dialog_delegate.cc
index a0079ac..6c1dfc3c 100644
--- a/chrome/browser/ui/external_protocol_dialog_delegate.cc
+++ b/chrome/browser/ui/external_protocol_dialog_delegate.cc
@@ -50,8 +50,7 @@
 }
 
 base::string16 ExternalProtocolDialogDelegate::GetCheckboxText() const {
-  return l10n_util::GetStringFUTF16(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT,
-                                    ElideCommandName(program_name_));
+  return l10n_util::GetStringUTF16(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT);
 }
 
 base::string16 ExternalProtocolDialogDelegate::GetTitleText() const {
@@ -60,11 +59,11 @@
 }
 
 void ExternalProtocolDialogDelegate::DoAccept(const GURL& url,
-                                              bool dont_block) const {
+                                              bool remember) const {
   content::WebContents* web_contents = tab_util::GetWebContentsByID(
       render_process_host_id_, render_view_routing_id_);
 
-  if (dont_block) {
+  if (remember) {
     Profile* profile =
         Profile::FromBrowserContext(web_contents->GetBrowserContext());
 
@@ -74,16 +73,3 @@
 
   ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url, web_contents);
 }
-
-void ExternalProtocolDialogDelegate::DoCancel(const GURL& url,
-                                              bool dont_block) const {
-  if (dont_block) {
-    content::WebContents* web_contents = tab_util::GetWebContentsByID(
-        render_process_host_id_, render_view_routing_id_);
-    Profile* profile =
-        Profile::FromBrowserContext(web_contents->GetBrowserContext());
-
-    ExternalProtocolHandler::SetBlockState(
-        url.scheme(), ExternalProtocolHandler::BLOCK, profile);
-  }
-}
diff --git a/chrome/browser/ui/external_protocol_dialog_delegate.h b/chrome/browser/ui/external_protocol_dialog_delegate.h
index e7325eb..57891e7 100644
--- a/chrome/browser/ui/external_protocol_dialog_delegate.h
+++ b/chrome/browser/ui/external_protocol_dialog_delegate.h
@@ -22,8 +22,7 @@
 
   const base::string16& program_name() const { return program_name_; }
 
-  void DoAccept(const GURL& url, bool dont_block) const override;
-  void DoCancel(const GURL& url, bool dont_block) const override;
+  void DoAccept(const GURL& url, bool remember) const override;
 
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   base::string16 GetMessageText() const override;
diff --git a/chrome/browser/ui/overlay/OWNERS b/chrome/browser/ui/overlay/OWNERS
new file mode 100644
index 0000000..645933b
--- /dev/null
+++ b/chrome/browser/ui/overlay/OWNERS
@@ -0,0 +1,4 @@
+apacible@chromium.org
+mlamouri@chromium.org
+
+# COMPONENT: Internals>Media>UI
diff --git a/chrome/browser/ui/passwords/password_manager_presenter.cc b/chrome/browser/ui/passwords/password_manager_presenter.cc
index 4f4406b..d2535a6 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter.cc
+++ b/chrome/browser/ui/passwords/password_manager_presenter.cc
@@ -381,7 +381,7 @@
 void PasswordManagerPresenter::PasswordListPopulater::Populate() {
   PasswordStore* store = page_->GetPasswordStore();
   if (store != NULL) {
-    cancelable_task_tracker()->TryCancelAll();
+    CancelAllRequests();
     store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(this);
   } else {
     LOG(ERROR) << "No password store! Cannot display passwords.";
@@ -405,7 +405,7 @@
 void PasswordManagerPresenter::PasswordExceptionListPopulater::Populate() {
   PasswordStore* store = page_->GetPasswordStore();
   if (store != NULL) {
-    cancelable_task_tracker()->TryCancelAll();
+    CancelAllRequests();
     store->GetBlacklistLoginsWithAffiliationAndBrandingInformation(this);
   } else {
     LOG(ERROR) << "No password store! Cannot display exceptions.";
diff --git a/chrome/browser/ui/protocol_dialog_delegate.h b/chrome/browser/ui/protocol_dialog_delegate.h
index f1d913e..9fa827f 100644
--- a/chrome/browser/ui/protocol_dialog_delegate.h
+++ b/chrome/browser/ui/protocol_dialog_delegate.h
@@ -18,14 +18,9 @@
   virtual ~ProtocolDialogDelegate() {}
 
   // Called if the user has chosen to launch the application for this protocol.
-  // |dont_block| is true if the checkbox to prevent future instances of this
+  // |remember| is true if the checkbox to prevent future instances of this
   // dialog is checked.
-  virtual void DoAccept(const GURL& url, bool dont_block) const = 0;
-
-  // Called if the user has chosen to do nothing for this protocol.
-  // |dont_block| is true if the checkbox to prevent future instances of this
-  // dialog is checked.
-  virtual void DoCancel(const GURL& url, bool dont_block) const = 0;
+  virtual void DoAccept(const GURL& url, bool remember) const = 0;
 
   virtual base::string16 GetDialogButtonLabel(
       ui::DialogButton button) const = 0;
diff --git a/chrome/browser/ui/search/instant_controller.cc b/chrome/browser/ui/search/instant_controller.cc
index 0fd79bc5..337167cf 100644
--- a/chrome/browser/ui/search/instant_controller.cc
+++ b/chrome/browser/ui/search/instant_controller.cc
@@ -7,14 +7,38 @@
 #include <stddef.h>
 #include <utility>
 
+#include "base/bind.h"
+#include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/ui/browser_instant_controller.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
-#include "url/gurl.h"
+#include "content/public/browser/web_contents_observer.h"
+
+class InstantController::TabObserver : public content::WebContentsObserver {
+ public:
+  TabObserver(content::WebContents* web_contents, const base::Closure& callback)
+      : content::WebContentsObserver(web_contents), callback_(callback) {}
+  ~TabObserver() override = default;
+
+ private:
+  // Overridden from content::WebContentsObserver:
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override {
+    if (navigation_handle->HasCommitted() &&
+        navigation_handle->IsInMainFrame()) {
+      callback_.Run();
+    }
+  }
+
+  base::Closure callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabObserver);
+};
 
 InstantController::InstantController(BrowserInstantController* browser)
     : browser_(browser), search_origin_(SearchModel::Origin::DEFAULT) {}
@@ -49,12 +73,8 @@
   debug_events_.clear();
 }
 
-void InstantController::InstantTabAboutToNavigateMainFrame(
-    const content::WebContents* contents,
-    const GURL& url) {
-  DCHECK(instant_tab_);
-  DCHECK_EQ(instant_tab_->web_contents(), contents);
-
+void InstantController::InstantTabAboutToNavigateMainFrame() {
+  DCHECK(instant_tab_observer_);
   // The Instant tab navigated (which means it had instant support both before
   // and after the navigation). This may cause it to be assigned to a new
   // renderer process, which doesn't have the most visited/theme data yet, so
@@ -67,18 +87,21 @@
 void InstantController::ResetInstantTab() {
   if (search_origin_ == SearchModel::Origin::NTP) {
     content::WebContents* active_tab = browser_->GetActiveWebContents();
-    if (!instant_tab_ || active_tab != instant_tab_->web_contents()) {
-      instant_tab_ = base::MakeUnique<InstantTab>(this, active_tab);
-      instant_tab_->Init();
+    if (!instant_tab_observer_ ||
+        active_tab != instant_tab_observer_->web_contents()) {
+      instant_tab_observer_ = base::MakeUnique<TabObserver>(
+          active_tab,
+          base::Bind(&InstantController::InstantTabAboutToNavigateMainFrame,
+                     base::Unretained(this)));
       UpdateInfoForInstantTab();
     }
   } else {
-    instant_tab_.reset();
+    instant_tab_observer_.reset();
   }
 }
 
 void InstantController::UpdateInfoForInstantTab() {
-  DCHECK(instant_tab_);
+  DCHECK(instant_tab_observer_);
   InstantService* instant_service =
       InstantServiceFactory::GetForProfile(browser_->profile());
   if (instant_service) {
diff --git a/chrome/browser/ui/search/instant_controller.h b/chrome/browser/ui/search/instant_controller.h
index e7c97f9d..f82b504f 100644
--- a/chrome/browser/ui/search/instant_controller.h
+++ b/chrome/browser/ui/search/instant_controller.h
@@ -14,33 +14,28 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "chrome/browser/ui/search/instant_tab.h"
 #include "chrome/browser/ui/search/search_model.h"
 
 class BrowserInstantController;
 
-namespace content {
-class WebContents;
-}
-
 // InstantController is responsible for updating the theme and most visited info
 // of the current tab when
 // * the user switches to an existing NTP tab, or
 // * an open tab navigates to an NTP.
 //
 // InstantController is owned by Browser via BrowserInstantController.
-class InstantController : public InstantTab::Delegate {
+class InstantController {
  public:
   explicit InstantController(BrowserInstantController* browser);
-  ~InstantController() override;
+  ~InstantController();
 
-  // The search mode in the active tab has changed. Bind |instant_tab_| if the
-  // |new_mode| reflects an Instant NTP.
+  // The search mode in the active tab has changed. Bind |instant_tab_observer_|
+  // if the |new_origin| reflects an Instant NTP.
   void SearchModeChanged(SearchModel::Origin old_origin,
                          SearchModel::Origin new_origin);
 
-  // The user switched tabs. Bind |instant_tab_| if the newly active tab is an
-  // Instant NTP.
+  // The user switched tabs. Bind |instant_tab_observer_| if the newly active
+  // tab is an Instant NTP.
   void ActiveTabChanged();
 
   // Resets list of debug events.
@@ -52,6 +47,8 @@
   }
 
  private:
+  class TabObserver;
+
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
                            SearchDoesntReuseInstantTabWithoutSupport);
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
@@ -59,11 +56,7 @@
   FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest,
                            DispatchMVChangeEventWhileNavigatingBackToNTP);
 
-  // Overridden from InstantTab::Delegate:
-  // TODO(shishir): We assume that the WebContent's current RenderViewHost is
-  // the RenderViewHost being created which is not always true. Fix this.
-  void InstantTabAboutToNavigateMainFrame(const content::WebContents* contents,
-                                          const GURL& url) override;
+  void InstantTabAboutToNavigateMainFrame();
 
   // Adds a new event to |debug_events_| and also DVLOG's it. Ensures that
   // |debug_events_| doesn't get too large.
@@ -78,8 +71,8 @@
 
   BrowserInstantController* const browser_;
 
-  // The instance of InstantTab maintained by InstantController.
-  std::unique_ptr<InstantTab> instant_tab_;
+  // Only non-null if the current tab is an Instant tab, i.e. an NTP.
+  std::unique_ptr<TabObserver> instant_tab_observer_;
 
   // The search model mode for the active tab.
   SearchModel::Origin search_origin_;
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index 1d21c52c..bc75c88 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -2,136 +2,34 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <stdint.h>
-
 #include <sstream>
 
-#include "base/base_switches.h"
-#include "base/command_line.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/histogram_samples.h"
-#include "base/metrics/statistics_recorder.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/instant_service.h"
-#include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/location_bar/location_bar.h"
-#include "chrome/browser/ui/search/instant_tab.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
 #include "chrome/browser/ui/search/instant_uitest_base.h"
-#include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/theme_source.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/search/instant_types.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/bookmarks/browser/bookmark_utils.h"
-#include "components/bookmarks/test/bookmark_test_helpers.h"
-#include "components/history/core/browser/history_db_task.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/history/core/browser/top_sites.h"
-#include "components/history/core/common/thumbnail_score.h"
-#include "components/omnibox/browser/autocomplete_controller.h"
-#include "components/omnibox/browser/autocomplete_match.h"
-#include "components/omnibox/browser/autocomplete_provider.h"
-#include "components/omnibox/browser/autocomplete_result.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
-#include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/search_provider.h"
-#include "components/prefs/pref_service.h"
-#include "components/search/search.h"
-#include "components/search_engines/template_url_service.h"
-#include "components/sessions/core/serialized_navigation_entry.h"
 #include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
-#include "content/public/browser/site_instance.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/bindings_policy.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "net/base/network_change_notifier.h"
-#include "net/http/http_status_code.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher_impl.h"
-#include "net/url_request/url_request_status.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-using base::ASCIIToUTF16;
-using testing::HasSubstr;
-
-namespace {
-
-// Task used to make sure history has finished processing a request. Intended
-// for use with BlockUntilHistoryProcessesPendingRequests.
-class QuittingHistoryDBTask : public history::HistoryDBTask {
- public:
-  QuittingHistoryDBTask() {}
-
-  bool RunOnDBThread(history::HistoryBackend* backend,
-                     history::HistoryDatabase* db) override {
-    return true;
-  }
-
-  void DoneRunOnMainThread() override {
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
-  }
-
- private:
-  ~QuittingHistoryDBTask() override {}
-
-  DISALLOW_COPY_AND_ASSIGN(QuittingHistoryDBTask);
-};
-
-class FakeNetworkChangeNotifier : public net::NetworkChangeNotifier {
- public:
-  FakeNetworkChangeNotifier() : connection_type_(CONNECTION_NONE) {}
-
-  ConnectionType GetCurrentConnectionType() const override {
-    return connection_type_;
-  }
-
-  void SetConnectionType(ConnectionType type) {
-    connection_type_ = type;
-    NotifyObserversOfNetworkChange(type);
-    base::RunLoop().RunUntilIdle();
-  }
-
-  ~FakeNetworkChangeNotifier() override {}
-
- private:
-  ConnectionType connection_type_;
-  DISALLOW_COPY_AND_ASSIGN(FakeNetworkChangeNotifier);
-};
-}  // namespace
+#include "testing/gtest/include/gtest/gtest.h"
 
 class InstantExtendedTest : public InProcessBrowserTest,
                             public InstantUITestBase {
@@ -140,7 +38,6 @@
       : on_most_visited_change_calls_(0),
         most_visited_items_count_(0),
         first_most_visited_item_id_(0),
-        submit_count_(0),
         on_focus_changed_calls_(0),
         is_focused_(false) {}
 
@@ -154,17 +51,6 @@
     InstantTestBase::Init(instant_url, ntp_url, false);
   }
 
-  int64_t GetHistogramCount(const char* name) {
-    base::HistogramBase* histogram =
-        base::StatisticsRecorder::FindHistogram(name);
-    if (!histogram) {
-      // If no histogram is found, it's possible that no values have been
-      // recorded yet. Assume that the value is zero.
-      return 0;
-    }
-    return histogram->SnapshotSamples()->TotalCount();
-  }
-
   bool UpdateSearchState(content::WebContents* contents) WARN_UNUSED_RESULT {
     return instant_test_utils::GetIntFromJS(contents,
                                             "onMostVisitedChangedCalls",
@@ -173,105 +59,22 @@
                                             &most_visited_items_count_) &&
            instant_test_utils::GetIntFromJS(contents, "firstMostVisitedItemId",
                                             &first_most_visited_item_id_) &&
-           instant_test_utils::GetIntFromJS(contents, "submitCount",
-                                            &submit_count_) &&
            instant_test_utils::GetIntFromJS(contents, "onFocusChangedCalls",
                                             &on_focus_changed_calls_) &&
            instant_test_utils::GetBoolFromJS(contents, "isFocused",
-                                             &is_focused_) &&
-           instant_test_utils::GetStringFromJS(contents, "prefetchQuery",
-                                               &prefetch_query_value_);
-  }
-
-  const TemplateURL* GetDefaultSearchProviderTemplateURL() {
-    TemplateURLService* template_url_service =
-        TemplateURLServiceFactory::GetForProfile(browser()->profile());
-    if (template_url_service)
-      return template_url_service->GetDefaultSearchProvider();
-    return NULL;
-  }
-
-  bool AddSearchToHistory(base::string16 term, int visit_count) {
-    const TemplateURL* template_url = GetDefaultSearchProviderTemplateURL();
-    if (!template_url)
-      return false;
-
-    history::HistoryService* history = HistoryServiceFactory::GetForProfile(
-        browser()->profile(), ServiceAccessType::EXPLICIT_ACCESS);
-    GURL search(template_url->url_ref().ReplaceSearchTerms(
-        TemplateURLRef::SearchTermsArgs(term),
-        TemplateURLServiceFactory::GetForProfile(
-            browser()->profile())->search_terms_data()));
-    history->AddPageWithDetails(
-        search, base::string16(), visit_count, visit_count,
-        base::Time::Now(), false, history::SOURCE_BROWSED);
-    history->SetKeywordSearchTermsForURL(
-        search, template_url->id(), term);
-    return true;
-  }
-
-  void BlockUntilHistoryProcessesPendingRequests() {
-    history::HistoryService* history = HistoryServiceFactory::GetForProfile(
-        browser()->profile(), ServiceAccessType::EXPLICIT_ACCESS);
-    DCHECK(history);
-    DCHECK(base::MessageLoop::current());
-
-    base::CancelableTaskTracker tracker;
-    history->ScheduleDBTask(
-        std::unique_ptr<history::HistoryDBTask>(new QuittingHistoryDBTask()),
-        &tracker);
-    base::RunLoop().Run();
-  }
-
-  int CountSearchProviderSuggestions() {
-    return omnibox()->model()->autocomplete_controller()->search_provider()->
-        matches().size();
+                                             &is_focused_);
   }
 
   int on_most_visited_change_calls_;
   int most_visited_items_count_;
   int first_most_visited_item_id_;
-  int submit_count_;
   int on_focus_changed_calls_;
   bool is_focused_;
-  std::string prefetch_query_value_;
 };
 
-class InstantExtendedPrefetchTest : public InstantExtendedTest {
+class InstantThemeTest : public ExtensionBrowserTest, public InstantUITestBase {
  public:
-  InstantExtendedPrefetchTest()
-      : factory_(new net::URLFetcherImplFactory()),
-        fake_factory_(new net::FakeURLFetcherFactory(factory_.get())) {
-  }
-
-  void SetUpInProcessBrowserTestFixture() override {
-    ASSERT_TRUE(https_test_server().Start());
-    GURL instant_url =
-        https_test_server().GetURL("/instant_extended.html?strk=1&");
-    GURL ntp_url =
-        https_test_server().GetURL("/instant_extended_ntp.html?strk=1&");
-    InstantTestBase::Init(instant_url, ntp_url, true);
-  }
-
-  net::FakeURLFetcherFactory* fake_factory() { return fake_factory_.get(); }
-
- private:
-  // Used to instantiate FakeURLFetcherFactory.
-  std::unique_ptr<net::URLFetcherImplFactory> factory_;
-
-  // Used to mock default search provider suggest response.
-  std::unique_ptr<net::FakeURLFetcherFactory> fake_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstantExtendedPrefetchTest);
-};
-
-// Test class used to verify chrome-search: scheme and access policy from the
-// Instant overlay.  This is a subclass of |ExtensionBrowserTest| because it
-// loads a theme that provides a background image.
-class InstantPolicyTest : public ExtensionBrowserTest,
-                          public InstantUITestBase {
- public:
-  InstantPolicyTest() {}
+  InstantThemeTest() {}
 
  protected:
   void SetUpInProcessBrowserTestFixture() override {
@@ -306,82 +109,29 @@
     theme_change_observer.Wait();
     const extensions::Extension* new_theme =
         ThemeServiceFactory::GetThemeForProfile(profile());
-    ASSERT_NE(static_cast<extensions::Extension*>(NULL), new_theme);
+    ASSERT_NE(nullptr, new_theme);
     ASSERT_EQ(new_theme->name(), theme_name);
   }
 
+  // Loads a named image from |image_url| from the given |rvh| host. |loaded|
+  // returns whether the image was able to load without error.
+  // The method returns true if the JavaScript executed cleanly.
+  bool LoadImage(content::RenderViewHost* rvh,
+                 const GURL& image_url,
+                 bool* loaded) {
+    std::string js_chrome =
+        "var img = document.createElement('img');"
+        "img.onerror = function() { domAutomationController.send(false); };"
+        "img.onload  = function() { domAutomationController.send(true); };"
+        "img.src = '" +
+        image_url.spec() + "';";
+    return content::ExecuteScriptAndExtractBool(rvh, js_chrome, loaded);
+  }
+
  private:
-  DISALLOW_COPY_AND_ASSIGN(InstantPolicyTest);
+  DISALLOW_COPY_AND_ASSIGN(InstantThemeTest);
 };
 
-// TODO(https://crbug.com/678975): Flaky on memory bot (all platforms).
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       DISABLED_SearchDoesntReuseInstantTab) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmnibox();
-
-  SetOmniboxText("flowers");
-  PressEnterAndWaitForFrameLoad();
-
-  // Just did a regular search.
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=flowers"));
-  ASSERT_TRUE(UpdateSearchState(active_tab));
-  ASSERT_EQ(0, submit_count_);
-
-  SetOmniboxText("puppies");
-  PressEnterAndWaitForNavigation();
-
-  // Should not have reused the tab.
-  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=puppies"));
-  ASSERT_TRUE(UpdateSearchState(active_tab));
-  EXPECT_EQ(0, submit_count_);
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       SearchDoesntReuseInstantTabWithoutSupport) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmnibox();
-
-  // Don't wait for the navigation to complete.
-  SetOmniboxText("flowers");
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  SetOmniboxText("puppies");
-  browser()->window()->GetLocationBar()->AcceptInput();
-
-  // Should not have reused the tab.
-  ASSERT_THAT(
-      browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(),
-      HasSubstr("q=puppies"));
-}
-
-IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       TypedSearchURLDoesntReuseInstantTab) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmnibox();
-
-  SetOmniboxText("flowers");
-  PressEnterAndWaitForFrameLoad();
-
-  // Just did a regular search.
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=flowers"));
-  ASSERT_TRUE(UpdateSearchState(active_tab));
-  ASSERT_EQ(0, submit_count_);
-
-  // Typed in a search URL "by hand".
-  SetOmniboxText(instant_url().Resolve("#q=puppies").spec());
-  PressEnterAndWaitForNavigation();
-
-  // Should not have reused the tab.
-  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=puppies"));
-}
-
 // Test to verify that switching tabs should not dispatch onmostvisitedchanged
 // events.
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NoMostVisitedChangedOnTabSwitch) {
@@ -414,25 +164,23 @@
   EXPECT_EQ(1, on_most_visited_change_calls_);
 }
 
-IN_PROC_BROWSER_TEST_F(InstantPolicyTest, ThemeBackgroundAccess) {
+IN_PROC_BROWSER_TEST_F(InstantThemeTest, ThemeBackgroundAccess) {
   InstallThemeSource();
   ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
 
-  // The "Instant" New Tab should have access to chrome-search: scheme but not
-  // chrome: scheme.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL),
       WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
           ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
 
+  // The "Instant" New Tab should have access to chrome-search: scheme but not
+  // chrome: scheme.
+  const GURL chrome_url("chrome://theme/IDR_THEME_NTP_BACKGROUND");
+  const GURL search_url("chrome-search://theme/IDR_THEME_NTP_BACKGROUND");
   content::RenderViewHost* rvh =
       browser()->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost();
-
-  const std::string chrome_url("chrome://theme/IDR_THEME_NTP_BACKGROUND");
-  const std::string search_url(
-      "chrome-search://theme/IDR_THEME_NTP_BACKGROUND");
   bool loaded = false;
   ASSERT_TRUE(LoadImage(rvh, chrome_url, &loaded));
   EXPECT_FALSE(loaded) << chrome_url;
@@ -441,7 +189,7 @@
 }
 
 // Flaky on all bots. http://crbug.com/335297.
-IN_PROC_BROWSER_TEST_F(InstantPolicyTest,
+IN_PROC_BROWSER_TEST_F(InstantThemeTest,
                        DISABLED_NoThemeBackgroundChangeEventOnTabSwitch) {
   InstallThemeSource();
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
@@ -483,7 +231,7 @@
 }
 
 // Flaky on all bots. http://crbug.com/335297, http://crbug.com/265971.
-IN_PROC_BROWSER_TEST_F(InstantPolicyTest,
+IN_PROC_BROWSER_TEST_F(InstantThemeTest,
                        DISABLED_SendThemeBackgroundChangedEvent) {
   InstallThemeSource();
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
@@ -592,130 +340,6 @@
   EXPECT_EQ(1, on_most_visited_change_calls_);
 }
 
-// http://crbug.com/518106
-IN_PROC_BROWSER_TEST_F(InstantExtendedPrefetchTest, DISABLED_SetPrefetchQuery) {
-  // Skip the test if suggest support is disabled, since this is generally due
-  // to policy and can't be overridden.
-  if (!browser()->profile()->GetPrefs()->GetBoolean(
-      prefs::kSearchSuggestEnabled)) {
-    return;
-  }
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmnibox();
-
-  content::WindowedNotificationObserver new_tab_observer(
-      content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-      content::NotificationService::AllSources());
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL(chrome::kChromeUINewTabURL),
-      WindowOpenDisposition::CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
-  new_tab_observer.Wait();
-
-  OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs = 0;
-
-  // Set the fake response for search query.
-  fake_factory()->SetFakeResponse(instant_url().Resolve("#q=flowers"),
-                                  "",
-                                  net::HTTP_OK,
-                                  net::URLRequestStatus::SUCCESS);
-
-  // Navigate to a search results page.
-  SetOmniboxText("flowers");
-  PressEnterAndWaitForNavigation();
-
-  // Set the fake response for suggest request. Response has prefetch details.
-  // Ensure that the page received the suggest response, then add another
-  // keystroke to allow the asynchronously-received inline autocomplete
-  // suggestion to actually be inlined (which in turn triggers it to prefetch).
-  fake_factory()->SetFakeResponse(
-      instant_url().Resolve("#q=pup"),
-      "[\"pup\",[\"puppy\", \"puppies\"],[],[],"
-      "{\"google:clientdata\":{\"phi\": 0},"
-          "\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
-          "\"google:suggestrelevance\":[1400, 9]}]",
-      net::HTTP_OK,
-      net::URLRequestStatus::SUCCESS);
-
-  SetOmniboxText("pup");
-  while (!omnibox()->model()->autocomplete_controller()->done()) {
-    content::WindowedNotificationObserver ready_observer(
-        chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
-        content::Source<AutocompleteController>(
-            omnibox()->model()->autocomplete_controller()));
-    ready_observer.Wait();
-  }
-  SetOmniboxText("pupp");
-
-  ASSERT_EQ(3, CountSearchProviderSuggestions());
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(UpdateSearchState(active_tab));
-  ASSERT_TRUE(SearchProvider::ShouldPrefetch(*(
-      omnibox()->model()->result().default_match())));
-  ASSERT_EQ("puppy", prefetch_query_value_);
-}
-
-// http://crbug.com/518106
-IN_PROC_BROWSER_TEST_F(InstantExtendedPrefetchTest,
-                       DISABLED_ClearPrefetchedResults) {
-  // Skip the test if suggest support is disabled, since this is generally due
-  // to policy and can't be overridden.
-  if (!browser()->profile()->GetPrefs()->GetBoolean(
-      prefs::kSearchSuggestEnabled)) {
-    return;
-  }
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-  FocusOmnibox();
-
-  content::WindowedNotificationObserver new_tab_observer(
-      content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-      content::NotificationService::AllSources());
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL(chrome::kChromeUINewTabURL),
-      WindowOpenDisposition::CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
-  new_tab_observer.Wait();
-
-  OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs = 0;
-
-  // Set the fake response for search query.
-  fake_factory()->SetFakeResponse(instant_url().Resolve("#q=flowers"),
-                                  "",
-                                  net::HTTP_OK,
-                                  net::URLRequestStatus::SUCCESS);
-
-  // Navigate to a search results page.
-  SetOmniboxText("flowers");
-  PressEnterAndWaitForNavigation();
-
-  // Set the fake response for suggest request. Response has no prefetch
-  // details. Ensure that the page received a blank query to clear the
-  // prefetched results.
-  fake_factory()->SetFakeResponse(
-      instant_url().Resolve("#q=dogs"),
-      "[\"dogs\",[\"https://dogs.com\"],[],[],"
-          "{\"google:suggesttype\":[\"NAVIGATION\"],"
-          "\"google:suggestrelevance\":[2]}]",
-      net::HTTP_OK,
-      net::URLRequestStatus::SUCCESS);
-
-  SetOmniboxText("dogs");
-  while (!omnibox()->model()->autocomplete_controller()->done()) {
-    content::WindowedNotificationObserver ready_observer(
-        chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
-        content::Source<AutocompleteController>(
-            omnibox()->model()->autocomplete_controller()));
-    ready_observer.Wait();
-  }
-
-  ASSERT_EQ(2, CountSearchProviderSuggestions());
-  ASSERT_FALSE(SearchProvider::ShouldPrefetch(*(
-      omnibox()->model()->result().default_match())));
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(UpdateSearchState(active_tab));
-  ASSERT_EQ("", prefetch_query_value_);
-}
-
 // Check that clicking on a result sends the correct referrer.
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest, Referrer) {
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -741,5 +365,5 @@
   content::WaitForLoadStop(contents);
   std::string expected_title =
       "Referrer is " + instant_url().GetWithEmptyPath().spec();
-  EXPECT_EQ(ASCIIToUTF16(expected_title), contents->GetTitle());
+  EXPECT_EQ(base::ASCIIToUTF16(expected_title), contents->GetTitle());
 }
diff --git a/chrome/browser/ui/search/instant_tab.cc b/chrome/browser/ui/search/instant_tab.cc
deleted file mode 100644
index 7193a54..0000000
--- a/chrome/browser/ui/search/instant_tab.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/search/instant_tab.h"
-
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/web_contents.h"
-
-InstantTab::Delegate::~Delegate() {}
-
-InstantTab::InstantTab(Delegate* delegate, content::WebContents* web_contents)
-    : delegate_(delegate), pending_web_contents_(web_contents) {}
-
-InstantTab::~InstantTab() {}
-
-void InstantTab::Init() {
-  if (!pending_web_contents_)
-    return;
-
-  Observe(pending_web_contents_);
-  pending_web_contents_ = nullptr;
-}
-
-void InstantTab::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  if (navigation_handle->HasCommitted() && navigation_handle->IsInMainFrame()) {
-    delegate_->InstantTabAboutToNavigateMainFrame(
-        web_contents(), navigation_handle->GetURL());
-  }
-}
diff --git a/chrome/browser/ui/search/instant_tab.h b/chrome/browser/ui/search/instant_tab.h
deleted file mode 100644
index 91035d95..0000000
--- a/chrome/browser/ui/search/instant_tab.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_SEARCH_INSTANT_TAB_H_
-#define CHROME_BROWSER_UI_SEARCH_INSTANT_TAB_H_
-
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "content/public/browser/web_contents_observer.h"
-
-class GURL;
-
-namespace content {
-class WebContents;
-}
-
-// InstantTab is instantiated by InstantController for the current tab if it
-// is a New Tab page.
-class InstantTab : public content::WebContentsObserver {
- public:
-  // InstantTab calls its delegate in response to messages received from the
-  // page. Each method is called with the |contents| corresponding to the page
-  // we are observing.
-  class Delegate {
-   public:
-    // Called when the page is about to navigate to |url|.
-    virtual void InstantTabAboutToNavigateMainFrame(
-        const content::WebContents* contents,
-        const GURL& url) = 0;
-
-   protected:
-    virtual ~Delegate();
-  };
-
-  InstantTab(Delegate* delegate, content::WebContents* web_contents);
-  ~InstantTab() override;
-
-  // Sets up communication with the WebContents passed to the constructor. Does
-  // nothing if that WebContents was null. Should not be called more than once.
-  void Init();
-
- private:
-  // Overridden from content::WebContentsObserver:
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override;
-
-  Delegate* const delegate_;
-
-  content::WebContents* pending_web_contents_;
-
-  DISALLOW_COPY_AND_ASSIGN(InstantTab);
-};
-
-#endif  // CHROME_BROWSER_UI_SEARCH_INSTANT_TAB_H_
diff --git a/chrome/browser/ui/search/instant_uitest_base.cc b/chrome/browser/ui/search/instant_uitest_base.cc
index 6b62ce9..ed24d9f1 100644
--- a/chrome/browser/ui/search/instant_uitest_base.cc
+++ b/chrome/browser/ui/search/instant_uitest_base.cc
@@ -63,15 +63,3 @@
 std::string InstantUITestBase::GetOmniboxText() {
   return base::UTF16ToUTF8(omnibox()->GetText());
 }
-
-bool InstantUITestBase::LoadImage(content::RenderViewHost* rvh,
-                                  const std::string& image,
-                                  bool* loaded) {
-  std::string js_chrome =
-      "var img = document.createElement('img');"
-      "img.onerror = function() { domAutomationController.send(false); };"
-      "img.onload  = function() { domAutomationController.send(true); };"
-      "img.src = '" +
-      image + "';";
-  return content::ExecuteScriptAndExtractBool(rvh, js_chrome, loaded);
-}
diff --git a/chrome/browser/ui/search/instant_uitest_base.h b/chrome/browser/ui/search/instant_uitest_base.h
index 6d9e978..54c2711 100644
--- a/chrome/browser/ui/search/instant_uitest_base.h
+++ b/chrome/browser/ui/search/instant_uitest_base.h
@@ -12,10 +12,6 @@
 
 class OmniboxView;
 
-namespace content {
-class RenderViewHost;
-}  // namespace content
-
 // This utility class is meant to be used in a "mix-in" fashion, giving the
 // derived test class additional Instant-related UI test functionality.
 class InstantUITestBase : public InstantTestBase {
@@ -35,13 +31,6 @@
 
   std::string GetOmniboxText();
 
-  // Loads a named image from url |image| from the given |rvh| host.  |loaded|
-  // returns whether the image was able to load without error.
-  // The method returns true if the JavaScript executed cleanly.
-  bool LoadImage(content::RenderViewHost* rvh,
-                 const std::string& image,
-                 bool* loaded);
-
  private:
   DISALLOW_COPY_AND_ASSIGN(InstantUITestBase);
 };
diff --git a/chrome/browser/ui/signin_view_controller.cc b/chrome/browser/ui/signin_view_controller.cc
index f7bb63a..5602c7fa 100644
--- a/chrome/browser/ui/signin_view_controller.cc
+++ b/chrome/browser/ui/signin_view_controller.cc
@@ -7,8 +7,7 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/signin_view_controller_delegate.h"
 
-SigninViewController::SigninViewController()
-    : signin_view_controller_delegate_(nullptr) {}
+SigninViewController::SigninViewController() : delegate_(nullptr) {}
 
 SigninViewController::~SigninViewController() {
   CloseModalSignin();
@@ -21,14 +20,13 @@
   CloseModalSignin();
   // The delegate will delete itself on request of the UI code when the widget
   // is closed.
-  signin_view_controller_delegate_ =
-      SigninViewControllerDelegate::CreateModalSigninDelegate(
-          this, mode, browser, access_point);
+  delegate_ = SigninViewControllerDelegate::CreateModalSigninDelegate(
+      this, mode, browser, access_point);
 
   // When the user has a proxy that requires HTTP auth, loading the sign-in
   // dialog can trigger the HTTP auth dialog.  This means the signin view
   // controller needs a dialog manager to handle any such dialog.
-  signin_view_controller_delegate_->AttachDialogManager();
+  delegate_->AttachDialogManager();
   chrome::RecordDialogCreation(chrome::DialogIdentifier::SIGN_IN);
 }
 
@@ -36,9 +34,8 @@
   CloseModalSignin();
   // The delegate will delete itself on request of the UI code when the widget
   // is closed.
-  signin_view_controller_delegate_ =
-      SigninViewControllerDelegate::CreateSyncConfirmationDelegate(this,
-                                                                   browser);
+  delegate_ = SigninViewControllerDelegate::CreateSyncConfirmationDelegate(
+      this, browser);
   chrome::RecordDialogCreation(
       chrome::DialogIdentifier::SIGN_IN_SYNC_CONFIRMATION);
 }
@@ -47,25 +44,34 @@
   CloseModalSignin();
   // The delegate will delete itself on request of the UI code when the widget
   // is closed.
-  signin_view_controller_delegate_ =
+  delegate_ =
       SigninViewControllerDelegate::CreateSigninErrorDelegate(this, browser);
   chrome::RecordDialogCreation(chrome::DialogIdentifier::SIGN_IN_ERROR);
 }
 
-void SigninViewController::CloseModalSignin() {
-  if (signin_view_controller_delegate_)
-    signin_view_controller_delegate_->CloseModalSignin();
+bool SigninViewController::ShowsModalDialog() {
+  return delegate_ != nullptr;
+}
 
-  DCHECK(!signin_view_controller_delegate_);
+void SigninViewController::CloseModalSignin() {
+  if (delegate_)
+    delegate_->CloseModalSignin();
+
+  DCHECK(!delegate_);
 }
 
 void SigninViewController::SetModalSigninHeight(int height) {
-  if (signin_view_controller_delegate_)
-    signin_view_controller_delegate_->ResizeNativeView(height);
+  if (delegate_)
+    delegate_->ResizeNativeView(height);
+}
+
+void SigninViewController::PerformNavigation() {
+  if (delegate_)
+    delegate_->PerformNavigation();
 }
 
 void SigninViewController::ResetModalSigninDelegate() {
-  signin_view_controller_delegate_ = nullptr;
+  delegate_ = nullptr;
 }
 
 // static
@@ -75,3 +81,9 @@
          mode == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
          mode == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH;
 }
+
+content::WebContents*
+SigninViewController::GetModalDialogWebContentsForTesting() {
+  DCHECK(delegate_);
+  return delegate_->web_contents();
+}
diff --git a/chrome/browser/ui/signin_view_controller.h b/chrome/browser/ui/signin_view_controller.h
index adc7ce5..0ea37cd 100644
--- a/chrome/browser/ui/signin_view_controller.h
+++ b/chrome/browser/ui/signin_view_controller.h
@@ -11,6 +11,14 @@
 class Browser;
 class SigninViewControllerDelegate;
 
+namespace content {
+class WebContents;
+}
+
+namespace login_ui_test_utils {
+class SigninViewControllerTestUtil;
+}
+
 namespace signin_metrics {
 enum class AccessPoint;
 }
@@ -35,6 +43,9 @@
   void ShowModalSyncConfirmationDialog(Browser* browser);
   void ShowModalSigninErrorDialog(Browser* browser);
 
+  // Returns true if the modal dialog is shown.
+  bool ShowsModalDialog();
+
   // Closes the tab-modal signin flow previously shown using this
   // SigninViewController, if one exists. Does nothing otherwise.
   void CloseModalSignin();
@@ -42,16 +53,21 @@
   // Sets the height of the modal signin dialog.
   void SetModalSigninHeight(int height);
 
-  // Notifies this object that it's |signin_view_controller_delegate_|
-  // member has become invalid.
+  // Either navigates back in the signin flow if the history state allows it or
+  // closes the flow otherwise.
+  // Does nothing if the signin flow does not exist.
+  void PerformNavigation();
+
+  // Notifies this object that it's |delegate_| member has become invalid.
   void ResetModalSigninDelegate();
 
-  SigninViewControllerDelegate* delegate() {
-    return signin_view_controller_delegate_;
-  }
-
  private:
-  SigninViewControllerDelegate* signin_view_controller_delegate_;
+  friend class login_ui_test_utils::SigninViewControllerTestUtil;
+
+  // Returns the web contents of the modal dialog.
+  content::WebContents* GetModalDialogWebContentsForTesting();
+
+  SigninViewControllerDelegate* delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(SigninViewController);
 };
diff --git a/chrome/browser/ui/signin_view_controller_delegate.h b/chrome/browser/ui/signin_view_controller_delegate.h
index b6c7c129..e50d79d 100644
--- a/chrome/browser/ui/signin_view_controller_delegate.h
+++ b/chrome/browser/ui/signin_view_controller_delegate.h
@@ -78,7 +78,7 @@
 
   // WebContents is used for executing javascript in the context of a modal sync
   // confirmation dialog.
-  content::WebContents* web_contents_for_testing() { return web_contents_; }
+  content::WebContents* web_contents() { return web_contents_; }
 
  protected:
   SigninViewControllerDelegate(SigninViewController* signin_view_controller,
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 11bb9cd5..5baae933 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -381,8 +381,9 @@
       // the signin for the original profile was cancelled (must do this after
       // we have called Initialize() with the new profile, as otherwise this
       // object will get freed when the signin on the old profile is cancelled.
-      old_signin_manager->SignOut(signin_metrics::TRANSFER_CREDENTIALS,
-                                  signin_metrics::SignoutDelete::IGNORE_METRIC);
+      old_signin_manager->SignOutAndRemoveAllAccounts(
+          signin_metrics::TRANSFER_CREDENTIALS,
+          signin_metrics::SignoutDelete::IGNORE_METRIC);
 
       if (!dm_token_.empty()) {
         // Load policy for the just-created profile - once policy has finished
@@ -415,9 +416,9 @@
 }
 
 void OneClickSigninSyncStarter::CancelSigninAndDelete() {
-  SigninManagerFactory::GetForProfile(profile_)
-      ->SignOut(signin_metrics::ABORT_SIGNIN,
-                signin_metrics::SignoutDelete::IGNORE_METRIC);
+  SigninManagerFactory::GetForProfile(profile_)->SignOut(
+      signin_metrics::ABORT_SIGNIN,
+      signin_metrics::SignoutDelete::IGNORE_METRIC);
   // The statement above results in a call to SigninFailed() which will free
   // this object, so do not refer to the OneClickSigninSyncStarter object
   // after this point.
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index d992488..71f1ce0 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -71,6 +71,8 @@
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/dom_distiller/content/browser/web_contents_main_frame_observer.h"
 #include "components/dom_distiller/core/dom_distiller_switches.h"
+#include "components/download/content/factory/navigation_monitor_factory.h"
+#include "components/download/content/public/download_navigation_observer.h"
 #include "components/history/content/browser/web_contents_top_sites_observer.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/offline_pages/features/features.h"
@@ -202,6 +204,9 @@
 
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  download::DownloadNavigationObserver::CreateForWebContents(
+      web_contents,
+      download::NavigationMonitorFactory::GetForBrowserContext(profile));
   history::WebContentsTopSitesObserver::CreateForWebContents(
       web_contents, TopSitesFactory::GetForProfile(profile).get());
   HistoryTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index 345e78d..db90857 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -180,6 +180,10 @@
   init_params->mus_properties
       [ui::mojom::WindowManager::kRemoveStandardFrame_InitProperty] =
       mojo::ConvertTo<std::vector<uint8_t>>(init_params->remove_standard_frame);
+  init_params
+      ->mus_properties[ui::mojom::WindowManager::kShelfItemType_Property] =
+      mojo::ConvertTo<std::vector<uint8_t>>(
+          static_cast<int64_t>(ash::TYPE_APP));
 }
 
 void ChromeNativeAppWindowViewsAuraAsh::OnBeforePanelWidgetInit(
@@ -194,6 +198,10 @@
     wm::ConvertRectToScreen(ash::Shell::GetRootWindowForNewWindows(),
                             &init_params->bounds);
   }
+  init_params
+      ->mus_properties[ui::mojom::WindowManager::kShelfItemType_Property] =
+      mojo::ConvertTo<std::vector<uint8_t>>(
+          static_cast<int64_t>(ash::TYPE_APP_PANEL));
 }
 
 views::NonClientFrameView*
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
index babbed17..f9cc8aae 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
@@ -67,7 +67,7 @@
   SignInBrowser(browser());
 
 #if !defined(OS_CHROMEOS)
-  EXPECT_TRUE(browser()->signin_view_controller()->delegate());
+  EXPECT_TRUE(browser()->signin_view_controller()->ShowsModalDialog());
   EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
 #else
   EXPECT_EQ(starting_tab_count + 1, browser()->tab_strip_model()->count());
@@ -80,7 +80,7 @@
   SignInBrowser(browser());
 
 #if !defined(OS_CHROMEOS)
-  EXPECT_TRUE(browser()->signin_view_controller()->delegate());
+  EXPECT_TRUE(browser()->signin_view_controller()->ShowsModalDialog());
 #endif
   EXPECT_EQ(starting_tab_count, browser()->tab_strip_model()->count());
 }
@@ -131,7 +131,7 @@
 
   int tab_count = extra_browser->tab_strip_model()->count();
 #if !defined(OS_CHROMEOS)
-  EXPECT_TRUE(extra_browser->signin_view_controller()->delegate());
+  EXPECT_TRUE(extra_browser->signin_view_controller()->ShowsModalDialog());
   EXPECT_EQ(starting_tab_count, tab_count);
 #else
   // A new tab should have been opened in the extra browser, which should be
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc
index 7a1e128..f10d3e53 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -54,10 +54,6 @@
   return gfx::Size(kDialogContentWidth, GetHeightForWidth(kDialogContentWidth));
 }
 
-int ExternalProtocolDialog::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_CANCEL;
-}
-
 base::string16 ExternalProtocolDialog::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return delegate_->GetDialogButtonLabel(button);
@@ -68,12 +64,8 @@
 }
 
 bool ExternalProtocolDialog::Cancel() {
-  const bool remember = remember_decision_checkbox_->checked();
-  delegate_->DoCancel(delegate_->url(), remember);
-
-  ExternalProtocolHandler::RecordCheckboxStateMetrics(remember);
   ExternalProtocolHandler::RecordHandleStateMetrics(
-      remember, ExternalProtocolHandler::BLOCK);
+      false /* checkbox_selected */, ExternalProtocolHandler::BLOCK);
 
   // Returning true closes the dialog.
   return true;
@@ -87,7 +79,6 @@
                            base::TimeTicks::Now() - creation_time_);
 
   const bool remember = remember_decision_checkbox_->checked();
-  ExternalProtocolHandler::RecordCheckboxStateMetrics(remember);
   ExternalProtocolHandler::RecordHandleStateMetrics(
       remember, ExternalProtocolHandler::DONT_BLOCK);
 
@@ -97,15 +88,6 @@
   return true;
 }
 
-bool ExternalProtocolDialog::Close() {
-  // If the user dismisses the dialog without interacting with the buttons (e.g.
-  // via pressing Esc or the X), act as though they cancelled the request, but
-  // ignore the checkbox state. This ensures that if they check the checkbox but
-  // dismiss the dialog, we don't stop prompting them forever.
-  delegate_->DoCancel(delegate_->url(), false);
-  return true;
-}
-
 ui::ModalType ExternalProtocolDialog::GetModalType() const {
   return ui::MODAL_TYPE_CHILD;
 }
diff --git a/chrome/browser/ui/views/external_protocol_dialog.h b/chrome/browser/ui/views/external_protocol_dialog.h
index 8175d7c4..7929190 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.h
+++ b/chrome/browser/ui/views/external_protocol_dialog.h
@@ -22,7 +22,7 @@
 
 class ExternalProtocolDialog : public views::DialogDelegateView {
  public:
-  // Show by calling ExternalProtocolHandler::RunExternalProtocolDialog.
+  // Show by calling ExternalProtocolHandler::RunExternalProtocolDialog().
   ExternalProtocolDialog(std::unique_ptr<const ProtocolDialogDelegate> delegate,
                          int render_process_host_id,
                          int routing_id);
@@ -31,12 +31,10 @@
 
   // views::DialogDelegateView:
   gfx::Size CalculatePreferredSize() const override;
-  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   base::string16 GetWindowTitle() const override;
   bool Cancel() override;
   bool Accept() override;
-  bool Close() override;
   ui::ModalType GetModalType() const override;
 
  private:
diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
index 6bac799..3607a81 100644
--- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
@@ -40,7 +40,7 @@
 }  // namespace test
 
 // Wrapper dialog delegate that sets |called|, |accept|, |cancel|, and
-// |dont_block| bools based on what is called by the ExternalProtocolDialog.
+// |remember| bools based on what is called by the ExternalProtocolDialog.
 class TestExternalProtocolDialogDelegate
     : public ExternalProtocolDialogDelegate {
  public:
@@ -49,36 +49,24 @@
                                      int routing_id,
                                      bool* called,
                                      bool* accept,
-                                     bool* cancel,
-                                     bool* dont_block)
+                                     bool* remember)
       : ExternalProtocolDialogDelegate(url, render_process_host_id, routing_id),
         called_(called),
         accept_(accept),
-        cancel_(cancel),
-        dont_block_(dont_block) {}
+        remember_(remember) {}
 
   // ExternalProtocolDialogDelegate:
-  void DoAccept(const GURL& url, bool dont_block) const override {
+  void DoAccept(const GURL& url, bool remember) const override {
     // Don't call the base impl because it will actually launch |url|.
     *called_ = true;
     *accept_ = true;
-    *cancel_ = false;
-    *dont_block_ = dont_block;
-  }
-
-  void DoCancel(const GURL& url, bool dont_block) const override {
-    // Don't call the base impl because it will actually launch |url|.
-    *called_ = true;
-    *accept_ = false;
-    *cancel_ = true;
-    *dont_block_ = dont_block;
+    *remember_ = remember;
   }
 
  private:
   bool* called_;
   bool* accept_;
-  bool* cancel_;
-  bool* dont_block_;
+  bool* remember_;
 
   DISALLOW_COPY_AND_ASSIGN(TestExternalProtocolDialogDelegate);
 };
@@ -96,7 +84,7 @@
     dialog_ = new ExternalProtocolDialog(
         base::MakeUnique<TestExternalProtocolDialogDelegate>(
             GURL("telnet://12345"), render_process_host_id, routing_id,
-            &called_, &accept_, &cancel_, &dont_block_),
+            &called_, &accept_, &remember_),
         render_process_host_id, routing_id);
   }
 
@@ -110,8 +98,7 @@
   ExternalProtocolDialog* dialog_ = nullptr;
   bool called_ = false;
   bool accept_ = false;
-  bool cancel_ = false;
-  bool dont_block_ = false;
+  bool remember_ = false;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ExternalProtocolDialogBrowserTest);
@@ -122,10 +109,7 @@
   EXPECT_TRUE(dialog_->Accept());
   EXPECT_TRUE(called_);
   EXPECT_TRUE(accept_);
-  EXPECT_FALSE(cancel_);
-  EXPECT_FALSE(dont_block_);
-  histogram_tester_.ExpectBucketCount(
-      ExternalProtocolHandler::kRememberCheckboxMetric, 0 /* false */, 1);
+  EXPECT_FALSE(remember_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::LAUNCH, 1);
@@ -138,10 +122,7 @@
   EXPECT_TRUE(dialog_->Accept());
   EXPECT_TRUE(called_);
   EXPECT_TRUE(accept_);
-  EXPECT_FALSE(cancel_);
-  EXPECT_TRUE(dont_block_);
-  histogram_tester_.ExpectBucketCount(
-      ExternalProtocolHandler::kRememberCheckboxMetric, 1 /* true */, 1);
+  EXPECT_TRUE(remember_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::CHECKED_LAUNCH, 1);
@@ -150,12 +131,9 @@
 IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, TestCancel) {
   ShowDialog();
   EXPECT_TRUE(dialog_->Cancel());
-  EXPECT_TRUE(called_);
+  EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
-  EXPECT_TRUE(cancel_);
-  EXPECT_FALSE(dont_block_);
-  histogram_tester_.ExpectBucketCount(
-      ExternalProtocolHandler::kRememberCheckboxMetric, 0 /* false */, 1);
+  EXPECT_FALSE(remember_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
       ExternalProtocolHandler::DONT_LAUNCH, 1);
@@ -166,47 +144,38 @@
   ShowDialog();
   SetChecked(true);
   EXPECT_TRUE(dialog_->Cancel());
-  EXPECT_TRUE(called_);
+  EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
-  EXPECT_TRUE(cancel_);
-  EXPECT_TRUE(dont_block_);
-  histogram_tester_.ExpectBucketCount(
-      ExternalProtocolHandler::kRememberCheckboxMetric, 1 /* true */, 1);
+  EXPECT_FALSE(remember_);
   histogram_tester_.ExpectBucketCount(
       ExternalProtocolHandler::kHandleStateMetric,
-      ExternalProtocolHandler::CHECKED_DONT_LAUNCH, 1);
+      ExternalProtocolHandler::DONT_LAUNCH, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, TestClose) {
-  // Closing the dialog should always call DoCancel() with |dont_block| = false.
+  // Closing the dialog should be the same as canceling, except for histograms.
   ShowDialog();
   EXPECT_TRUE(dialog_->Close());
-  EXPECT_TRUE(called_);
+  EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
-  EXPECT_TRUE(cancel_);
-  EXPECT_FALSE(dont_block_);
-  // No histogram data
-  histogram_tester_.ExpectTotalCount(
-      ExternalProtocolHandler::kRememberCheckboxMetric, 0);
-  histogram_tester_.ExpectTotalCount(
-      ExternalProtocolHandler::kHandleStateMetric, 0);
+  EXPECT_FALSE(remember_);
+  histogram_tester_.ExpectBucketCount(
+      ExternalProtocolHandler::kHandleStateMetric,
+      ExternalProtocolHandler::DONT_LAUNCH, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest,
                        TestCloseWithChecked) {
-  // Closing the dialog should always call DoCancel() with |dont_block| = false.
+  // Closing the dialog should be the same as canceling, except for histograms.
   ShowDialog();
   SetChecked(true);
   EXPECT_TRUE(dialog_->Close());
-  EXPECT_TRUE(called_);
+  EXPECT_FALSE(called_);
   EXPECT_FALSE(accept_);
-  EXPECT_TRUE(cancel_);
-  EXPECT_FALSE(dont_block_);
-  // No histogram data
-  histogram_tester_.ExpectTotalCount(
-      ExternalProtocolHandler::kRememberCheckboxMetric, 0);
-  histogram_tester_.ExpectTotalCount(
-      ExternalProtocolHandler::kHandleStateMetric, 0);
+  EXPECT_FALSE(remember_);
+  histogram_tester_.ExpectBucketCount(
+      ExternalProtocolHandler::kHandleStateMetric,
+      ExternalProtocolHandler::DONT_LAUNCH, 1);
 }
 
 // Invokes a dialog that asks the user if an external application is allowed to
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder.cc b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
index 8c47ad8f..29ac283 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
@@ -144,9 +144,8 @@
 void SystemMenuModelBuilder::AppendTeleportMenu(ui::SimpleMenuModel* model) {
 #if defined(OS_CHROMEOS)
   DCHECK(browser()->window());
-  // If there is no manager, we are not in the proper multi user mode.
   if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
-          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
+      chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_ON)
     return;
 
   // Don't show the menu for incognito windows.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index bdb8769..cb97c42 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -499,12 +499,6 @@
   return render_text;
 }
 
-int OmniboxResultView::GetMatchContentsWidth() const {
-  InitContentsRenderTextIfNecessary();
-  contents_rendertext_->SetDisplayRect(gfx::Rect(gfx::Size(INT_MAX, 0)));
-  return contents_rendertext_->GetContentWidth();
-}
-
 void OmniboxResultView::SetCustomIcon(const gfx::ImageSkia& icon) {
   custom_icon_ = icon;
   SchedulePaint();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index 1fee668..b1c2f981 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -80,9 +80,6 @@
   // class, this is the height of one line of text.
   virtual int GetTextHeight() const;
 
-  // Returns the display width required for the match contents.
-  int GetMatchContentsWidth() const;
-
   // Stores a custom icon as a local data member and schedules a repaint.
   void SetCustomIcon(const gfx::ImageSkia& icon);
 
@@ -220,7 +217,7 @@
   gfx::ImageSkia answer_image_;
 
   // We preserve these RenderTexts so that we won't recreate them on every call
-  // to GetMatchContentsWidth() or OnPaint().
+  // to OnPaint().
   mutable std::unique_ptr<gfx::RenderText> contents_rendertext_;
   mutable std::unique_ptr<gfx::RenderText> description_rendertext_;
   mutable std::unique_ptr<gfx::RenderText> separator_rendertext_;
diff --git a/chrome/browser/ui/views/overlay/OWNERS b/chrome/browser/ui/views/overlay/OWNERS
new file mode 100644
index 0000000..d735a53
--- /dev/null
+++ b/chrome/browser/ui/views/overlay/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/ui/overlay/OWNERS
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
index bb7b504e..2243dce 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -230,6 +230,65 @@
   return button;
 }
 
+// Builds a credential row, adds the given elements to the layout.
+// Releases the unique pointers after adding them to the layout.
+// |password_view_button| is an optional field. If it is a nullptr, a
+// DOUBLE_VIEW_COLUMN_SET will be used instead of TRIPLE_VIEW_COLUMN_SET.
+void BuildCredentialRow(
+    views::GridLayout* layout,
+    std::unique_ptr<views::View> username_field,
+    std::unique_ptr<views::View> password_field,
+    std::unique_ptr<views::ToggleImageButton> password_view_button) {
+  ColumnSetType type =
+      password_view_button ? TRIPLE_VIEW_COLUMN_SET : DOUBLE_VIEW_COLUMN_SET;
+  BuildColumnSet(layout, type);
+  layout->StartRow(0, type);
+  // TODO(https://crbug.com/761767): Remove this workaround once the grid
+  // layout bug is fixed.
+  int username_width = username_field->GetPreferredSize().width();
+  int password_width = password_field->GetPreferredSize().width();
+  int available_width;
+  if (password_view_button) {
+    available_width = ManagePasswordsBubbleView::kDesiredBubbleWidth -
+                      2 * ChromeLayoutProvider::Get()->GetDistanceMetric(
+                              views::DISTANCE_RELATED_CONTROL_HORIZONTAL) -
+                      password_view_button->GetPreferredSize().width();
+  } else {
+    available_width = ManagePasswordsBubbleView::kDesiredBubbleWidth -
+                      ChromeLayoutProvider::Get()->GetDistanceMetric(
+                          views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
+  }
+  if (username_width > available_width && password_width < available_width) {
+    // If username is long and password is short, we limit the length of the
+    // username to the available width and password gets 0.
+    layout->AddView(username_field.release(), 1, 1, views::GridLayout::FILL,
+                    views::GridLayout::FILL, available_width, 0);
+    layout->AddView(password_field.release(), 1, 1, views::GridLayout::FILL,
+                    views::GridLayout::FILL, 0, 0);
+  } else if (username_width < available_width &&
+             password_width > available_width) {
+    // If username is short and password is long, username keeps its
+    // preferred length, and password gets the remaining available width.
+    layout->AddView(username_field.release(), 1, 1, views::GridLayout::FILL,
+                    views::GridLayout::FILL, username_width, 0);
+    layout->AddView(password_field.release(), 1, 1, views::GridLayout::FILL,
+                    views::GridLayout::FILL, available_width - username_width,
+                    0);
+  } else {
+    // If both fields are long or both are short, regular implementation is
+    // kept. For long username and password, fields get equal space. For
+    // shorter ones, they share the existing space.
+    layout->AddView(username_field.release(), 1, 1, views::GridLayout::FILL,
+                    views::GridLayout::FILL, 0, 0);
+    layout->AddView(password_field.release(), 1, 1, views::GridLayout::FILL,
+                    views::GridLayout::FILL, 0, 0);
+  }
+  // The eye icon is also added to the layout if it was passed.
+  if (password_view_button) {
+    layout->AddView(password_view_button.release());
+  }
+}
+
 }  // namespace
 
 // ManagePasswordsBubbleView::AutoSigninView ----------------------------------
@@ -399,15 +458,8 @@
   }
 
   // Credentials row.
-  const ColumnSetType column_type =
-      (base::FeatureList::IsEnabled(
-          password_manager::features::kEnablePasswordSelection))
-          ? TRIPLE_VIEW_COLUMN_SET
-          : DOUBLE_VIEW_COLUMN_SET;
-  BuildColumnSet(layout, column_type);
   if (!parent_->model()->pending_password().username_value.empty() ||
       edit_button_) {
-    layout->StartRow(0, column_type);
     const autofill::PasswordForm* password_form =
         &parent_->model()->pending_password();
     DCHECK(!username_field_);
@@ -419,15 +471,17 @@
     if (!password_field_) {
       password_field_ = GeneratePasswordLabel(*password_form).release();
     }
-    layout->AddView(username_field_);
-    layout->AddView(password_field_);
+
     // Add the eye icon if password selection feature is on.
-    if (column_type == TRIPLE_VIEW_COLUMN_SET) {
-      if (!password_view_button_) {
-        password_view_button_ = GeneratePasswordViewButton(this).release();
-      }
-      layout->AddView(password_view_button_);
+    if (base::FeatureList::IsEnabled(
+            password_manager::features::kEnablePasswordSelection) &&
+        !password_view_button_) {
+      password_view_button_ = GeneratePasswordViewButton(this).release();
     }
+    BuildCredentialRow(
+        layout, std::unique_ptr<views::View>(username_field_),
+        std::unique_ptr<views::View>(password_field_),
+        std::unique_ptr<views::ToggleImageButton>(password_view_button_));
     layout->AddPaddingRow(0,
                           ChromeLayoutProvider::Get()
                               ->GetInsetsMetric(views::INSETS_DIALOG_CONTENTS)
@@ -798,12 +852,10 @@
     layout->StartRow(0, SINGLE_VIEW_COLUMN_SET);
     layout->AddView(new CredentialsSelectionView(parent->model()));
   } else {
-    BuildColumnSet(layout, DOUBLE_VIEW_COLUMN_SET);
-    layout->StartRow(0, DOUBLE_VIEW_COLUMN_SET);
     const autofill::PasswordForm* password_form =
         &parent_->model()->pending_password();
-    layout->AddView(GenerateUsernameLabel(*password_form).release());
-    layout->AddView(GeneratePasswordLabel(*password_form).release());
+    BuildCredentialRow(layout, GenerateUsernameLabel(*password_form),
+                       GeneratePasswordLabel(*password_form), nullptr);
   }
   layout->AddPaddingRow(
       0,
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 3ddcd54..6d88fa75 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -434,7 +434,7 @@
       favicon_hiding_offset_(0),
       should_display_crashed_favicon_(false),
       pulse_animation_(this),
-      crash_icon_animation_(this),
+      crash_icon_animation_(base::MakeUnique<FaviconCrashAnimation>(this)),
       animation_container_(container),
       throbber_(nullptr),
       alert_indicator_button_(nullptr),
@@ -549,13 +549,13 @@
   title_->SetText(title);
 
   if (!data_.IsCrashed()) {
-    crash_icon_animation_.Stop();
+    crash_icon_animation_->Stop();
     SetShouldDisplayCrashedFavicon(false);
     favicon_hiding_offset_ = 0;
   } else if (!should_display_crashed_favicon_ &&
-             !crash_icon_animation_.is_animating()) {
+             !crash_icon_animation_->is_animating()) {
     data_.alert_state = TabAlertState::NONE;
-    crash_icon_animation_.Start();
+    crash_icon_animation_->Start();
   }
 
   if (data_.alert_state != old.alert_state)
@@ -1462,7 +1462,7 @@
     return;
 
   // Extends the area to the bottom when the crash animation is in progress.
-  if (crash_icon_animation_.is_animating())
+  if (crash_icon_animation_->is_animating())
     bounds.set_height(height() - bounds.y());
   SchedulePaintInRect(GetMirroredRect(bounds));
 }
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index e567427f..bbab533 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -327,7 +327,7 @@
   gfx::ThrobAnimation pulse_animation_;
 
   // Crash icon animation (in place of favicon).
-  gfx::LinearAnimation crash_icon_animation_;
+  std::unique_ptr<FaviconCrashAnimation> crash_icon_animation_;
 
   scoped_refptr<gfx::AnimationContainer> animation_container_;
 
diff --git a/chrome/browser/ui/views/try_chrome_dialog.cc b/chrome/browser/ui/views/try_chrome_dialog.cc
index 7b4ce00..c2ba43a 100644
--- a/chrome/browser/ui/views/try_chrome_dialog.cc
+++ b/chrome/browser/ui/views/try_chrome_dialog.cc
@@ -6,6 +6,8 @@
 
 #include <shellapi.h>
 
+#include <utility>
+
 #include "base/logging.h"
 #include "base/strings/string16.h"
 #include "chrome/app/vector_icons/vector_icons.h"
@@ -15,7 +17,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "chrome/installer/util/experiment.h"
-#include "chrome/installer/util/experiment_metrics.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
@@ -119,7 +120,7 @@
 // static
 TryChromeDialog::Result TryChromeDialog::Show(
     size_t group,
-    const ActiveModalDialogListener& listener) {
+    ActiveModalDialogListener listener) {
   if (group >= arraysize(kExperiments)) {
     // This is a test value. We want to make sure we exercise
     // returning this early. See TryChromeDialogBrowserTest test.
@@ -127,7 +128,8 @@
   }
 
   TryChromeDialog dialog(group);
-  return dialog.ShowDialog(listener, DialogType::MODAL, UsageType::FOR_CHROME);
+  return dialog.ShowDialog(std::move(listener), DialogType::MODAL,
+                           UsageType::FOR_CHROME);
 }
 
 TryChromeDialog::TryChromeDialog(size_t group)
@@ -139,7 +141,7 @@
 TryChromeDialog::~TryChromeDialog() {}
 
 TryChromeDialog::Result TryChromeDialog::ShowDialog(
-    const ActiveModalDialogListener& listener,
+    ActiveModalDialogListener listener,
     DialogType dialog_type,
     UsageType usage_type) {
   usage_type_ = usage_type;
@@ -277,18 +279,53 @@
   }
 
   popup_->Show();
-  if (!listener.is_null())
-    listener.Run(popup_->GetNativeView());
 
   if (dialog_type == DialogType::MODAL) {
+    if (listener) {
+      listener.Run(base::Bind(&TryChromeDialog::OnProcessNotification,
+                              base::Unretained(this)));
+    }
     run_loop_.reset(new base::RunLoop);
     run_loop_->Run();
-    if (!listener.is_null())
-      listener.Run(nullptr);
+    if (listener)
+      listener.Run(base::Closure());
   }
+
   return result_;
 }
 
+void TryChromeDialog::CloseDialog(Result result,
+                                  installer::ExperimentMetrics::State state) {
+  // Exit early if somehow a second notification arrives.
+  if (!popup_)
+    return;
+
+  // Record the result of the toast.
+  result_ = result;
+
+  // Update post-action stats.
+  if (usage_type_ == UsageType::FOR_CHROME) {
+    auto lock = storage_.AcquireLock();
+    installer::Experiment experiment;
+    if (lock->LoadExperiment(&experiment)) {
+      base::TimeDelta action_delay = (base::TimeTicks::Now() - time_shown_);
+      experiment.SetActionDelay(action_delay);
+      experiment.SetState(state);
+      lock->StoreExperiment(experiment);
+    }
+  }
+
+  // Close the dialog and quit the loop.
+  popup_->Close();
+  popup_ = nullptr;
+  if (run_loop_)
+    run_loop_->QuitWhenIdle();
+}
+
+void TryChromeDialog::OnProcessNotification() {
+  CloseDialog(OPEN_CHROME_DEFER, installer::ExperimentMetrics::kOtherLaunch);
+}
+
 gfx::Rect TryChromeDialog::ComputePopupBounds(const gfx::Size& size,
                                               bool is_RTL) {
   gfx::Point origin;
@@ -302,37 +339,25 @@
 
 void TryChromeDialog::ButtonPressed(views::Button* sender,
                                     const ui::Event& event) {
-  if (sender->tag() == static_cast<int>(ButtonTag::CLOSE_BUTTON) ||
-      sender->tag() == static_cast<int>(ButtonTag::NO_THANKS_BUTTON)) {
-    result_ = NOT_NOW;
-  } else if (sender->tag() == static_cast<int>(ButtonTag::OK_BUTTON)) {
-    result_ = kExperiments[group_].result;
-  } else {
-    NOTREACHED() << "Unknown button selected.";
+  Result result = NOT_NOW;
+  installer::ExperimentMetrics::State state =
+      installer::ExperimentMetrics::kUninitialized;
+
+  switch (sender->tag()) {
+    case static_cast<int>(ButtonTag::CLOSE_BUTTON):
+      state = installer::ExperimentMetrics::kSelectedClose;
+      break;
+    case static_cast<int>(ButtonTag::OK_BUTTON):
+      result = kExperiments[group_].result;
+      state = installer::ExperimentMetrics::kSelectedOpenChromeAndNoCrash;
+      break;
+    case static_cast<int>(ButtonTag::NO_THANKS_BUTTON):
+      state = installer::ExperimentMetrics::kSelectedNoThanks;
+      break;
+    default:
+      NOTREACHED();
+      break;
   }
 
-  // Update post-action stats.
-  if (usage_type_ == UsageType::FOR_CHROME) {
-    auto lock = storage_.AcquireLock();
-    installer::Experiment experiment;
-    if (lock->LoadExperiment(&experiment)) {
-      base::TimeDelta action_delay = (base::TimeTicks::Now() - time_shown_);
-      experiment.SetActionDelay(action_delay);
-      if (sender->tag() == static_cast<int>(ButtonTag::CLOSE_BUTTON)) {
-        experiment.SetState(installer::ExperimentMetrics::kSelectedClose);
-      } else if (sender->tag() ==
-                 static_cast<int>(ButtonTag::NO_THANKS_BUTTON)) {
-        experiment.SetState(installer::ExperimentMetrics::kSelectedNoThanks);
-      } else {
-        // TODO(skare): Differentiate crash/no-crash/logoff cases.
-        experiment.SetState(
-            installer::ExperimentMetrics::kSelectedOpenChromeAndNoCrash);
-      }
-      lock->StoreExperiment(experiment);
-    }
-  }
-
-  popup_->Close();
-  popup_ = nullptr;
-  run_loop_->QuitWhenIdle();
+  CloseDialog(result, state);
 }
diff --git a/chrome/browser/ui/views/try_chrome_dialog.h b/chrome/browser/ui/views/try_chrome_dialog.h
index 4581eb9e..0f65b05c 100644
--- a/chrome/browser/ui/views/try_chrome_dialog.h
+++ b/chrome/browser/ui/views/try_chrome_dialog.h
@@ -7,15 +7,16 @@
 
 #include <stddef.h>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
+#include "chrome/installer/util/experiment_metrics.h"
 #include "chrome/installer/util/experiment_storage.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/gfx/native_widget_types.h"
 #include "ui/views/controls/button/button.h"
 
 namespace views {
@@ -38,27 +39,29 @@
 // Some variants do not have body text, or only have one button.
 class TryChromeDialog : public views::ButtonListener {
  public:
-  // Receives a handle to the active modal dialog, or NULL when the active
-  // dialog is dismissed.
-  typedef base::Callback<void(gfx::NativeWindow active_dialog)>
-      ActiveModalDialogListener;
+  // Receives a closure to run upon process singleton notification when the
+  // modal dialog is open, or a null closure when the active dialog is
+  // dismissed.
+  typedef base::Callback<void(base::Closure)> ActiveModalDialogListener;
 
   enum Result {
     NOT_NOW,                    // Don't launch chrome. Exit now.
     OPEN_CHROME_WELCOME,        // Launch Chrome to the standard Welcome page.
     OPEN_CHROME_WELCOME_WIN10,  // Launch Chrome to the Win10 Welcome page.
     OPEN_CHROME_DEFAULT,        // Launch Chrome to the default page.
+    OPEN_CHROME_DEFER,          // Launch Chrome on account of a rendezvous,
+                                // deferring to the caller's command line.
   };
 
   // Shows a modal dialog asking the user to give Chrome another try. See
   // above for the possible outcomes of the function.
   // |group| selects what strings to present and what controls are shown.
-  // |listener| will be notified when the dialog becomes active and when it is
-  // dismissed.
+  // |listener| will be provided with a closure when the dialog becomes active
+  // and when it is dismissed.
   // Note that the dialog has no parent and it will position itself in a lower
   // corner of the screen or near the Chrome taskbar button.
   // The dialog does not steal focus and does not have an entry in the taskbar.
-  static Result Show(size_t group, const ActiveModalDialogListener& listener);
+  static Result Show(size_t group, ActiveModalDialogListener listener);
 
  private:
   // Indicates whether the dialog is modal
@@ -86,10 +89,18 @@
   // selection, and is used in testing. This case will always return NOT_NOW.
   // The |usage_type| parameter indicates whether this is being invoked by
   // Chrome or a test.
-  Result ShowDialog(const ActiveModalDialogListener& listener,
+  Result ShowDialog(ActiveModalDialogListener listener,
                     DialogType dialog_type,
                     UsageType usage_type);
 
+  // Concludes the modal interaction by recording |result| and |state|, then
+  // closing the dialog.
+  void CloseDialog(Result result, installer::ExperimentMetrics::State state);
+
+  // Invoked upon notification from another process by way of the process
+  // singleton. Closes the dialog, allowing Chrome startup to resume.
+  void OnProcessNotification();
+
   // Returns a screen rectangle that is fit to show the window. In particular
   // it has the following properties: a) is visible and b) is attached to the
   // bottom of the working area. For LTR machines it returns a left side
diff --git a/chrome/browser/ui/webui/browsing_history_handler.cc b/chrome/browser/ui/webui/browsing_history_handler.cc
index d4158841..c5cc78e5 100644
--- a/chrome/browser/ui/webui/browsing_history_handler.cc
+++ b/chrome/browser/ui/webui/browsing_history_handler.cc
@@ -231,8 +231,7 @@
 }  // namespace
 
 BrowsingHistoryHandler::BrowsingHistoryHandler()
-    : clock_(new base::DefaultClock()),
-      browsing_history_service_(nullptr) {}
+    : clock_(new base::DefaultClock()), browsing_history_service_(nullptr) {}
 
 BrowsingHistoryHandler::~BrowsingHistoryHandler() {}
 
@@ -251,6 +250,10 @@
   web_ui()->RegisterMessageCallback("queryHistory",
       base::Bind(&BrowsingHistoryHandler::HandleQueryHistory,
                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "queryHistoryContinuation",
+      base::Bind(&BrowsingHistoryHandler::HandleQueryHistoryContinuation,
+                 base::Unretained(this)));
   web_ui()->RegisterMessageCallback("removeVisits",
       base::Bind(&BrowsingHistoryHandler::HandleRemoveVisits,
                  base::Unretained(this)));
@@ -263,25 +266,16 @@
 }
 
 void BrowsingHistoryHandler::HandleQueryHistory(const base::ListValue* args) {
-  history::QueryOptions options;
+  query_history_continuation_.Reset();
 
-  // Parse the arguments from JavaScript. There are five required arguments:
+  // Parse the arguments from JavaScript. There are two required arguments:
   // - the text to search for (may be empty)
-  // - the end time for the query. Only results older than this time will be
-  //   returned.
   // - the maximum number of results to return (may be 0, meaning that there
   //   is no maximum).
   base::string16 search_text = ExtractStringValue(args);
 
-  double end_time;
-  if (!args->GetDouble(1, &end_time)) {
-    NOTREACHED() << "Failed to convert argument 1. ";
-    return;
-  }
-  if (end_time)
-    options.end_time = base::Time::FromJsTime(end_time);
-
-  if (!args->GetInteger(2, &options.max_count)) {
+  history::QueryOptions options;
+  if (!args->GetInteger(1, &options.max_count)) {
     NOTREACHED() << "Failed to convert argument 2.";
     return;
   }
@@ -290,6 +284,13 @@
   browsing_history_service_->QueryHistory(search_text, options);
 }
 
+void BrowsingHistoryHandler::HandleQueryHistoryContinuation(
+    const base::ListValue* args) {
+  DCHECK(args->empty());
+  DCHECK(query_history_continuation_);
+  std::move(query_history_continuation_).Run();
+}
+
 void BrowsingHistoryHandler::HandleRemoveVisits(const base::ListValue* args) {
   std::vector<BrowsingHistoryService::HistoryEntry> items_to_remove;
   items_to_remove.reserve(args->GetSize());
@@ -345,7 +346,9 @@
 
 void BrowsingHistoryHandler::OnQueryComplete(
     const std::vector<BrowsingHistoryService::HistoryEntry>& results,
-    const BrowsingHistoryService::QueryResultsInfo& query_results_info) {
+    const BrowsingHistoryService::QueryResultsInfo& query_results_info,
+    base::OnceClosure continuation_closure) {
+  query_history_continuation_ = std::move(continuation_closure);
   Profile* profile = Profile::FromWebUI(web_ui());
   BookmarkModel* bookmark_model =
       BookmarkModelFactory::GetForBrowserContext(profile);
@@ -373,8 +376,7 @@
   // HistoryQuery. Please update it whenever you add or remove any keys in
   // results_info_value_.
   results_info.SetString("term", query_results_info.search_text);
-  results_info.SetBoolean("finished",
-                          query_results_info.reached_beginning_of_local);
+  results_info.SetBoolean("finished", query_results_info.reached_beginning);
   results_info.SetBoolean("hasSyncedResults",
                           query_results_info.has_synced_results);
 
diff --git a/chrome/browser/ui/webui/browsing_history_handler.h b/chrome/browser/ui/webui/browsing_history_handler.h
index 0a06539..0a30097 100644
--- a/chrome/browser/ui/webui/browsing_history_handler.h
+++ b/chrome/browser/ui/webui/browsing_history_handler.h
@@ -12,6 +12,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/time/clock.h"
 #include "base/values.h"
@@ -31,6 +32,9 @@
   // Handler for the "queryHistory" message.
   void HandleQueryHistory(const base::ListValue* args);
 
+  // Handler for the "queryHistoryContinuation" message.
+  void HandleQueryHistoryContinuation(const base::ListValue* args);
+
   // Handler for the "removeVisits" message.
   void HandleRemoveVisits(const base::ListValue* args);
 
@@ -44,7 +48,8 @@
   void OnQueryComplete(
       const std::vector<history::BrowsingHistoryService::HistoryEntry>& results,
       const history::BrowsingHistoryService::QueryResultsInfo&
-          query_results_info) override;
+          query_results_info,
+      base::OnceClosure continuation_closure) override;
   void OnRemoveVisitsComplete() override;
   void OnRemoveVisitsFailed() override;
   void HistoryDeleted() override;
@@ -69,6 +74,8 @@
 
   std::unique_ptr<history::BrowsingHistoryService> browsing_history_service_;
 
+  base::OnceClosure query_history_continuation_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowsingHistoryHandler);
 };
 
diff --git a/chrome/browser/ui/webui/browsing_history_handler_unittest.cc b/chrome/browser/ui/webui/browsing_history_handler_unittest.cc
index bef9231..200dcb04 100644
--- a/chrome/browser/ui/webui/browsing_history_handler_unittest.cc
+++ b/chrome/browser/ui/webui/browsing_history_handler_unittest.cc
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/simple_test_clock.h"
 #include "base/values.h"
@@ -241,27 +242,23 @@
 
 #if !defined(OS_ANDROID)
 TEST_F(BrowsingHistoryHandlerTest, MdTruncatesTitles) {
-  history::URLResult long_result(
-      GURL("http://looooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
+  history::BrowsingHistoryService::HistoryEntry long_url_entry;
+  long_url_entry.url = GURL(
+      "http://loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
       "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
       "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
       "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
       "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
       "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
-      "ngurlislong.com"), base::Time());
-  ASSERT_GT(long_result.url().spec().size(), 300u);
-
-  std::vector<history::URLResult> result_vector;
-  result_vector.push_back(std::move(long_result));
-  history::QueryResults results;
-  results.SetURLResults(std::move(result_vector));
+      "ngurlislong.com");
+  ASSERT_GT(long_url_entry.url.spec().size(), 300U);
 
   BrowsingHistoryHandlerWithWebUIForTesting handler(web_ui());
-  handler.RegisterMessages();  // Needed to create BrowsingHistoryService.
-  web_ui()->ClearTrackedCalls();
+  ASSERT_TRUE(web_ui()->call_data().empty());
 
-  handler.browsing_history_service_->QueryComplete(
-      base::string16(), history::QueryOptions(), &results);
+  handler.OnQueryComplete({long_url_entry},
+                          history::BrowsingHistoryService::QueryResultsInfo(),
+                          base::OnceClosure());
   ASSERT_FALSE(web_ui()->call_data().empty());
 
   const base::ListValue* arg2;
diff --git a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
index 8213ca1..6bb1525 100644
--- a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
@@ -407,9 +407,12 @@
 // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
 // It should be removed by issue 251179.
 void SupervisedUserCreationScreenHandler::HandleGetImages() {
-  std::unique_ptr<base::ListValue> image_urls =
-      default_user_image::GetAsDictionary(false /* all */);
-  CallJS("setDefaultImages", *image_urls);
+  base::DictionaryValue result;
+  result.SetInteger("first", default_user_image::GetFirstDefaultImage());
+  std::unique_ptr<base::ListValue> default_images =
+      default_user_image::GetAsDictionary(true /* all */);
+  result.Set("images", std::move(default_images));
+  CallJS("setDefaultImages", result);
 }
 
 void SupervisedUserCreationScreenHandler::HandlePhotoTaken
diff --git a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
index d86ecdb..8f34f6a7 100644
--- a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
@@ -117,9 +117,12 @@
 
 // TODO(antrim) : It looks more like parameters for "Init" rather than callback.
 void UserImageScreenHandler::HandleGetImages() {
-  std::unique_ptr<base::ListValue> image_urls =
-      default_user_image::GetAsDictionary(false /* all */);
-  CallJS("setDefaultImages", *image_urls);
+  base::DictionaryValue result;
+  result.SetInteger("first", default_user_image::GetFirstDefaultImage());
+  std::unique_ptr<base::ListValue> default_images =
+      default_user_image::GetAsDictionary(true /* all */);
+  result.Set("images", std::move(default_images));
+  CallJS("setDefaultImages", result);
 }
 
 void UserImageScreenHandler::HandleScreenReady() {
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index 855530d..9642a7c 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -48,6 +48,7 @@
                              IDS_POLICY_SHOW_EXPANDED_VALUE);
   source->AddLocalizedString("hideExpandedValue",
                              IDS_POLICY_HIDE_EXPANDED_VALUE);
+  source->AddLocalizedString("policyLearnMore", IDS_POLICY_LEARN_MORE);
   // Add required resources.
 #if !defined(OS_ANDROID)
   source->AddResourcePath("policy_common.css", IDR_POLICY_COMMON_CSS);
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy_ui_browsertest.cc
index fd94cc9..48a7664a 100644
--- a/chrome/browser/ui/webui/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_ui_browsertest.cc
@@ -223,6 +223,9 @@
       "    children = item.getElementsByTagName('span');"
       "    if (children.length == 1)"
       "      item = children[0];"
+      "    children = item.getElementsByClassName('name-link');"
+      "    if (children.length == 1)"
+      "      item = children[0];"
       "    values.push(item.textContent);"
       "  }"
       "  policies.push(values);"
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc
index 71e633b..c5c69de 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -277,7 +277,7 @@
   Browser* browser = signin::GetDesktopBrowser(web_ui());
   DCHECK(browser);
 
-  browser->signin_view_controller()->delegate()->PerformNavigation();
+  browser->signin_view_controller()->PerformNavigation();
 }
 
 void InlineLoginHandler::HandleDialogClose(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
index 06fe6ac..2a10ba6 100644
--- a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
@@ -111,6 +111,35 @@
 
 
 namespace login_ui_test_utils {
+class SigninViewControllerTestUtil {
+ public:
+  static bool TryDismissSyncConfirmationDialog(Browser* browser) {
+#if defined(OS_CHROMEOS)
+    NOTREACHED();
+    return false;
+#else
+    SigninViewController* signin_view_controller =
+        browser->signin_view_controller();
+    DCHECK_NE(signin_view_controller, nullptr);
+    if (!signin_view_controller->ShowsModalDialog())
+      return false;
+    content::WebContents* dialog_web_contents =
+        signin_view_controller->GetModalDialogWebContentsForTesting();
+    DCHECK_NE(dialog_web_contents, nullptr);
+    std::string message;
+    std::string js =
+        "if (document.getElementById('confirmButton') == null) {"
+        "  window.domAutomationController.send('NotFound');"
+        "} else {"
+        "  document.getElementById('confirmButton').click();"
+        "  window.domAutomationController.send('Ok');"
+        "}";
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(dialog_web_contents, js,
+                                                       &message));
+    return message == "Ok";
+#endif
+  }
+};
 
 void WaitUntilUIReady(Browser* browser) {
   std::string message;
@@ -252,38 +281,10 @@
                       signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT);
 }
 
-bool TryDismissSyncConfirmationDialog(Browser* browser) {
-#if defined(OS_CHROMEOS)
-  NOTREACHED();
-  return false;
-#else
-  SigninViewController* signin_view_controller =
-      browser->signin_view_controller();
-  DCHECK_NE(signin_view_controller, nullptr);
-  SigninViewControllerDelegate* delegate = signin_view_controller->delegate();
-  if (delegate == nullptr)
-    return false;
-  content::WebContents* dialog_web_contents =
-      delegate->web_contents_for_testing();
-  DCHECK_NE(dialog_web_contents, nullptr);
-  std::string message;
-  std::string js =
-      "if (document.getElementById('confirmButton') == null) {"
-      "  window.domAutomationController.send('NotFound');"
-      "} else {"
-      "  document.getElementById('confirmButton').click();"
-      "  window.domAutomationController.send('Ok');"
-      "}";
-  EXPECT_TRUE(content::ExecuteScriptAndExtractString(dialog_web_contents, js,
-                                                     &message));
-  return message == "Ok";
-#endif
-}
-
 bool DismissSyncConfirmationDialog(Browser* browser, base::TimeDelta timeout) {
   const base::Time expire_time = base::Time::Now() + timeout;
   while (base::Time::Now() <= expire_time) {
-    if (TryDismissSyncConfirmationDialog(browser))
+    if (SigninViewControllerTestUtil::TryDismissSyncConfirmationDialog(browser))
       return true;
     RunLoopFor(base::TimeDelta::FromMilliseconds(1000));
   }
diff --git a/chrome/browser/ui/webui/signin/signin_dice_internals_handler.cc b/chrome/browser/ui/webui/signin/signin_dice_internals_handler.cc
index 897f0c5e..f5534d09 100644
--- a/chrome/browser/ui/webui/signin/signin_dice_internals_handler.cc
+++ b/chrome/browser/ui/webui/signin/signin_dice_internals_handler.cc
@@ -25,6 +25,10 @@
   web_ui()->RegisterMessageCallback(
       "enableSync", base::Bind(&SigninDiceInternalsHandler::HandleEnableSync,
                                base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      "disableSync", base::Bind(&SigninDiceInternalsHandler::HandleDisableSync,
+                                base::Unretained(this)));
 }
 
 void SigninDiceInternalsHandler::HandleEnableSync(const base::ListValue* args) {
@@ -56,3 +60,16 @@
   new OneClickSigninSyncStarter(profile_, browser, gaia_id, email,
                                 web_ui()->GetWebContents(), callback);
 }
+
+void SigninDiceInternalsHandler::HandleDisableSync(
+    const base::ListValue* args) {
+  SigninManager* signin_manager = SigninManagerFactory::GetForProfile(profile_);
+  if (!signin_manager->IsAuthenticated()) {
+    VLOG(2) << "[Dice] Cannot disable sync as profile is not authenticated";
+    return;
+  }
+
+  VLOG(2) << "[Dice] Sign out.";
+  signin_manager->SignOut(signin_metrics::USER_TUNED_OFF_SYNC_FROM_DICE_UI,
+                          signin_metrics::SignoutDelete::IGNORE_METRIC);
+}
diff --git a/chrome/browser/ui/webui/signin/signin_dice_internals_handler.h b/chrome/browser/ui/webui/signin/signin_dice_internals_handler.h
index b9230a8..7a1166b7 100644
--- a/chrome/browser/ui/webui/signin/signin_dice_internals_handler.h
+++ b/chrome/browser/ui/webui/signin/signin_dice_internals_handler.h
@@ -25,6 +25,9 @@
   // Handler for enable sync event.
   void HandleEnableSync(const base::ListValue* args);
 
+  // Handler for disable sync event.
+  void HandleDisableSync(const base::ListValue* args);
+
   Profile* profile_;
 
   DISALLOW_COPY_AND_ASSIGN(SigninDiceInternalsHandler);
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 76ad565..cd71a00 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -434,16 +434,6 @@
 const base::Feature kUseGoogleLocalNtp{"UseGoogleLocalNtp",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Experiment to use grouped permission infobars which could show and handle
-// multiple permission requests.
-const base::Feature kUseGroupedPermissionInfobars{
-    "UseGroupedPermissionInfobars", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Feature to use the PermissionManager to show prompts for WebRTC permission
-// requests.
-const base::Feature kUsePermissionManagerForMediaRequests{
-    "UsePermissionManagerForMediaRequests", base::FEATURE_ENABLED_BY_DEFAULT};
-
 #if !defined(OS_ANDROID)
 // Enables or disables Voice Search on the local NTP.
 const base::Feature kVoiceSearchOnLocalNtp{"VoiceSearchOnLocalNtp",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 7835026b..5df65816 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -224,10 +224,6 @@
 
 extern const base::Feature kUseGoogleLocalNtp;
 
-extern const base::Feature kUseGroupedPermissionInfobars;
-
-extern const base::Feature kUsePermissionManagerForMediaRequests;
-
 #if !defined(OS_ANDROID)
 extern const base::Feature kVoiceSearchOnLocalNtp;
 #endif
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
index 10c4a5c7..85ef8c5 100644
--- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "components/url_formatter/url_formatter.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/feature_switch.h"
@@ -28,8 +29,6 @@
 namespace extensions {
 namespace {
 
-const char kWwwPrefix[] = "www.";
-
 std::unique_ptr<GURL> CreateManifestURL(const std::string& url) {
   std::unique_ptr<GURL> manifest_url(new GURL(url));
   if (!manifest_url->is_valid() ||
@@ -105,11 +104,9 @@
   base::StringPiece host = url.host_piece();
   // A www. prefix is not informative and thus not worth the limited real estate
   // in the permissions UI.
-  base::StringPiece formatted_host =
-      base::StartsWith(host, kWwwPrefix, base::CompareCase::INSENSITIVE_ASCII)
-          ? host.substr(strlen(kWwwPrefix))
-          : host;
-  return formatted_host.as_string();
+  // TODO(catmullings): Ideally, we wouldn't be using custom code to format URLs
+  // here, since we have a number of methods that do that more universally.
+  return base::UTF16ToUTF8(url_formatter::StripWWW(base::UTF8ToUTF16(host)));
 }
 
 }  // namespace
diff --git a/chrome/common/profiling/memlog_allocator_shim.cc b/chrome/common/profiling/memlog_allocator_shim.cc
index 42cd8a9..ba0502f 100644
--- a/chrome/common/profiling/memlog_allocator_shim.cc
+++ b/chrome/common/profiling/memlog_allocator_shim.cc
@@ -25,17 +25,11 @@
 
 MemlogSenderPipe* g_sender_pipe = nullptr;
 
-#if defined(OS_WIN)
 // Matches the native buffer size on the pipe.
+// On Windows and Linux, the default pipe buffer size is 65536.
+// On macOS, the default pipe buffer size is 16 * 1024, but grows to 64 * 1024
+// for large writes.
 constexpr int kSendBufferSize = 65536;
-#else
-// Writes on Posix greater than PIPE_BUF are not guaranteed to be atomic, but
-// PIPE_BUF is potentially as low as 512, which isn't large enough to accomodate
-// a message with 256 stack frames. Instead, we use a large value [artifically
-// chosen to match that of Windows], and make the Send() method of the
-// MemlogSenderPipe a critical section.
-constexpr int kSendBufferSize = 65536;
-#endif
 
 // Prime since this is used like a hash table. Numbers of this magnitude seemed
 // to provide sufficient parallelism to avoid lock overhead in ad-hoc testing.
diff --git a/chrome/common/profiling/memlog_sender_pipe_posix.cc b/chrome/common/profiling/memlog_sender_pipe_posix.cc
index b3b1e8b..d6c777b6 100644
--- a/chrome/common/profiling/memlog_sender_pipe_posix.cc
+++ b/chrome/common/profiling/memlog_sender_pipe_posix.cc
@@ -26,7 +26,7 @@
 
 bool MemlogSenderPipe::Send(const void* data, size_t sz) {
   base::AutoLock lock(lock_);
-  return mojo::edk::PlatformChannelWrite(handle_.get(), data, sz);
+  return mojo::edk::PlatformChannelWrite(handle_.get(), data, sz) != -1;
 }
 
 }  // namespace profiling
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index a41ff974e..452d6237 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -102,8 +102,7 @@
 # The bot setup is to build stable, unstable, and beta packages for the current
 # build. Then a later step picks up the package corresponding to what the
 # current build is supposed to be. This is wasteful since one build will only
-# be one of these. This build file also has targets for trunk and possibly asan
-# installers.
+# be one of these.
 #
 # TODO it would be much nicer to have a build variable so the bot can tell us
 # what the current build should be, so we only have to make one .deb/.rpm pair.
@@ -398,14 +397,3 @@
 linux_package("unstable") {
   channel = "unstable"
 }
-
-# Other packages that we support that aren't included in the default "linux"
-# target.
-linux_package("trunk") {
-  channel = "trunk"
-}
-if (is_asan) {
-  linux_package("asan") {
-    channel = "asan"
-  }
-}
diff --git a/chrome/installer/linux/debian/build.sh b/chrome/installer/linux/debian/build.sh
index 7aa9c7c3..357ead7 100755
--- a/chrome/installer/linux/debian/build.sh
+++ b/chrome/installer/linux/debian/build.sh
@@ -135,11 +135,11 @@
 }
 
 usage() {
-  echo "usage: $(basename $0) [-a target_arch] [-b 'dir'] [-c channel]"
+  echo "usage: $(basename $0) [-a target_arch] [-b 'dir'] -c channel"
   echo "                      -d branding [-f] [-o 'dir'] -s 'dir'"
   echo "-a arch     package architecture (ia32 or x64)"
   echo "-b dir      build input directory    [${BUILDDIR}]"
-  echo "-c channel  the package channel (trunk, asan, unstable, beta, stable)"
+  echo "-c channel  the package channel (unstable, beta, stable)"
   echo "-d brand    either chromium or google_chrome"
   echo "-f          indicates that this is an official build"
   echo "-h          this help message"
@@ -162,12 +162,6 @@
       CHANNEL=beta
       RELEASENOTES="http://googlechromereleases.blogspot.com/search/label/Beta%20updates"
       ;;
-    trunk|asan )
-      # Setting this to empty will prevent it from updating any existing configs
-      # from release packages.
-      REPOCONFIG=""
-      RELEASENOTES="http://googlechromereleases.blogspot.com/"
-      ;;
     * )
       echo
       echo "ERROR: '$CHANNEL' is not a valid channel type."
@@ -227,7 +221,6 @@
 
 SCRIPTDIR=$(readlink -f "$(dirname "$0")")
 OUTPUTDIR="${PWD}"
-CHANNEL="trunk"
 # Default target architecture to same as build host.
 if [ "$(uname -m)" = "x86_64" ]; then
   TARGETARCH="x64"
diff --git a/chrome/installer/linux/rpm/build.sh b/chrome/installer/linux/rpm/build.sh
index e0b19e3..90f0dbf 100755
--- a/chrome/installer/linux/rpm/build.sh
+++ b/chrome/installer/linux/rpm/build.sh
@@ -15,8 +15,8 @@
 
 gen_spec() {
   rm -f "${SPEC}"
-  # Trunk packages need to install to a custom path so they don't conflict with
-  # release channel packages.
+  # Different channels need to install to different locations so they
+  # don't conflict with each other.
   local PACKAGE_FILENAME="${PACKAGE}-${CHANNEL}"
   if [ "$CHANNEL" != "stable" ]; then
     local INSTALLDIR="${INSTALLDIR}-${CHANNEL}"
@@ -218,11 +218,11 @@
 }
 
 usage() {
-  echo "usage: $(basename $0) [-a target_arch] [-b 'dir'] [-c channel]"
+  echo "usage: $(basename $0) [-a target_arch] [-b 'dir'] -c channel"
   echo "                      -d branding [-f] [-o 'dir']"
   echo "-a arch     package architecture (ia32 or x64)"
   echo "-b dir      build input directory    [${BUILDDIR}]"
-  echo "-c channel  the package channel (trunk, asan, unstable, beta, stable)"
+  echo "-c channel  the package channel (unstable, beta, stable)"
   echo "-d brand    either chromium or google_chrome"
   echo "-f          indicates that this is an official build"
   echo "-h          this help message"
@@ -247,15 +247,6 @@
       # TODO(phajdan.jr): Remove REPLACES completely.
       REPLACES="dummy"
       ;;
-    trunk|asan )
-      # This is a special package, mostly for development testing, so don't make
-      # it replace any installed release packages.
-      # TODO(phajdan.jr): Remove REPLACES completely.
-      REPLACES="dummy"
-      # Setting this to empty will prevent it from updating any existing configs
-      # from release packages.
-      REPOCONFIG=""
-      ;;
     * )
       echo
       echo "ERROR: '$CHANNEL' is not a valid channel type."
@@ -313,7 +304,6 @@
 
 SCRIPTDIR=$(readlink -f "$(dirname "$0")")
 OUTPUTDIR="${PWD}"
-CHANNEL="trunk"
 # Default target architecture to same as build host.
 if [ "$(uname -m)" = "x86_64" ]; then
   TARGETARCH="x64"
diff --git a/chrome/installer/util/experiment_metrics.h b/chrome/installer/util/experiment_metrics.h
index f18e0b8..f1652fc 100644
--- a/chrome/installer/util/experiment_metrics.h
+++ b/chrome/installer/util/experiment_metrics.h
@@ -73,6 +73,9 @@
     // User logged off (gracefully) without interacting with toast.
     kUserLogOff = 15,
 
+    // Another Chrome launch closed the toast.
+    kOtherLaunch = 16,
+
     NUM_STATES
   };
 
diff --git a/chrome/installer/util/experiment_storage.cc b/chrome/installer/util/experiment_storage.cc
index 22155e7..28031f6e 100644
--- a/chrome/installer/util/experiment_storage.cc
+++ b/chrome/installer/util/experiment_storage.cc
@@ -322,7 +322,8 @@
       ReadUint64Bits(metrics_value, ExperimentMetrics::kToastLocationBits,
                      kToastLocationLowestBit));
 
-  static_assert(ExperimentMetrics::State::NUM_STATES <= (1 << 4),
+  static_assert(ExperimentMetrics::State::NUM_STATES <=
+                    (1 << ExperimentMetrics::kStateBits),
                 "Too many states for ExperimentMetrics encoding.");
   result.state = static_cast<ExperimentMetrics::State>(ReadUint64Bits(
       metrics_value, ExperimentMetrics::kStateBits, kStateLowestBit));
@@ -361,7 +362,8 @@
                 kToastCountLowestBit, &metrics_value);
   SetUint64Bits(metrics.toast_location, ExperimentMetrics::kToastLocationBits,
                 kToastLocationLowestBit, &metrics_value);
-  static_assert(ExperimentMetrics::State::NUM_STATES <= (1 << 4),
+  static_assert(ExperimentMetrics::State::NUM_STATES <=
+                    (1 << ExperimentMetrics::kStateBits),
                 "Too many states for ExperimentMetrics encoding.");
   SetUint64Bits(metrics.state, ExperimentMetrics::kStateBits, kStateLowestBit,
                 &metrics_value);
diff --git a/chrome/profiling/allocation_tracker.cc b/chrome/profiling/allocation_tracker.cc
index 3a67fac..bce03f7 100644
--- a/chrome/profiling/allocation_tracker.cc
+++ b/chrome/profiling/allocation_tracker.cc
@@ -5,6 +5,7 @@
 #include "chrome/profiling/allocation_tracker.h"
 
 #include "base/callback.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/profiling/backtrace_storage.h"
 
 namespace profiling {
@@ -41,8 +42,8 @@
 }
 
 void AllocationTracker::OnComplete() {
-  std::move(complete_callback_).Run();
-  // Danger: object may be deleted now.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                std::move(complete_callback_));
 }
 
 }  // namespace profiling
diff --git a/chrome/profiling/json_exporter.cc b/chrome/profiling/json_exporter.cc
index b9dde7cb..02a25b1 100644
--- a/chrome/profiling/json_exporter.cc
+++ b/chrome/profiling/json_exporter.cc
@@ -295,29 +295,71 @@
   out << R"("level_of_detail": "detailed")"
       << ",\n";
 
+  // Aggregate allocations. Allocations of the same size and stack get grouped.
+  UniqueAllocCount alloc_counts;
+  for (const auto& alloc : event_set) {
+    UniqueAlloc unique_alloc(alloc.backtrace(), alloc.size());
+    alloc_counts[unique_alloc]++;
+  }
+
+  size_t total_size = 0;
+  size_t total_count = 0;
+  // Filter irrelevant allocations.
+  for (auto alloc = alloc_counts.begin(); alloc != alloc_counts.end();) {
+    size_t alloc_count = alloc->second;
+    size_t alloc_size = alloc->first.size;
+    size_t alloc_total_size = alloc_size * alloc_count;
+    total_size += alloc_total_size;
+    total_count += alloc_count;
+    if (alloc_total_size < min_size_threshold &&
+        alloc_count < min_count_threshold) {
+      alloc = alloc_counts.erase(alloc);
+    } else {
+      ++alloc;
+    }
+  }
+
   // Write the top-level allocators section. This section is used by the tracing
   // UI to show a small summary for each allocator. It's necessary as a
   // placeholder to allow the stack-viewing UI to be shown.
   // TODO: Fill in placeholders for "value". https://crbug.com/758434.
-  out << R"(
+  const char* allocators_raw = R"(
   "allocators": {
     "malloc": {
       "attrs": {
         "virtual_size": {
           "type": "scalar",
           "units": "bytes",
-          "value": "1234"
+          "value": "%zx"
         },
         "size": {
           "type": "scalar",
           "units": "bytes",
-          "value": "1234"
+          "value": "%zx"
+        }
+      }
+    },
+    "malloc/allocated_objects": {
+      "attrs": {
+        "shim_allocated_objects_count": {
+          "type": "scalar",
+          "units": "objects",
+          "value": "%zx"
+        },
+        "shim_allocated_objects_size": {
+          "type": "scalar",
+          "units": "bytes",
+          "value": "%zx"
         }
       }
     }
   },
   )";
 
+  std::string allocators = base::StringPrintf(
+      allocators_raw, total_size, total_size, total_count, total_size);
+  out << allocators;
+
   WriteHeapsV2Header(out);
 
   // Output Heaps_V2 format version. Currently "1" is the only valid value.
@@ -328,26 +370,6 @@
   // We hardcode one type, "[unknown]".
   size_t type_string_id = AddOrGetString("[unknown]", &string_table);
 
-  // Aggregate allocations. Allocations of the same size and stack get grouped.
-  UniqueAllocCount alloc_counts;
-  for (const auto& alloc : event_set) {
-    UniqueAlloc unique_alloc(alloc.backtrace(), alloc.size());
-    alloc_counts[unique_alloc]++;
-  }
-
-  // Filter irrelevant allocations.
-  for (auto alloc = alloc_counts.begin(); alloc != alloc_counts.end();) {
-    size_t alloc_count = alloc->second;
-    size_t alloc_size = alloc->first.size;
-    size_t alloc_total_size = alloc_size * alloc_count;
-    if (alloc_total_size < min_size_threshold &&
-        alloc_count < min_count_threshold) {
-      alloc = alloc_counts.erase(alloc);
-    } else {
-      ++alloc;
-    }
-  }
-
   // Find all backtraces referenced by the set and not filtered. The backtrace
   // storage will contain more stacks than we want to write out (it will refer
   // to all processes, while we're only writing one). So do those only on
diff --git a/chrome/profiling/memlog_connection_manager.cc b/chrome/profiling/memlog_connection_manager.cc
index 4e1b043..d4605d8 100644
--- a/chrome/profiling/memlog_connection_manager.cc
+++ b/chrome/profiling/memlog_connection_manager.cc
@@ -26,8 +26,6 @@
 namespace {
 const size_t kMinSizeThreshold = 16 * 1024;
 const size_t kMinCountThreshold = 1024;
-const size_t kMinSizeThresholdForTracing = 0;
-const size_t kMinCountThresholdForTracing = 0;
 }  // namespace
 
 struct MemlogConnectionManager::Connection {
@@ -177,8 +175,8 @@
   Connection* connection = it->second.get();
   std::ostringstream oss;
   ExportMemoryMapsAndV2StackTraceToJSON(connection->tracker.live_allocs(), maps,
-                                        oss, kMinSizeThresholdForTracing,
-                                        kMinCountThresholdForTracing);
+                                        oss, kMinSizeThreshold,
+                                        kMinCountThreshold);
   std::string reply = oss.str();
 
   mojo::ScopedSharedBufferHandle buffer =
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index da4353c..143a19f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1406,6 +1406,7 @@
       "../browser/printing/print_browsertest.cc",
       "../browser/printing/print_preview_dialog_controller_browsertest.cc",
       "../browser/printing/print_preview_pdf_generated_browsertest.cc",
+      "../browser/printing/pwg_raster_converter_browsertest.cc",
       "../browser/process_singleton_browsertest.cc",
       "../browser/profile_resetter/profile_resetter_browsertest.cc",
       "../browser/profiles/host_zoom_map_browsertest.cc",
@@ -3111,6 +3112,7 @@
     "../browser/conflicts/module_info_util_win_unittest.cc",
     "../browser/conflicts/module_info_win_unittest.cc",
     "../browser/conflicts/module_inspector_win_unittest.cc",
+    "../browser/conflicts/module_list_manager_win_unittest.cc",
     "../browser/content_settings/content_settings_default_provider_unittest.cc",
     "../browser/content_settings/content_settings_mock_observer.cc",
     "../browser/content_settings/content_settings_mock_observer.h",
@@ -3135,7 +3137,6 @@
     "../browser/download/download_path_reservation_tracker_unittest.cc",
     "../browser/download/download_prefs_unittest.cc",
     "../browser/download/download_query_unittest.cc",
-    "../browser/download/download_request_infobar_delegate_unittest.cc",
     "../browser/download/download_request_limiter_unittest.cc",
     "../browser/download/download_resource_throttle_unittest.cc",
     "../browser/download/download_status_updater_unittest.cc",
@@ -3182,6 +3183,7 @@
     "../browser/media/media_engagement_contents_observer_unittest.cc",
     "../browser/media/media_engagement_score_unittest.cc",
     "../browser/media/media_engagement_service_unittest.cc",
+    "../browser/media/media_storage_id_salt_unittest.cc",
     "../browser/media/midi_permission_context_unittest.cc",
     "../browser/media/midi_sysex_permission_context_unittest.cc",
     "../browser/media/router/browser_presentation_connection_proxy_unittest.cc",
@@ -3320,6 +3322,7 @@
     "../browser/profiles/profile_info_cache_unittest.h",
     "../browser/profiles/profile_manager_unittest.cc",
     "../browser/profiles/profile_shortcut_manager_unittest_win.cc",
+    "../browser/profiling_host/background_profiling_triggers_unittest.cc",
     "../browser/push_messaging/push_messaging_app_identifier_unittest.cc",
     "../browser/push_messaging/push_messaging_notification_manager_unittest.cc",
     "../browser/push_messaging/push_messaging_service_unittest.cc",
@@ -3622,7 +3625,6 @@
       "../browser/password_manager/account_chooser_dialog_android_unittest.cc",
       "../browser/password_manager/auto_signin_first_run_dialog_android_unittest.cc",
       "../browser/password_manager/save_password_infobar_delegate_android_unittest.cc",
-      "../browser/permissions/permission_queue_controller_unittest.cc",
     ]
     deps += [
       ":unit_tests_java",
@@ -3694,6 +3696,7 @@
       "../browser/search/instant_unittest_base.h",
       "../browser/search/one_google_bar/one_google_bar_fetcher_impl_unittest.cc",
       "../browser/search/one_google_bar/one_google_bar_service_unittest.cc",
+      "../browser/search/search_engine_base_url_tracker_unittest.cc",
       "../browser/search/search_unittest.cc",
       "../browser/sessions/persistent_tab_restore_service_unittest.cc",
       "../browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc",
@@ -3821,8 +3824,6 @@
       "../browser/media/router/discovery/discovery_network_list_unittest.cc",
       "../browser/media/router/discovery/discovery_network_monitor_unittest.cc",
     ]
-    sources -=
-        [ "../browser/download/download_request_infobar_delegate_unittest.cc" ]
     deps += [
       "//components/signin/core/common:signin_features",
       "//ipc",
@@ -3899,6 +3900,7 @@
 
   if ((is_linux && !is_chromeos) || is_win) {
     sources += [
+      "../browser/feature_engagement/bookmark/bookmark_tracker_unittest.cc",
       "../browser/feature_engagement/feature_tracker_unittest.cc",
       "../browser/feature_engagement/new_tab/new_tab_tracker_unittest.cc",
       "../browser/feature_engagement/session_duration_updater_unittest.cc",
@@ -4722,7 +4724,7 @@
         "../browser/ui/cocoa/location_bar/keyword_hint_decoration_unittest.mm",
         "../browser/ui/cocoa/location_bar/location_bar_view_mac_unittest.mm",
         "../browser/ui/cocoa/location_bar/manage_passwords_decoration_unittest.mm",
-        "../browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm",
+        "../browser/ui/cocoa/location_bar/page_info_bubble_decoration_unittest.mm",
         "../browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm",
         "../browser/ui/cocoa/location_bar/zoom_decoration_unittest.mm",
         "../browser/ui/cocoa/md_hover_button_unittest.mm",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index ae0de22..a3567b70 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -99,6 +99,7 @@
     "//third_party/android_tools:android_support_v7_recyclerview_java",
     "//third_party/jsr-305:jsr_305_javalib",
     "//third_party/junit",
+    "//third_party/ub-uiautomator:ub_uiautomator_java",
     "//ui/android:ui_java",
     "//ui/android:ui_java_test_support",
   ]
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestRule.java
index e2002ca..17ec1ac 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/BottomSheetTestRule.java
@@ -4,10 +4,13 @@
 
 package org.chromium.chrome.test;
 
+import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 import static org.chromium.chrome.browser.ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE;
 import static org.chromium.chrome.test.BottomSheetTestRule.ENABLE_CHROME_HOME;
 import static org.chromium.chrome.test.ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG;
 
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
 import android.support.v7.widget.RecyclerView;
 
 import org.chromium.base.ThreadUtils;
@@ -96,10 +99,10 @@
     private Observer mObserver;
 
     /** A handle to the bottom sheet. */
-    private BottomSheet mBottomSheet;
+    private BottomSheet mSheet;
 
     /** A handle to the {@link BottomSheetContentController}. */
-    private BottomSheetContentController mBottomSheetContentController;
+    private BottomSheetContentController mSheetContentController;
 
     private boolean mOldChromeHomeFlagValue;
 
@@ -126,11 +129,11 @@
                 ((RecyclerView) getBottomSheetContent().getContentView().findViewById(
                         R.id.recycler_view)));
 
-        mBottomSheet = getActivity().getBottomSheet();
-        mBottomSheetContentController = getActivity().getBottomSheetContentController();
+        mSheet = getActivity().getBottomSheet();
+        mSheetContentController = getActivity().getBottomSheetContentController();
 
         mObserver = new Observer();
-        mBottomSheet.addObserver(mObserver);
+        mSheet.addObserver(mObserver);
     }
 
     @Override
@@ -155,11 +158,11 @@
     }
 
     public BottomSheet getBottomSheet() {
-        return mBottomSheet;
+        return mSheet;
     }
 
     public BottomSheetContentController getBottomSheetContentController() {
-        return mBottomSheetContentController;
+        return mSheetContentController;
     }
 
     /**
@@ -168,13 +171,8 @@
      * @param state   The state to set the sheet to.
      * @param animate If the sheet should animate to the provided state.
      */
-    public void setSheetState(final int state, final boolean animate) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mBottomSheet.setSheetState(state, animate);
-            }
-        });
+    public void setSheetState(int state, boolean animate) {
+        ThreadUtils.runOnUiThreadBlocking(() -> mSheet.setSheetState(state, animate));
     }
 
     /**
@@ -182,13 +180,8 @@
      *
      * @param offset The offset from the bottom that the sheet should be.
      */
-    public void setSheetOffsetFromBottom(final float offset) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mBottomSheet.setSheetOffsetFromBottomForTesting(offset);
-            }
-        });
+    public void setSheetOffsetFromBottom(float offset) {
+        ThreadUtils.runOnUiThreadBlocking(() -> mSheet.setSheetOffsetFromBottomForTesting(offset));
     }
 
     public BottomSheetContent getBottomSheetContent() {
@@ -199,12 +192,17 @@
      * @param itemId The id of the MenuItem corresponding to the {@link BottomSheetContent} to
      *               select.
      */
-    public void selectBottomSheetContent(final int itemId) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mBottomSheetContentController.selectItem(itemId);
-            }
-        });
+    public void selectBottomSheetContent(int itemId) {
+        ThreadUtils.runOnUiThreadBlocking(() -> mSheetContentController.selectItem(itemId));
+    }
+
+    /**
+     * Wait for an update to start and finish.
+     */
+    public static void waitForWindowUpdates() {
+        final long maxWindowUpdateTimeMs = scaleTimeout(1000);
+        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        device.waitForWindowUpdate(null, maxWindowUpdateTimeMs);
+        device.waitForIdle(maxWindowUpdateTimeMs);
     }
 }
diff --git a/chrome/test/chromedriver/BUILD.gn b/chrome/test/chromedriver/BUILD.gn
index e8dd5e92..7e92977 100644
--- a/chrome/test/chromedriver/BUILD.gn
+++ b/chrome/test/chromedriver/BUILD.gn
@@ -244,9 +244,7 @@
     "key_converter.h",
     "keycode_text_conversion.h",
     "keycode_text_conversion_mac.mm",
-    "keycode_text_conversion_ozone.cc",
     "keycode_text_conversion_win.cc",
-    "keycode_text_conversion_x.cc",
     "logging.cc",
     "logging.h",
     "performance_logger.cc",
@@ -270,12 +268,13 @@
   # Also compile the generated version files.
   sources += get_target_outputs(":embed_version_in_cpp")
 
-  # These aren't automatically filtered out.
-  if (!use_x11) {
-    sources -= [ "keycode_text_conversion_x.cc" ]
+  if (use_x11) {
+    sources += [ "keycode_text_conversion_x.cc" ]
   }
-  if (!use_ozone && !use_x11) {
-    sources -= [ "keycode_text_conversion_ozone.cc" ]
+
+  # The X11 implementation uses part of Ozone implementation.
+  if (use_ozone || use_x11) {
+    sources += [ "keycode_text_conversion_ozone.cc" ]
   }
 
   deps = [
diff --git a/chrome/test/data/apptest/basic.html b/chrome/test/data/apptest/basic.html
index 606cc956..0c4aead 100644
--- a/chrome/test/data/apptest/basic.html
+++ b/chrome/test/data/apptest/basic.html
@@ -23,7 +23,7 @@
       /* Adds an event with the given name to the AutomationEventQueue. */
       function raiseEvent(str) {
         if (window.domAutomationController) {
-          window.domAutomationController.sendWithId(4444, str);
+          window.domAutomationController.send(4444, str);
         }
       }
 
diff --git a/chrome/test/data/chromeos/oobe_webui_browsertest.js b/chrome/test/data/chromeos/oobe_webui_browsertest.js
index e36a80c0..dcbe7a9 100644
--- a/chrome/test/data/chromeos/oobe_webui_browsertest.js
+++ b/chrome/test/data/chromeos/oobe_webui_browsertest.js
@@ -182,8 +182,9 @@
       {'id'   : 'supervised-user-creation',
        'data' : createOobeWebUITestSupervisedManagerData()});
   $('supervised-user-creation').setDefaultImages(
-      [{'url': 'chrome://nothing/', 'title': 'None'},
-       {'url': 'chrome://nothing/', 'title': 'None'}]);
+      {'first' : 0,
+       'images' : [{'url': 'chrome://nothing/', 'title': 'None'},
+                   {'url': 'chrome://nothing/', 'title': 'None'}]});
   $('supervised-user-creation').setVisiblePage_('username');
 });
 
diff --git a/chrome/test/data/extensions/api_test/filtered_events/manifest.json b/chrome/test/data/extensions/api_test/filtered_events/manifest.json
deleted file mode 100644
index 73918bf..0000000
--- a/chrome/test/data/extensions/api_test/filtered_events/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-   "name": "filtered events apitest",
-   "description": "filtered events extension",
-   "version": "0.1",
-   "manifest_version": 2,
-   "background": {
-     "scripts": ["background.js"],
-     "persistent": false
-   },
-   "permissions": [ "webNavigation", "tabs" ]
-}
diff --git a/chrome/test/data/instant_extended.html b/chrome/test/data/instant_extended.html
index 2fd442c..748b8cc3 100644
--- a/chrome/test/data/instant_extended.html
+++ b/chrome/test/data/instant_extended.html
@@ -4,13 +4,10 @@
 
 var apiHandle;
 var newTabPageHandle;
-var suggestion;
 var onMostVisitedChangedCalls = 0;
 var mostVisitedItemsCount = 0;
 var firstMostVisitedItemId = 0;
-var submitCount = 0;
 var onFocusChangedCalls = 0;
-var prefetchQuery = '';
 var isFocused = false;
 var onvisibilitycalls = 0;
 var onThemeChangedCalls = 0;
@@ -33,11 +30,6 @@
   return null;
 }
 
-function handleSubmit() {
-  location.hash = 'q=' + encodeURIComponent(apiHandle.value);
-  submitCount++;
-}
-
 function handleMostVisitedChange() {
   onMostVisitedChangedCalls++;
   var items = newTabPageHandle.mostVisited;
@@ -56,10 +48,6 @@
   isFocused = apiHandle.isFocused;
 }
 
-function handleSuggestionChange() {
-  prefetchQuery = getApiHandle().suggestion.text;
-}
-
 function handleThemeChange() {
   onThemeChangedCalls++;
 }
@@ -69,9 +57,7 @@
   if (!apiHandle)
     return;
 
-  apiHandle.onsubmit = handleSubmit;
   apiHandle.onfocuschange = handleFocusChange;
-  apiHandle.onsuggestionchange = handleSuggestionChange;
 
   newTabPageHandle = getNewTabPageHandle();
   newTabPageHandle.onmostvisitedchange = handleMostVisitedChange;
diff --git a/chrome/test/data/instant_extended_ntp.html b/chrome/test/data/instant_extended_ntp.html
index 2fd442c..110af83 100644
--- a/chrome/test/data/instant_extended_ntp.html
+++ b/chrome/test/data/instant_extended_ntp.html
@@ -4,13 +4,10 @@
 
 var apiHandle;
 var newTabPageHandle;
-var suggestion;
 var onMostVisitedChangedCalls = 0;
 var mostVisitedItemsCount = 0;
 var firstMostVisitedItemId = 0;
-var submitCount = 0;
 var onFocusChangedCalls = 0;
-var prefetchQuery = '';
 var isFocused = false;
 var onvisibilitycalls = 0;
 var onThemeChangedCalls = 0;
@@ -56,10 +53,6 @@
   isFocused = apiHandle.isFocused;
 }
 
-function handleSuggestionChange() {
-  prefetchQuery = getApiHandle().suggestion.text;
-}
-
 function handleThemeChange() {
   onThemeChangedCalls++;
 }
@@ -69,9 +62,7 @@
   if (!apiHandle)
     return;
 
-  apiHandle.onsubmit = handleSubmit;
   apiHandle.onfocuschange = handleFocusChange;
-  apiHandle.onsuggestionchange = handleSuggestionChange;
 
   newTabPageHandle = getNewTabPageHandle();
   newTabPageHandle.onmostvisitedchange = handleMostVisitedChange;
diff --git a/chrome/test/data/media/bigbuck-player.html b/chrome/test/data/media/bigbuck-player.html
new file mode 100644
index 0000000..e35aba565
--- /dev/null
+++ b/chrome/test/data/media/bigbuck-player.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Big Buck Test</title>
+  <meta name=viewport content='width=device-width initial-scale=1.0'>
+</head>
+<body>
+  <video controls id=video src=bigbuck.webm></video>
+  <button id=fullscreen>fullscreen</button>
+  <iframe id=iframe></iframe>
+</body>
+<script>
+  document.getElementById('fullscreen').addEventListener('click', _ => {
+    document.getElementById('video').webkitRequestFullscreen();
+  });
+</script>
+</html>
diff --git a/chrome/test/data/media/bigbuck.webm b/chrome/test/data/media/bigbuck.webm
new file mode 100644
index 0000000..6378129
--- /dev/null
+++ b/chrome/test/data/media/bigbuck.webm
Binary files differ
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 3627a09..3308998 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -2547,7 +2547,7 @@
           { "policy": { "ScreenMagnifierType": 1 } }
         ]
       },
-      { "pref": "settings.a11y.screen_magnifier_type2" }
+      { "pref": "settings.a11y.screen_magnifier" }
     ]
   },
 
diff --git a/chrome/test/data/printing/pdf_to_pwg_raster_test.pdf b/chrome/test/data/printing/pdf_to_pwg_raster_test.pdf
new file mode 100644
index 0000000..9bddc46
--- /dev/null
+++ b/chrome/test/data/printing/pdf_to_pwg_raster_test.pdf
Binary files differ
diff --git a/chrome/test/data/printing/pdf_to_pwg_raster_test.pwg b/chrome/test/data/printing/pdf_to_pwg_raster_test.pwg
new file mode 100644
index 0000000..f9c5b68
--- /dev/null
+++ b/chrome/test/data/printing/pdf_to_pwg_raster_test.pwg
Binary files differ
diff --git a/chrome/test/data/printing/pdf_to_pwg_raster_test_32.pwg b/chrome/test/data/printing/pdf_to_pwg_raster_test_32.pwg
new file mode 100644
index 0000000..cc3be9c5
--- /dev/null
+++ b/chrome/test/data/printing/pdf_to_pwg_raster_test_32.pwg
Binary files differ
diff --git a/chrome/test/data/webrtc/peerconnection_rtp.js b/chrome/test/data/webrtc/peerconnection_rtp.js
index 7f4e2ebe..d7f23433 100644
--- a/chrome/test/data/webrtc/peerconnection_rtp.js
+++ b/chrome/test/data/webrtc/peerconnection_rtp.js
@@ -275,6 +275,70 @@
     });
 }
 
+function switchRemoteStreamWithoutWaitingForPromisesToResolve() {
+  let pc = new RTCPeerConnection();
+  let trackEventsFired = 0;
+  let streamEventsFired = 0;
+  pc.ontrack = (e) => {
+    ++trackEventsFired;
+    if (trackEventsFired == 1) {
+      if (e.track.id != 'track0')
+        throw failTest('Unexpected track id in first track event.');
+      if (e.receiver.track != e.track)
+        throw failTest('Unexpected receiver.track in first track event.');
+      if (e.streams[0].id != 'stream0')
+        throw failTest('Unexpected stream id in first track event.');
+      // Because we did not wait for promises to resolve before calling
+      // |setRemoteDescription| a second time, it may or may not have had an
+      // effect here. This is inherently racey and we have to check if the
+      // stream contains the track.
+      if (e.streams[0].getTracks().length != 0) {
+        if (e.streams[0].getTracks()[0] != e.track)
+          throw failTest('Unexpected track in stream in first track event.');
+      }
+    } else if (trackEventsFired == 2) {
+      if (e.track.id != 'track1')
+        throw failTest('Unexpected track id in second track event.');
+      if (e.receiver.track != e.track)
+        throw failTest('Unexpected receiver.track in second track event.');
+      if (e.streams[0].id != 'stream1')
+        throw failTest('Unexpected stream id in second track event.');
+      if (e.streams[0].getTracks()[0] != e.track)
+        throw failTest('The track should belong to the stream in the second ' +
+                       'track event.');
+      if (streamEventsFired != trackEventsFired)
+        throw failTest('All stream events should already have fired.');
+      returnToTest('ok');
+    }
+  };
+  pc.onaddstream = (e) => {
+    ++streamEventsFired;
+    if (streamEventsFired == 1) {
+      if (e.stream.id != 'stream0')
+        throw failTest('Unexpected stream id in first stream event.');
+      // Because we did not wait for promises to resolve before calling
+      // |setRemoteDescription| a second time, it may or may not have had an
+      // effect here. This is inherently racey and we have to check if the
+      // stream contains the track.
+      if (e.stream.getTracks().length != 0) {
+        if (e.stream.getTracks()[0].id != 'track0')
+          throw failTest('Unexpected track id in first stream event.');
+      }
+    } else if (streamEventsFired == 2) {
+      if (e.stream.id != 'stream1')
+        throw failTest('Unexpected stream id in second stream event.');
+      if (e.stream.getTracks()[0].id != 'track1')
+        throw failTest('Unexpected track id in second stream event.');
+    }
+  };
+  pc.setRemoteDescription(createOffer('stream0', 'track0'));
+  pc.setRemoteDescription(createOffer('stream1', 'track1'));
+}
+
+// TODO(hbos): Also try switching back again for the case where IDs do match
+// but the objects are in fact different. Verify that they are different objects
+// like in the |switchRemoteStreamAndBackAgain| test.
+
 /**
  * Invokes the GC and returns "ok-gc".
  */
diff --git a/chrome/test/data/webui/settings/bluetooth_page_tests.js b/chrome/test/data/webui/settings/bluetooth_page_tests.js
index 5644558..5da95ac2 100644
--- a/chrome/test/data/webui/settings/bluetooth_page_tests.js
+++ b/chrome/test/data/webui/settings/bluetooth_page_tests.js
@@ -2,6 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+function getFakePrefs() {
+  return {
+    ash: {
+      user: {
+        bluetooth: {
+          adapter_enabled: {
+            key: 'ash.user.bluetooth.adapter_enabled',
+            type: chrome.settingsPrivate.PrefType.BOOLEAN,
+            value: false,
+          }
+        }
+      }
+    }
+  };
+}
+
 suite('Bluetooth', function() {
   var bluetoothPage = null;
 
@@ -60,6 +76,7 @@
   setup(function() {
     PolymerTest.clearBody();
     bluetoothPage = document.createElement('settings-bluetooth-page');
+    bluetoothPage.prefs = getFakePrefs();
     assertTrue(!!bluetoothPage);
 
     bluetoothApi_.setDevicesForTest([]);
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index f3953e8..4d1df42f 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -166,8 +166,7 @@
       });
 
       test('getProfileStatsCount', function() {
-        return profileInfoBrowserProxy.whenCalled('getProfileStatsCount')
-            .then(function() {
+        return browserProxy.whenCalled('getSyncStatus').then(function() {
           Polymer.dom.flush();
 
           // Open the disconnect dialog.
@@ -175,8 +174,9 @@
           assertTrue(!!disconnectButton);
           MockInteractions.tap(disconnectButton);
 
-          return new Promise(function(resolve) { peoplePage.async(resolve); });
+          return profileInfoBrowserProxy.whenCalled('getProfileStatsCount');
         }).then(function() {
+          Polymer.dom.flush();
           assertTrue(peoplePage.$$('#disconnectDialog').open);
 
           // Assert the warning message is as expected.
diff --git a/chrome/tools/build/win/create_installer_archive.py b/chrome/tools/build/win/create_installer_archive.py
index 9fe93b1d..60a9d643 100755
--- a/chrome/tools/build/win/create_installer_archive.py
+++ b/chrome/tools/build/win/create_installer_archive.py
@@ -120,6 +120,7 @@
       continue
 
     dst_dir = os.path.join(staging_dir, config.get(section, option))
+    dst_dir = dst_dir.replace('\\', os.sep)
     src_paths = glob.glob(os.path.join(src_dir, option))
     if src_paths and not os.path.exists(dst_dir):
       os.makedirs(dst_dir)
@@ -139,8 +140,11 @@
   RunSystemCommand(cmd, options.verbose)
 
 def GetLZMAExec(build_dir):
-  lzma_exec = os.path.join(build_dir, "..", "..", "third_party",
-                           "lzma_sdk", "Executable", "7za.exe")
+  if sys.platform == 'win32':
+    lzma_exec = os.path.join(build_dir, "..", "..", "third_party",
+                             "lzma_sdk", "Executable", "7za.exe")
+  else:
+    lzma_exec = '7za'  # Use system 7za.
   return lzma_exec
 
 def GetPrevVersion(build_dir, temp_dir, last_chrome_installer, output_name):
@@ -159,7 +163,7 @@
   dll_path = glob.glob(os.path.join(temp_dir, 'Chrome-bin', '*', 'chrome.dll'))
   return os.path.split(os.path.split(dll_path[0])[0])[1]
 
-def MakeStagingDirectories(staging_dir):
+def MakeStagingDirectory(staging_dir):
   """Creates a staging path for installer archive. If directory exists already,
   deletes the existing directory.
   """
@@ -167,12 +171,7 @@
   if os.path.exists(file_path):
     shutil.rmtree(file_path)
   os.makedirs(file_path)
-
-  temp_file_path = os.path.join(staging_dir, TEMP_ARCHIVE_DIR)
-  if os.path.exists(temp_file_path):
-    shutil.rmtree(temp_file_path)
-  os.makedirs(temp_file_path)
-  return (file_path, temp_file_path)
+  return file_path
 
 def Readconfig(input_file, current_version):
   """Reads config information from input file after setting default value of
@@ -532,9 +531,9 @@
 
   config = Readconfig(options.input_file, current_version)
 
-  (staging_dir, temp_dir) = MakeStagingDirectories(options.staging_dir)
+  staging_dir = MakeStagingDirectory(options.staging_dir)
 
-  prev_version = GetPrevVersion(options.build_dir, temp_dir,
+  prev_version = GetPrevVersion(options.build_dir, staging_dir,
                                 options.last_chrome_installer,
                                 options.output_name)
 
diff --git a/chromecast/base/cast_features.cc b/chromecast/base/cast_features.cc
index 81dbe83..7d6bf7b 100644
--- a/chromecast/base/cast_features.cc
+++ b/chromecast/base/cast_features.cc
@@ -108,6 +108,10 @@
 
 // Begin Chromecast Feature definitions.
 
+// Allows applications to access media capture devices (webcams/microphones)
+// through getUserMedia API.
+const base::Feature kAllowUserMediaAccess{"allow_user_media_access",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
 // Enables the use of QUIC in Cast-specific URLRequestContextGetters. See
 // chromecast/browser/url_request_context_factory.cc for usage.
 const base::Feature kEnableQuic{"enable_quic",
diff --git a/chromecast/base/cast_features.h b/chromecast/base/cast_features.h
index b4a2c83..75dd2fcf 100644
--- a/chromecast/base/cast_features.h
+++ b/chromecast/base/cast_features.h
@@ -21,6 +21,7 @@
 namespace chromecast {
 
 // Add Cast Features here.
+extern const base::Feature kAllowUserMediaAccess;
 extern const base::Feature kEnableQuic;
 extern const base::Feature kTripleBuffer720;
 extern const base::Feature kSingleBuffer;
diff --git a/chromecast/browser/cast_web_view.cc b/chromecast/browser/cast_web_view.cc
index 113c22d..0ad4324 100644
--- a/chromecast/browser/cast_web_view.cc
+++ b/chromecast/browser/cast_web_view.cc
@@ -6,10 +6,13 @@
 
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/base/cast_features.h"
 #include "chromecast/base/metrics/cast_metrics_helper.h"
 #include "chromecast/browser/cast_web_contents_manager.h"
+#include "content/public/browser/media_capture_devices.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -133,6 +136,78 @@
   contents->GetRenderViewHost()->GetWidget()->Focus();
 }
 
+bool CastWebView::CheckMediaAccessPermission(content::WebContents* web_contents,
+                                             const GURL& security_origin,
+                                             content::MediaStreamType type) {
+  if (!base::FeatureList::IsEnabled(kAllowUserMediaAccess)) {
+    LOG(WARNING) << __func__ << ": media access is disabled.";
+    return false;
+  }
+  return true;
+}
+
+const content::MediaStreamDevice* GetRequestedDeviceOrDefault(
+    const content::MediaStreamDevices& devices,
+    const std::string& requested_device_id) {
+  if (!requested_device_id.empty()) {
+    auto it = std::find_if(
+        devices.begin(), devices.end(),
+        [requested_device_id](const content::MediaStreamDevice& device) {
+          return device.id == requested_device_id;
+        });
+    return it != devices.end() ? &(*it) : nullptr;
+  }
+
+  if (!devices.empty())
+    return &devices[0];
+
+  return nullptr;
+}
+
+void CastWebView::RequestMediaAccessPermission(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback) {
+  if (!base::FeatureList::IsEnabled(kAllowUserMediaAccess)) {
+    LOG(WARNING) << __func__ << ": media access is disabled.";
+    callback.Run(content::MediaStreamDevices(),
+                 content::MEDIA_DEVICE_NOT_SUPPORTED,
+                 std::unique_ptr<content::MediaStreamUI>());
+    return;
+  }
+
+  auto audio_devices =
+      content::MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices();
+  auto video_devices =
+      content::MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
+  VLOG(2) << __func__ << " audio_devices=" << audio_devices.size()
+          << " video_devices=" << video_devices.size();
+
+  content::MediaStreamDevices devices;
+  if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
+    const content::MediaStreamDevice* device = GetRequestedDeviceOrDefault(
+        audio_devices, request.requested_audio_device_id);
+    if (device) {
+      VLOG(1) << __func__ << "Using audio device: id=" << device->id
+              << " name=" << device->name;
+      devices.push_back(*device);
+    }
+  }
+
+  if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
+    const content::MediaStreamDevice* device = GetRequestedDeviceOrDefault(
+        video_devices, request.requested_video_device_id);
+    if (device) {
+      VLOG(1) << __func__ << "Using video device: id=" << device->id
+              << " name=" << device->name;
+      devices.push_back(*device);
+    }
+  }
+
+  callback.Run(devices, content::MEDIA_DEVICE_OK,
+               std::unique_ptr<content::MediaStreamUI>());
+}
+
 #if defined(OS_ANDROID)
 base::android::ScopedJavaLocalRef<jobject>
 CastWebView::GetContentVideoViewEmbedder() {
diff --git a/chromecast/browser/cast_web_view.h b/chromecast/browser/cast_web_view.h
index 61589f32..eb0df06 100644
--- a/chromecast/browser/cast_web_view.h
+++ b/chromecast/browser/cast_web_view.h
@@ -93,6 +93,13 @@
   void LoadingStateChanged(content::WebContents* source,
                            bool to_different_document) override;
   void ActivateContents(content::WebContents* contents) override;
+  bool CheckMediaAccessPermission(content::WebContents* web_contents,
+                                  const GURL& security_origin,
+                                  content::MediaStreamType type) override;
+  void RequestMediaAccessPermission(
+      content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback) override;
 #if defined(OS_ANDROID)
   base::android::ScopedJavaLocalRef<jobject> GetContentVideoViewEmbedder()
       override;
diff --git a/chromecast/media/cma/backend/alsa/alsa_volume_control.cc b/chromecast/media/cma/backend/alsa/alsa_volume_control.cc
index 23dba69..b1bf72fb 100644
--- a/chromecast/media/cma/backend/alsa/alsa_volume_control.cc
+++ b/chromecast/media/cma/backend/alsa/alsa_volume_control.cc
@@ -41,8 +41,18 @@
     DCHECK(alsa_);
     VLOG(1) << "Opening mixer element \"" << mixer_element_name
             << "\" on device \"" << mixer_device_name << "\"";
-    ALSA_ASSERT(MixerOpen, &mixer, 0);
-    ALSA_ASSERT(MixerAttach, mixer, mixer_device_name.c_str());
+    int alsa_err = alsa_->MixerOpen(&mixer, 0);
+    if (alsa_err < 0) {
+      LOG(ERROR) << "MixerOpen error: " << alsa_->StrError(alsa_err);
+      mixer = nullptr;
+      return;
+    }
+    alsa_err = alsa_->MixerAttach(mixer, mixer_device_name.c_str());
+    if (alsa_err < 0) {
+      LOG(ERROR) << "MixerAttach error: " << alsa_->StrError(alsa_err);
+      mixer = nullptr;
+      return;
+    }
     ALSA_ASSERT(MixerElementRegister, mixer, NULL, NULL);
     ALSA_ASSERT(MixerLoad, mixer);
 
@@ -58,10 +68,14 @@
     alsa_->MixerSelemIdFree(sid);
   }
 
-  ~ScopedAlsaMixer() { alsa_->MixerClose(mixer); }
+  ~ScopedAlsaMixer() {
+    if (mixer) {
+      alsa_->MixerClose(mixer);
+    }
+  }
 
-  snd_mixer_elem_t* element;
-  snd_mixer_t* mixer;
+  snd_mixer_elem_t* element = nullptr;
+  snd_mixer_t* mixer = nullptr;
 
  private:
   ::media::AlsaWrapper* const alsa_;
@@ -115,7 +129,10 @@
   }
 
   ScopedAlsaMixer mixer(alsa, mixer_device_name, mixer_element_name);
-  DCHECK(mixer.element);
+  if (!mixer.element) {
+    LOG(WARNING) << "The default ALSA mixer element does not exist.";
+    return mixer_element_name;
+  }
   if (alsa->MixerSelemHasPlaybackSwitch(mixer.element)) {
     return mixer_element_name;
   }
@@ -172,27 +189,28 @@
 
   volume_mixer_ = base::MakeUnique<ScopedAlsaMixer>(
       alsa_.get(), volume_mixer_device_name_, volume_mixer_element_name_);
-  DCHECK(volume_mixer_->element);
-  ALSA_ASSERT(MixerSelemGetPlaybackVolumeRange, volume_mixer_->element,
-              &volume_range_min_, &volume_range_max_);
-
-  alsa_->MixerElemSetCallback(volume_mixer_->element,
-                              &AlsaVolumeControl::VolumeOrMuteChangeCallback);
-  alsa_->MixerElemSetCallbackPrivate(volume_mixer_->element,
-                                     reinterpret_cast<void*>(this));
-  RefreshMixerFds(volume_mixer_.get());
+  if (volume_mixer_->element) {
+    ALSA_ASSERT(MixerSelemGetPlaybackVolumeRange, volume_mixer_->element,
+                &volume_range_min_, &volume_range_max_);
+    alsa_->MixerElemSetCallback(volume_mixer_->element,
+                                &AlsaVolumeControl::VolumeOrMuteChangeCallback);
+    alsa_->MixerElemSetCallbackPrivate(volume_mixer_->element,
+                                       reinterpret_cast<void*>(this));
+    RefreshMixerFds(volume_mixer_.get());
+  }
 
   if (mute_mixer_element_name_ != volume_mixer_element_name_) {
     mute_mixer_ = base::MakeUnique<ScopedAlsaMixer>(
         alsa_.get(), mute_mixer_device_name_, mute_mixer_element_name_);
-    DCHECK(mute_mixer_->element);
-    mute_mixer_ptr_ = mute_mixer_.get();
+    if (mute_mixer_->element) {
+      mute_mixer_ptr_ = mute_mixer_.get();
 
-    alsa_->MixerElemSetCallback(mute_mixer_->element,
-                                &AlsaVolumeControl::VolumeOrMuteChangeCallback);
-    alsa_->MixerElemSetCallbackPrivate(mute_mixer_->element,
-                                       reinterpret_cast<void*>(this));
-    RefreshMixerFds(mute_mixer_.get());
+      alsa_->MixerElemSetCallback(
+          mute_mixer_->element, &AlsaVolumeControl::VolumeOrMuteChangeCallback);
+      alsa_->MixerElemSetCallbackPrivate(mute_mixer_->element,
+                                         reinterpret_cast<void*>(this));
+      RefreshMixerFds(mute_mixer_.get());
+    }
   } else {
     mute_mixer_ptr_ = volume_mixer_.get();
   }
@@ -201,6 +219,10 @@
 AlsaVolumeControl::~AlsaVolumeControl() = default;
 
 float AlsaVolumeControl::VolumeThroughAlsa(float volume) {
+  if (volume_range_max_ == volume_range_min_) {
+    return 0.0f;
+  }
+
   long level = 0;  // NOLINT(runtime/int)
   level = std::round((volume * (volume_range_max_ - volume_range_min_)) +
                      volume_range_min_);
@@ -209,6 +231,9 @@
 }
 
 float AlsaVolumeControl::GetVolume() {
+  if (!volume_mixer_->element) {
+    return 0.0f;
+  }
   long level = 0;  // NOLINT(runtime/int)
   ALSA_ASSERT(MixerSelemGetPlaybackVolume, volume_mixer_->element,
               SND_MIXER_SCHN_MONO, &level);
@@ -217,13 +242,17 @@
 }
 
 void AlsaVolumeControl::SetVolume(float level) {
+  if (!volume_mixer_->element) {
+    return;
+  }
   float volume = std::round((level * (volume_range_max_ - volume_range_min_)) +
                             volume_range_min_);
   ALSA_ASSERT(MixerSelemSetPlaybackVolumeAll, volume_mixer_->element, volume);
 }
 
 bool AlsaVolumeControl::IsMuted() {
-  if (!alsa_->MixerSelemHasPlaybackSwitch(mute_mixer_ptr_->element)) {
+  if (!mute_mixer_ptr_->element ||
+      !alsa_->MixerSelemHasPlaybackSwitch(mute_mixer_ptr_->element)) {
     LOG(ERROR) << "Mute failed: no mute switch on mixer element.";
     return false;
   }
@@ -242,7 +271,8 @@
 }
 
 void AlsaVolumeControl::SetMuted(bool muted) {
-  if (!alsa_->MixerSelemHasPlaybackSwitch(mute_mixer_ptr_->element)) {
+  if (!mute_mixer_ptr_->element ||
+      !alsa_->MixerSelemHasPlaybackSwitch(mute_mixer_ptr_->element)) {
     LOG(ERROR) << "Mute failed: no mute switch on mixer element.";
     return;
   }
diff --git a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc
index c07e592d..c729404 100644
--- a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc
+++ b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc
@@ -109,8 +109,8 @@
   current_pts_ = start_pts;
   DCHECK(IsValidConfig(config_));
   mixer_input_.reset(new StreamMixerAlsaInput(
-      this, config_.samples_per_second, backend_->Primary(),
-      backend_->DeviceId(), backend_->ContentType()));
+      this, config_.samples_per_second, config_.playout_channel,
+      backend_->Primary(), backend_->DeviceId(), backend_->ContentType()));
   mixer_input_->SetVolumeMultiplier(volume_multiplier_);
   // Create decoder_ if necessary. This can happen if Stop() was called, and
   // SetConfig() was not called since then.
@@ -239,8 +239,8 @@
     // is updated.
     mixer_input_.reset();
     mixer_input_.reset(new StreamMixerAlsaInput(
-        this, config.samples_per_second, backend_->Primary(),
-        backend_->DeviceId(), backend_->ContentType()));
+        this, config.samples_per_second, config.playout_channel,
+        backend_->Primary(), backend_->DeviceId(), backend_->ContentType()));
     mixer_input_->SetVolumeMultiplier(volume_multiplier_);
     pending_output_frames_ = kNoPendingOutput;
   }
diff --git a/chromecast/media/cma/backend/alsa/filter_group.cc b/chromecast/media/cma/backend/alsa/filter_group.cc
index d3dce97..234ad30 100644
--- a/chromecast/media/cma/backend/alsa/filter_group.cc
+++ b/chromecast/media/cma/backend/alsa/filter_group.cc
@@ -24,6 +24,7 @@
                          const std::vector<FilterGroup*>& mixed_inputs)
     : num_channels_(num_channels),
       mix_to_mono_(mix_to_mono),
+      playout_channel_(kChannelAll),
       name_(name),
       device_ids_(device_ids),
       mixed_inputs_(mixed_inputs),
@@ -117,13 +118,26 @@
   delay_frames_ = post_processing_pipeline_->ProcessFrames(
       interleaved(), chunk_size, last_volume_, is_silence);
 
+  // Copy the active channel to all channels.
+  if (playout_channel_ != kChannelAll) {
+    DCHECK_GE(playout_channel_, 0);
+    DCHECK_LT(playout_channel_, num_channels_);
+
+    for (int frame = 0; frame < chunk_size; ++frame) {
+      float s = interleaved()[frame * num_channels_ + playout_channel_];
+      for (int c = 0; c < num_channels_; ++c)
+        interleaved()[frame * num_channels_ + c] = s;
+    }
+  }
+
   // Mono mixing after all processing if needed.
   if (mix_to_mono_) {
     for (int frame = 0; frame < chunk_size; ++frame) {
       float sum = 0;
       for (int c = 0; c < num_channels_; ++c)
         sum += interleaved()[frame * num_channels_ + c];
-      interleaved()[frame] = sum / num_channels_;
+      for (int c = 0; c < num_channels_; ++c)
+        interleaved()[frame * num_channels_ + c] = sum / num_channels_;
     }
   }
 
@@ -140,7 +154,7 @@
 }
 
 int FilterGroup::GetOutputChannelCount() const {
-  return mix_to_mono_ ? 1 : num_channels_;
+  return num_channels_;
 }
 
 void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) {
@@ -158,5 +172,19 @@
   post_processing_pipeline_->SetPostProcessorConfig(name, config);
 }
 
+void FilterGroup::SetMixToMono(bool mix_to_mono) {
+  mix_to_mono_ = (num_channels_ != 1 && mix_to_mono);
+}
+
+void FilterGroup::UpdatePlayoutChannel(int playout_channel) {
+  LOG(INFO) << __FUNCTION__ << " channel=" << playout_channel;
+  if (playout_channel >= num_channels_) {
+    LOG(ERROR) << "only " << num_channels_ << " present, wanted channel #"
+               << playout_channel;
+    return;
+  }
+  playout_channel_ = playout_channel;
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/filter_group.h b/chromecast/media/cma/backend/alsa/filter_group.h
index 9a966d16..903121d 100644
--- a/chromecast/media/cma/backend/alsa/filter_group.h
+++ b/chromecast/media/cma/backend/alsa/filter_group.h
@@ -98,11 +98,18 @@
   void SetPostProcessorConfig(const std::string& name,
                               const std::string& config);
 
+  // Toggles the mono mixer.
+  void SetMixToMono(bool mix_to_mono);
+
+  // Sets the active channel.
+  void UpdatePlayoutChannel(int playout_channel);
+
  private:
   void ResizeBuffersIfNecessary(int chunk_size);
 
   const int num_channels_;
   bool mix_to_mono_;
+  int playout_channel_;
   const std::string name_;
   const std::unordered_set<std::string> device_ids_;
   std::vector<FilterGroup*> mixed_inputs_;
diff --git a/chromecast/media/cma/backend/alsa/filter_group_unittest.cc b/chromecast/media/cma/backend/alsa/filter_group_unittest.cc
index 2daf3a4..e099c3b 100644
--- a/chromecast/media/cma/backend/alsa/filter_group_unittest.cc
+++ b/chromecast/media/cma/backend/alsa/filter_group_unittest.cc
@@ -165,7 +165,7 @@
   for (int i = 0; i < output_chunk_size; ++i) {
     const float* left_input = input->data()->channel(0);
     const float* right_input = input->data()->channel(1);
-    ASSERT_EQ((left_input[i] + right_input[i]) / 2, interleaved_data[i]);
+    ASSERT_EQ((left_input[i] + right_input[i]) / 2, interleaved_data[i * 2]);
   }
 }
 
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
index c82a181..48b28af 100644
--- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
+++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
@@ -320,7 +320,7 @@
   mix_filter_ = filter_groups_.back().get();
 
   filter_groups_.push_back(base::MakeUnique<FilterGroup>(
-      num_output_channels_, false /* mono_mixer */, "linearize",
+      kNumInputChannels, false /* mono_mixer */, "linearize",
       pipeline_parser->GetLinearizePipeline(),
       std::unordered_set<std::string>() /* device_ids */,
       std::vector<FilterGroup*>({mix_filter_})));
@@ -566,6 +566,7 @@
 
 void StreamMixerAlsa::Start() {
   DCHECK(mixer_task_runner_->BelongsToCurrentThread());
+  output_samples_per_second_ = requested_output_samples_per_second_;
   if (!pcm_) {
     RETURN_REPORT_ERROR(PcmOpen, &pcm_, alsa_device_name_.c_str(),
                         SND_PCM_STREAM_PLAYBACK, 0);
@@ -937,6 +938,19 @@
                              linearize_filter_->GetRenderingDelayMicroseconds();
   }
 
+  // Downmix reference signal to mono to reduce CPU load.
+  int mix_channel_count = mix_filter_->GetOutputChannelCount();
+
+  if (num_output_channels_ == 1 && mix_channel_count != num_output_channels_) {
+    for (int i = 0; i < frames; ++i) {
+      float sum = 0;
+      for (int c = 0; c < mix_channel_count; ++c) {
+        sum += mix_filter_->interleaved()[i * mix_channel_count + c];
+      }
+      mix_filter_->interleaved()[i] = sum / mix_channel_count;
+    }
+  }
+
   // Hard limit to [1.0, -1.0]
   for (int i = 0; i < frames * num_output_channels_; ++i) {
     mix_filter_->interleaved()[i] =
@@ -951,6 +965,16 @@
         InterleavedSize(frames));
   }
 
+  // Drop extra channels from linearize filter if necessary.
+  int linearize_channel_count = linearize_filter_->GetOutputChannelCount();
+  if (num_output_channels_ == 1 &&
+      linearize_channel_count != num_output_channels_) {
+    for (int i = 0; i < frames; ++i) {
+      linearize_filter_->interleaved()[i] =
+          linearize_filter_->interleaved()[i * linearize_channel_count];
+    }
+  }
+
   uint8_t* data;
   if (pcm_format_ == SND_PCM_FORMAT_FLOAT) {
     // Hard limit to [1.0, -1.0]. ToFixedPoint handles this for other cases.
@@ -1101,6 +1125,17 @@
   }
 }
 
+void StreamMixerAlsa::UpdatePlayoutChannel(int playout_channel) {
+  RUN_ON_MIXER_THREAD(&StreamMixerAlsa::UpdatePlayoutChannel, playout_channel);
+  LOG(INFO) << "Update playout channel: " << playout_channel;
+  DCHECK(mix_filter_);
+  DCHECK(linearize_filter_);
+
+  mix_filter_->SetMixToMono(num_output_channels_ == 1 &&
+                            playout_channel == kChannelAll);
+  linearize_filter_->UpdatePlayoutChannel(playout_channel);
+}
+
 void StreamMixerAlsa::SetFilterFrameAlignmentForTest(
     int filter_frame_alignment) {
   RUN_ON_MIXER_THREAD(&StreamMixerAlsa::SetFilterFrameAlignmentForTest,
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
index a2a3714a..27afef0d 100644
--- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
+++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
@@ -202,6 +202,9 @@
   void SetPostProcessorConfig(const std::string& name,
                               const std::string& config);
 
+  // Sets active channel in multichannel group.
+  void UpdatePlayoutChannel(int playout_channel);
+
   // Sets filter data alignment, required by some processors.
   // Must be called before audio playback starts.
   void SetFilterFrameAlignmentForTest(int filter_frame_alignment);
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.cc
index 5a79b17..af03f46a 100644
--- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.cc
+++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.cc
@@ -14,6 +14,7 @@
 
 StreamMixerAlsaInput::StreamMixerAlsaInput(Delegate* delegate,
                                            int samples_per_second,
+                                           int playout_channel,
                                            bool primary,
                                            const std::string& device_id,
                                            AudioContentType content_type) {
@@ -22,6 +23,7 @@
       StreamMixerAlsa::Get()));
   impl_ = impl.get();  // Store a pointer to the impl, but the mixer owns it.
   StreamMixerAlsa::Get()->AddInput(std::move(impl));
+  StreamMixerAlsa::Get()->UpdatePlayoutChannel(playout_channel);
 }
 
 StreamMixerAlsaInput::~StreamMixerAlsaInput() {
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h
index 918c4a2..0fd832b 100644
--- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h
+++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h
@@ -52,6 +52,7 @@
   // exist.
   StreamMixerAlsaInput(Delegate* delegate,
                        int samples_per_second,
+                       int playout_channel,
                        bool primary,
                        const std::string& device_id,
                        AudioContentType content_type);
diff --git a/chromecast/public/media/decoder_config.h b/chromecast/public/media/decoder_config.h
index d0fe46d..5800a69 100644
--- a/chromecast/public/media/decoder_config.h
+++ b/chromecast/public/media/decoder_config.h
@@ -280,6 +280,8 @@
 inline HDRMetadata::HDRMetadata(const HDRMetadata& rhs) = default;
 // ---- End copy/paste from media/base/hdr_metadata.h ----
 
+constexpr int kChannelAll = -1;
+
 // TODO(erickung): Remove constructor once CMA backend implementation doesn't
 // create a new object to reset the configuration and use IsValidConfig() to
 // determine if the configuration is still valid or not.
@@ -306,6 +308,8 @@
   std::vector<uint8_t> extra_data;
   // Encryption scheme (if any) used for the content.
   EncryptionScheme encryption_scheme;
+  // Selected channel.
+  int playout_channel;
 };
 
 inline AudioConfig::AudioConfig()
@@ -314,8 +318,8 @@
       sample_format(kUnknownSampleFormat),
       bytes_per_channel(0),
       channel_number(0),
-      samples_per_second(0) {
-}
+      samples_per_second(0),
+      playout_channel(kChannelAll) {}
 inline AudioConfig::AudioConfig(const AudioConfig& other) = default;
 inline AudioConfig::~AudioConfig() {
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 2a7446d..98ece30 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-9900.0.0
\ No newline at end of file
+9913.0.0
\ No newline at end of file
diff --git a/chromeos/audio/chromeos_sounds.h b/chromeos/audio/chromeos_sounds.h
index c289b6e..8095215 100644
--- a/chromeos/audio/chromeos_sounds.h
+++ b/chromeos/audio/chromeos_sounds.h
@@ -24,6 +24,7 @@
   SOUND_ENTER_SCREEN,
   SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_HIGH,
   SOUND_SPOKEN_FEEDBACK_TOGGLE_COUNTDOWN_LOW,
+  SOUND_TOUCH_TYPE,
   SOUND_COUNT,
 };
 
diff --git a/chromeos/dbus/cryptohome_client.cc b/chromeos/dbus/cryptohome_client.cc
index 6b64db8..ac4236d 100644
--- a/chromeos/dbus/cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome_client.cc
@@ -190,7 +190,7 @@
 
   // CryptohomeClient override,
   void GetSanitizedUsername(const cryptohome::Identification& cryptohome_id,
-                            const StringDBusMethodCallback& callback) override {
+                            StringDBusMethodCallback callback) override {
     dbus::MethodCall method_call(cryptohome::kCryptohomeInterface,
                                  cryptohome::kCryptohomeGetSanitizedUsername);
     dbus::MessageWriter writer(&method_call);
@@ -198,7 +198,7 @@
     proxy_->CallMethod(
         &method_call, kTpmDBusTimeoutMs,
         base::BindOnce(&CryptohomeClientImpl::OnStringMethod,
-                       weak_ptr_factory_.GetWeakPtr(), callback));
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
   // CryptohomeClient override.
@@ -307,13 +307,13 @@
   }
 
   // CryptohomeClient override.
-  void TpmGetPassword(const StringDBusMethodCallback& callback) override {
+  void TpmGetPassword(StringDBusMethodCallback callback) override {
     dbus::MethodCall method_call(cryptohome::kCryptohomeInterface,
                                  cryptohome::kCryptohomeTpmGetPassword);
     proxy_->CallMethod(
         &method_call, kTpmDBusTimeoutMs,
         base::BindOnce(&CryptohomeClientImpl::OnStringMethod,
-                       weak_ptr_factory_.GetWeakPtr(), callback));
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
   // CryptohomeClient override.
@@ -756,13 +756,13 @@
   }
 
   // CryptohomeClient override.
-  void TpmGetVersion(const StringDBusMethodCallback& callback) override {
+  void TpmGetVersion(StringDBusMethodCallback callback) override {
     dbus::MethodCall method_call(cryptohome::kCryptohomeInterface,
                                  cryptohome::kCryptohomeTpmGetVersion);
     proxy_->CallMethod(
         &method_call, kTpmDBusTimeoutMs,
         base::BindOnce(&CryptohomeClientImpl::OnStringMethod,
-                       weak_ptr_factory_.GetWeakPtr(), callback));
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
   void GetKeyDataEx(const cryptohome::Identification& id,
@@ -1093,19 +1093,19 @@
   }
 
   // Handles responses for methods with a string value result.
-  void OnStringMethod(const StringDBusMethodCallback& callback,
+  void OnStringMethod(StringDBusMethodCallback callback,
                       dbus::Response* response) {
     if (!response) {
-      callback.Run(DBUS_METHOD_CALL_FAILURE, std::string());
+      std::move(callback).Run(DBUS_METHOD_CALL_FAILURE, std::string());
       return;
     }
     dbus::MessageReader reader(response);
     std::string result;
     if (!reader.PopString(&result)) {
-      callback.Run(DBUS_METHOD_CALL_FAILURE, std::string());
+      std::move(callback).Run(DBUS_METHOD_CALL_FAILURE, std::string());
       return;
     }
-    callback.Run(DBUS_METHOD_CALL_SUCCESS, result);
+    std::move(callback).Run(DBUS_METHOD_CALL_SUCCESS, result);
   }
 
   // Handles responses for methods with a bool result and data.
diff --git a/chromeos/dbus/cryptohome_client.h b/chromeos/dbus/cryptohome_client.h
index abb2fdb..f821854 100644
--- a/chromeos/dbus/cryptohome_client.h
+++ b/chromeos/dbus/cryptohome_client.h
@@ -180,7 +180,7 @@
   // call succeeds.
   virtual void GetSanitizedUsername(
       const cryptohome::Identification& cryptohome_id,
-      const StringDBusMethodCallback& callback) = 0;
+      StringDBusMethodCallback callback) = 0;
 
   // Same as GetSanitizedUsername() but blocks until a reply is received, and
   // returns the sanitized username synchronously. Returns an empty string if
@@ -233,7 +233,7 @@
   virtual bool CallTpmIsEnabledAndBlock(bool* enabled) = 0;
 
   // Calls TpmGetPassword method.
-  virtual void TpmGetPassword(const StringDBusMethodCallback& callback) = 0;
+  virtual void TpmGetPassword(StringDBusMethodCallback callback) = 0;
 
   // Calls TpmIsOwned method.
   virtual void TpmIsOwned(const BoolDBusMethodCallback& callback) = 0;
@@ -492,7 +492,7 @@
 
   // Asynchronously gets the underlying TPM version information and passes it to
   // the given callback as a string.
-  virtual void TpmGetVersion(const StringDBusMethodCallback& callback) = 0;
+  virtual void TpmGetVersion(StringDBusMethodCallback callback) = 0;
 
   // Asynchronously calls the GetKeyDataEx method. |callback| will be invoked
   // with the reply protobuf.
diff --git a/chromeos/dbus/dbus_method_call_status.h b/chromeos/dbus/dbus_method_call_status.h
index 97f4a1da..0e24f6c 100644
--- a/chromeos/dbus/dbus_method_call_status.h
+++ b/chromeos/dbus/dbus_method_call_status.h
@@ -35,9 +35,9 @@
                             bool result)> BoolDBusMethodCallback;
 
 // A callback to handle responses of methods returning a string value.
-typedef base::Callback<void(
-    DBusMethodCallStatus call_status,
-    const std::string& result)> StringDBusMethodCallback;
+using StringDBusMethodCallback =
+    base::OnceCallback<void(DBusMethodCallStatus call_status,
+                            const std::string& result)>;
 
 // A callback to handle responses of methods returning a boolean value.
 typedef base::Callback<void(
diff --git a/chromeos/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc
index fd78bb4..82e278c 100644
--- a/chromeos/dbus/fake_cryptohome_client.cc
+++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -145,14 +145,15 @@
 
 void FakeCryptohomeClient::GetSanitizedUsername(
     const cryptohome::Identification& cryptohome_id,
-    const StringDBusMethodCallback& callback) {
+    StringDBusMethodCallback callback) {
   // Even for stub implementation we have to return different values so that
   // multi-profiles would work.
   auto task =
       service_is_available_
-          ? base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS,
+          ? base::BindOnce(std::move(callback), DBUS_METHOD_CALL_SUCCESS,
                            GetStubSanitizedUsername(cryptohome_id))
-          : base::BindOnce(callback, DBUS_METHOD_CALL_FAILURE, std::string());
+          : base::BindOnce(std::move(callback), DBUS_METHOD_CALL_FAILURE,
+                           std::string());
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task));
 }
 
@@ -207,12 +208,11 @@
   return true;
 }
 
-void FakeCryptohomeClient::TpmGetPassword(
-    const StringDBusMethodCallback& callback) {
+void FakeCryptohomeClient::TpmGetPassword(StringDBusMethodCallback callback) {
   const char kStubTpmPassword[] = "Stub-TPM-password";
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS,
-                            std::string(kStubTpmPassword)));
+      FROM_HERE, base::BindOnce(std::move(callback), DBUS_METHOD_CALL_SUCCESS,
+                                std::string(kStubTpmPassword)));
 }
 
 void FakeCryptohomeClient::TpmIsOwned(
@@ -377,9 +377,11 @@
 
 void FakeCryptohomeClient::TpmAttestationIsPrepared(
     const BoolDBusMethodCallback& callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS,
-                                tpm_attestation_is_prepared_));
+  auto task = service_is_available_
+                  ? base::BindOnce(callback, DBUS_METHOD_CALL_SUCCESS,
+                                   tpm_attestation_is_prepared_)
+                  : base::BindOnce(callback, DBUS_METHOD_CALL_FAILURE, false);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task));
 }
 
 void FakeCryptohomeClient::TpmAttestationIsEnrolled(
@@ -568,10 +570,10 @@
       FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
 }
 
-void FakeCryptohomeClient::TpmGetVersion(
-    const StringDBusMethodCallback& callback) {
+void FakeCryptohomeClient::TpmGetVersion(StringDBusMethodCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, std::string()));
+      FROM_HERE, base::BindOnce(std::move(callback), DBUS_METHOD_CALL_SUCCESS,
+                                std::string()));
 }
 
 void FakeCryptohomeClient::GetKeyDataEx(
diff --git a/chromeos/dbus/fake_cryptohome_client.h b/chromeos/dbus/fake_cryptohome_client.h
index 0ec30a2d6..4635016 100644
--- a/chromeos/dbus/fake_cryptohome_client.h
+++ b/chromeos/dbus/fake_cryptohome_client.h
@@ -53,7 +53,7 @@
                            const ProtobufMethodCallback& callback) override;
   void GetSystemSalt(const GetSystemSaltCallback& callback) override;
   void GetSanitizedUsername(const cryptohome::Identification& cryptohome_id,
-                            const StringDBusMethodCallback& callback) override;
+                            StringDBusMethodCallback callback) override;
   std::string BlockingGetSanitizedUsername(
       const cryptohome::Identification& cryptohome_id) override;
   void AsyncMount(const cryptohome::Identification& cryptohome_id,
@@ -71,7 +71,7 @@
   void TpmIsReady(const BoolDBusMethodCallback& callback) override;
   void TpmIsEnabled(const BoolDBusMethodCallback& callback) override;
   bool CallTpmIsEnabledAndBlock(bool* enabled) override;
-  void TpmGetPassword(const StringDBusMethodCallback& callback) override;
+  void TpmGetPassword(StringDBusMethodCallback callback) override;
   void TpmIsOwned(const BoolDBusMethodCallback& callback) override;
   bool CallTpmIsOwnedAndBlock(bool* owned) override;
   void TpmIsBeingOwned(const BoolDBusMethodCallback& callback) override;
@@ -169,7 +169,7 @@
       const cryptohome::Identification& cryptohome_id,
       const std::string& key_prefix,
       const BoolDBusMethodCallback& callback) override;
-  void TpmGetVersion(const StringDBusMethodCallback& callback) override;
+  void TpmGetVersion(StringDBusMethodCallback callback) override;
   void GetKeyDataEx(const cryptohome::Identification& cryptohome_id,
                     const cryptohome::AuthorizationRequest& auth,
                     const cryptohome::GetKeyDataRequest& request,
diff --git a/chromeos/dbus/fake_image_loader_client.cc b/chromeos/dbus/fake_image_loader_client.cc
index 8647e96..cd60fcd4 100644
--- a/chromeos/dbus/fake_image_loader_client.cc
+++ b/chromeos/dbus/fake_image_loader_client.cc
@@ -14,15 +14,14 @@
     const BoolDBusMethodCallback& callback) {
   callback.Run(DBUS_METHOD_CALL_FAILURE, false);
 }
-void FakeImageLoaderClient::LoadComponent(
-    const std::string& name,
-    const StringDBusMethodCallback& callback) {
-  callback.Run(DBUS_METHOD_CALL_FAILURE, "");
+void FakeImageLoaderClient::LoadComponent(const std::string& name,
+                                          StringDBusMethodCallback callback) {
+  std::move(callback).Run(DBUS_METHOD_CALL_FAILURE, "");
 }
 void FakeImageLoaderClient::RequestComponentVersion(
     const std::string& name,
-    const StringDBusMethodCallback& callback) {
-  callback.Run(DBUS_METHOD_CALL_FAILURE, "");
+    StringDBusMethodCallback callback) {
+  std::move(callback).Run(DBUS_METHOD_CALL_FAILURE, "");
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_image_loader_client.h b/chromeos/dbus/fake_image_loader_client.h
index 68282f7..0636ce2 100644
--- a/chromeos/dbus/fake_image_loader_client.h
+++ b/chromeos/dbus/fake_image_loader_client.h
@@ -27,10 +27,9 @@
                          const std::string& component_folder_abs_path,
                          const BoolDBusMethodCallback& callback) override;
   void LoadComponent(const std::string& name,
-                     const StringDBusMethodCallback& callback) override;
-  void RequestComponentVersion(
-      const std::string& name,
-      const StringDBusMethodCallback& callback) override;
+                     StringDBusMethodCallback callback) override;
+  void RequestComponentVersion(const std::string& name,
+                               StringDBusMethodCallback callback) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeImageLoaderClient);
diff --git a/chromeos/dbus/image_loader_client.cc b/chromeos/dbus/image_loader_client.cc
index 5ad0a41..d172abb 100644
--- a/chromeos/dbus/image_loader_client.cc
+++ b/chromeos/dbus/image_loader_client.cc
@@ -38,26 +38,25 @@
   }
 
   void LoadComponent(const std::string& name,
-                     const StringDBusMethodCallback& callback) override {
+                     StringDBusMethodCallback callback) override {
     dbus::MethodCall method_call(imageloader::kImageLoaderServiceInterface,
                                  imageloader::kLoadComponent);
     dbus::MessageWriter writer(&method_call);
     writer.AppendString(name);
-    proxy_->CallMethod(
-        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::BindOnce(&ImageLoaderClientImpl::OnStringMethod, callback));
+    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                       base::BindOnce(&ImageLoaderClientImpl::OnStringMethod,
+                                      std::move(callback)));
   }
 
-  void RequestComponentVersion(
-      const std::string& name,
-      const StringDBusMethodCallback& callback) override {
+  void RequestComponentVersion(const std::string& name,
+                               StringDBusMethodCallback callback) override {
     dbus::MethodCall method_call(imageloader::kImageLoaderServiceInterface,
                                  imageloader::kGetComponentVersion);
     dbus::MessageWriter writer(&method_call);
     writer.AppendString(name);
-    proxy_->CallMethod(
-        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::BindOnce(&ImageLoaderClientImpl::OnStringMethod, callback));
+    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                       base::BindOnce(&ImageLoaderClientImpl::OnStringMethod,
+                                      std::move(callback)));
   }
 
  protected:
@@ -85,20 +84,20 @@
     callback.Run(DBUS_METHOD_CALL_SUCCESS, result);
   }
 
-  static void OnStringMethod(const StringDBusMethodCallback& callback,
+  static void OnStringMethod(StringDBusMethodCallback callback,
                              dbus::Response* response) {
     if (!response) {
-      callback.Run(DBUS_METHOD_CALL_FAILURE, "");
+      std::move(callback).Run(DBUS_METHOD_CALL_FAILURE, std::string());
       return;
     }
     dbus::MessageReader reader(response);
     std::string result;
     if (!reader.PopString(&result)) {
-      callback.Run(DBUS_METHOD_CALL_FAILURE, "");
+      std::move(callback).Run(DBUS_METHOD_CALL_FAILURE, std::string());
       LOG(ERROR) << "Invalid response: " << response->ToString();
       return;
     }
-    callback.Run(DBUS_METHOD_CALL_SUCCESS, result);
+    std::move(callback).Run(DBUS_METHOD_CALL_SUCCESS, result);
   }
 
   dbus::ObjectProxy* proxy_ = nullptr;
diff --git a/chromeos/dbus/image_loader_client.h b/chromeos/dbus/image_loader_client.h
index bf070d7..ee9cf7b 100644
--- a/chromeos/dbus/image_loader_client.h
+++ b/chromeos/dbus/image_loader_client.h
@@ -31,12 +31,11 @@
   // Mounts a component given the |name| and return the mount point (if call is
   // successful).
   virtual void LoadComponent(const std::string& name,
-                             const StringDBusMethodCallback& callback) = 0;
+                             StringDBusMethodCallback callback) = 0;
 
   // Requests the currently registered version of the given component |name|.
-  virtual void RequestComponentVersion(
-      const std::string& name,
-      const StringDBusMethodCallback& callback) = 0;
+  virtual void RequestComponentVersion(const std::string& name,
+                                       StringDBusMethodCallback callback) = 0;
 
   // Factory function, creates a new instance and returns ownership.
   // For normal usage, access the singleton via DBusThreadManager::Get().
diff --git a/chromeos/process_proxy/process_proxy.cc b/chromeos/process_proxy/process_proxy.cc
index 03b7390e7..d672e49 100644
--- a/chromeos/process_proxy/process_proxy.cc
+++ b/chromeos/process_proxy/process_proxy.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
+#include <termios.h>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -201,6 +202,20 @@
     return false;
   }
 
+  // Get the current tty settings so we can overlay our updates.
+  struct termios termios;
+  if (tcgetattr(pt_pair_[PT_SLAVE_FD], &termios) != 0) {
+    CloseFdPair(pt_pair);
+    return false;
+  }
+
+  // Set the IUTF8 bit on the tty as we should be UTF-8 clean everywhere.
+  termios.c_iflag |= IUTF8;
+  if (tcsetattr(pt_pair_[PT_SLAVE_FD], TCSANOW, &termios) != 0) {
+    CloseFdPair(pt_pair);
+    return false;
+  }
+
   return true;
 }
 
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 882f61b..cafd946 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -195,6 +195,7 @@
       "//components/keyed_service/content:unit_tests",
       "//components/link_header_util:unit_tests",
       "//components/navigation_interception:unit_tests",
+      "//components/network_error_logging:unit_tests",
       "//components/network_hints/renderer:unit_tests",
       "//components/offline_pages/content/background_loader:unit_tests",
       "//components/offline_pages/core:unit_tests",
diff --git a/components/arc/intent_helper/arc_intent_helper_bridge.cc b/components/arc/intent_helper/arc_intent_helper_bridge.cc
index e8d6290..74a57b1 100644
--- a/components/arc/intent_helper/arc_intent_helper_bridge.cc
+++ b/components/arc/intent_helper/arc_intent_helper_bridge.cc
@@ -95,17 +95,23 @@
   // downloads by default, which is what we want.  However if it is open it will
   // simply be brought to the forgeground without forcibly being navigated to
   // downloads, which is probably not ideal.
-  ash::Shell::Get()->new_window_controller()->OpenFileManager();
+  // TODO(mash): Support this functionality without ash::Shell access in Chrome.
+  if (ash::Shell::HasInstance())
+    ash::Shell::Get()->new_window_controller()->OpenFileManager();
 }
 
 void ArcIntentHelperBridge::OnOpenUrl(const std::string& url) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  ash::Shell::Get()->shell_delegate()->OpenUrlFromArc(GURL(url));
+  // TODO(mash): Support this functionality without ash::Shell access in Chrome.
+  if (ash::Shell::HasInstance())
+    ash::Shell::Get()->shell_delegate()->OpenUrlFromArc(GURL(url));
 }
 
 void ArcIntentHelperBridge::OpenWallpaperPicker() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  ash::Shell::Get()->wallpaper_controller()->OpenSetWallpaperPage();
+  // TODO(mash): Support this functionality without ash::Shell access in Chrome.
+  if (ash::Shell::HasInstance())
+    ash::Shell::Get()->wallpaper_controller()->OpenSetWallpaperPage();
 }
 
 void ArcIntentHelperBridge::SetWallpaperDeprecated(
diff --git a/components/arc/power/arc_power_bridge.cc b/components/arc/power/arc_power_bridge.cc
index bc71e9b..a4b1910 100644
--- a/components/arc/power/arc_power_bridge.cc
+++ b/components/arc/power/arc_power_bridge.cc
@@ -71,7 +71,9 @@
   mojom::PowerHostPtr host_proxy;
   binding_.Bind(mojo::MakeRequest(&host_proxy));
   power_instance->Init(std::move(host_proxy));
-  ash::Shell::Get()->display_configurator()->AddObserver(this);
+  // TODO(mash): Support this functionality without ash::Shell access in Chrome.
+  if (ash::Shell::HasInstance())
+    ash::Shell::Get()->display_configurator()->AddObserver(this);
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
       AddObserver(this);
   chromeos::DBusThreadManager::Get()
@@ -82,7 +84,9 @@
 }
 
 void ArcPowerBridge::OnInstanceClosed() {
-  ash::Shell::Get()->display_configurator()->RemoveObserver(this);
+  // TODO(mash): Support this functionality without ash::Shell access in Chrome.
+  if (ash::Shell::HasInstance())
+    ash::Shell::Get()->display_configurator()->RemoveObserver(this);
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
       RemoveObserver(this);
   ReleaseAllDisplayWakeLocks();
@@ -183,7 +187,11 @@
 }
 
 void ArcPowerBridge::IsDisplayOn(const IsDisplayOnCallback& callback) {
-  callback.Run(ash::Shell::Get()->display_configurator()->IsDisplayOn());
+  bool is_display_on = false;
+  // TODO(mash): Support this functionality without ash::Shell access in Chrome.
+  if (ash::Shell::HasInstance())
+    is_display_on = ash::Shell::Get()->display_configurator()->IsDisplayOn();
+  callback.Run(is_display_on);
 }
 
 void ArcPowerBridge::OnScreenBrightnessUpdateRequest(double percent) {
diff --git a/components/autofill/content/common/autofill_param_traits_macros.h b/components/autofill/content/common/autofill_param_traits_macros.h
index edd3fcb..db9dd09 100644
--- a/components/autofill/content/common/autofill_param_traits_macros.h
+++ b/components/autofill/content/common/autofill_param_traits_macros.h
@@ -71,6 +71,7 @@
   IPC_STRUCT_TRAITS_MEMBER(username_marked_by_site)
   IPC_STRUCT_TRAITS_MEMBER(username_value)
   IPC_STRUCT_TRAITS_MEMBER(other_possible_usernames)
+  IPC_STRUCT_TRAITS_MEMBER(other_possible_passwords)
   IPC_STRUCT_TRAITS_MEMBER(password_element)
   IPC_STRUCT_TRAITS_MEMBER(password_value)
   IPC_STRUCT_TRAITS_MEMBER(new_password_element)
diff --git a/components/autofill/content/common/autofill_types.mojom b/components/autofill/content/common/autofill_types.mojom
index cb6ea75..8d454ec 100644
--- a/components/autofill/content/common/autofill_types.mojom
+++ b/components/autofill/content/common/autofill_types.mojom
@@ -172,6 +172,7 @@
   bool username_marked_by_site;
   string username_value;
   array<PossibleUsernamePair> other_possible_usernames;
+  array<string> other_possible_passwords;
   string password_element;
   string password_value;
   bool password_value_is_default;
diff --git a/components/autofill/content/common/autofill_types_struct_traits.cc b/components/autofill/content/common/autofill_types_struct_traits.cc
index ed4c5c4..98a06bc 100644
--- a/components/autofill/content/common/autofill_types_struct_traits.cc
+++ b/components/autofill/content/common/autofill_types_struct_traits.cc
@@ -552,6 +552,7 @@
 
   if (!data.ReadUsernameValue(&out->username_value) ||
       !data.ReadOtherPossibleUsernames(&out->other_possible_usernames) ||
+      !data.ReadOtherPossiblePasswords(&out->other_possible_passwords) ||
       !data.ReadPasswordElement(&out->password_element) ||
       !data.ReadPasswordValue(&out->password_value))
     return false;
diff --git a/components/autofill/content/common/autofill_types_struct_traits.h b/components/autofill/content/common/autofill_types_struct_traits.h
index b98c9dc..d233dac 100644
--- a/components/autofill/content/common/autofill_types_struct_traits.h
+++ b/components/autofill/content/common/autofill_types_struct_traits.h
@@ -402,6 +402,11 @@
     return r.other_possible_usernames;
   }
 
+  static const std::vector<base::string16>& other_possible_passwords(
+      const autofill::PasswordForm& r) {
+    return r.other_possible_passwords;
+  }
+
   static const base::string16& password_element(
       const autofill::PasswordForm& r) {
     return r.password_element;
diff --git a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
index d4ba271..b5d10c08 100644
--- a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
+++ b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
@@ -74,6 +74,8 @@
       base::ASCIIToUTF16("Jerry_1"), base::ASCIIToUTF16("id1")));
   form->other_possible_usernames.push_back(PossibleUsernamePair(
       base::ASCIIToUTF16("Jerry_2"), base::ASCIIToUTF16("id2")));
+  form->other_possible_passwords.push_back(base::ASCIIToUTF16("pass1"));
+  form->other_possible_passwords.push_back(base::ASCIIToUTF16("pass2"));
   form->password_element = base::ASCIIToUTF16("password");
   form->password_value = base::ASCIIToUTF16("test");
   form->password_value_is_default = true;
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index efd5015..65bf484 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -335,6 +335,7 @@
     "autofill_data_util_unittest.cc",
     "autofill_download_manager_unittest.cc",
     "autofill_driver_factory_unittest.cc",
+    "autofill_experiments_unittest.cc",
     "autofill_external_delegate_unittest.cc",
     "autofill_field_unittest.cc",
     "autofill_ie_toolbar_import_win_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index e727dd6..e7d0535 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -43,6 +43,8 @@
     base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kAutofillSuppressDisusedAddresses{
     "AutofillSuppressDisusedAddresses", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillUpstreamAllowAllEmailDomains{
+    "AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillUpstreamRequestCvcIfMissing{
     "AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillUpstreamShowGoogleLogo{
@@ -238,8 +240,12 @@
   if (user_email.empty())
     return false;
   std::string domain = gaia::ExtractDomainName(user_email);
-  if (!(domain == "googlemail.com" || domain == "gmail.com" ||
-        domain == "google.com")) {
+  // If the "allow all email domains" flag is off, restrict credit card upload
+  // only to Google Accounts with @googlemail, @gmail, @google, or @chromium
+  // domains.
+  if (!base::FeatureList::IsEnabled(kAutofillUpstreamAllowAllEmailDomains) &&
+      !(domain == "googlemail.com" || domain == "gmail.com" ||
+        domain == "google.com" || domain == "chromium.org")) {
     return false;
   }
 
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index 6fcc5168..33c3d15 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -34,6 +34,7 @@
 extern const base::Feature kAutofillOfferLocalSaveIfServerCardManuallyEntered;
 extern const base::Feature kAutofillRationalizeFieldTypePredictions;
 extern const base::Feature kAutofillSuppressDisusedAddresses;
+extern const base::Feature kAutofillUpstreamAllowAllEmailDomains;
 extern const base::Feature kAutofillUpstreamRequestCvcIfMissing;
 extern const base::Feature kAutofillUpstreamShowGoogleLogo;
 extern const base::Feature kAutofillUpstreamShowNewUi;
diff --git a/components/autofill/core/browser/autofill_experiments_unittest.cc b/components/autofill/core/browser/autofill_experiments_unittest.cc
new file mode 100644
index 0000000..ef45b490
--- /dev/null
+++ b/components/autofill/core/browser/autofill_experiments_unittest.cc
@@ -0,0 +1,181 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_experiments.h"
+
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/common/autofill_pref_names.h"
+#include "components/autofill/core/common/autofill_switches.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/sync/driver/fake_sync_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+namespace {
+
+class TestSyncService : public syncer::FakeSyncService {
+ public:
+  TestSyncService()
+      : can_sync_start_(true),
+        preferred_data_types_(syncer::ModelTypeSet::All()),
+        is_engine_initialized_(true),
+        is_using_secondary_passphrase_(false) {}
+
+  bool CanSyncStart() const override { return can_sync_start_; }
+
+  syncer::ModelTypeSet GetPreferredDataTypes() const override {
+    return preferred_data_types_;
+  }
+
+  bool IsEngineInitialized() const override { return is_engine_initialized_; }
+
+  bool IsUsingSecondaryPassphrase() const override {
+    return is_using_secondary_passphrase_;
+  }
+
+  void SetCanSyncStart(bool can_sync_start) {
+    can_sync_start_ = can_sync_start;
+  }
+
+  void SetPreferredDataTypes(syncer::ModelTypeSet preferred_data_types) {
+    preferred_data_types_ = preferred_data_types;
+  }
+
+  void SetIsEngineInitialized(bool is_engine_initialized) {
+    is_engine_initialized_ = is_engine_initialized;
+  }
+
+  void SetIsUsingSecondaryPassphrase(bool is_using_secondary_passphrase) {
+    is_using_secondary_passphrase_ = is_using_secondary_passphrase;
+  }
+
+ private:
+  bool can_sync_start_;
+  syncer::ModelTypeSet preferred_data_types_;
+  bool is_engine_initialized_;
+  bool is_using_secondary_passphrase_;
+};
+
+}  // namespace
+
+class AutofillExperimentsTest : public testing::Test {
+ public:
+  AutofillExperimentsTest() {}
+
+ protected:
+  void SetUp() override {
+    pref_service_.registry()->RegisterBooleanPref(
+        prefs::kAutofillWalletImportEnabled, true);
+  }
+
+  bool IsCreditCardUploadEnabled() {
+    return IsCreditCardUploadEnabled("john.smith@gmail.com", "Default");
+  }
+
+  bool IsCreditCardUploadEnabled(const std::string& user_email) {
+    return IsCreditCardUploadEnabled(user_email, "Default");
+  }
+
+  bool IsCreditCardUploadEnabled(const std::string& user_email,
+                                 const std::string& field_trial_value) {
+    base::FieldTrialList field_trial_list(nullptr);
+    base::FieldTrialList::CreateFieldTrial("OfferUploadCreditCards",
+                                           field_trial_value);
+
+    return autofill::IsCreditCardUploadEnabled(&pref_service_, &sync_service_,
+                                               user_email);
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+  TestingPrefServiceSimple pref_service_;
+  TestSyncService sync_service_;
+};
+
+TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceCannotStart) {
+  sync_service_.SetCanSyncStart(false);
+  EXPECT_FALSE(IsCreditCardUploadEnabled());
+}
+
+TEST_F(AutofillExperimentsTest,
+       DenyUpload_SyncServiceDoesNotHaveAutofillProfilePreferredDataType) {
+  sync_service_.SetPreferredDataTypes(syncer::ModelTypeSet());
+  EXPECT_FALSE(IsCreditCardUploadEnabled());
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceEngineNotInitialized) {
+  sync_service_.SetIsEngineInitialized(false);
+  EXPECT_FALSE(IsCreditCardUploadEnabled());
+}
+
+TEST_F(AutofillExperimentsTest,
+       DenyUpload_SyncServiceUsingSecondaryPassphrase) {
+  sync_service_.SetIsUsingSecondaryPassphrase(true);
+  EXPECT_FALSE(IsCreditCardUploadEnabled());
+}
+
+TEST_F(AutofillExperimentsTest,
+       DenyUpload_AutofillWalletImportEnabledPrefIsDisabled) {
+  pref_service_.SetBoolean(prefs::kAutofillWalletImportEnabled, false);
+  EXPECT_FALSE(IsCreditCardUploadEnabled());
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_EmptyUserEmail) {
+  EXPECT_FALSE(IsCreditCardUploadEnabled(""));
+}
+
+TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithGoogleDomain) {
+  EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com"));
+  EXPECT_TRUE(IsCreditCardUploadEnabled("googler@google.com"));
+  EXPECT_TRUE(IsCreditCardUploadEnabled("old.school@googlemail.com"));
+  EXPECT_TRUE(IsCreditCardUploadEnabled("code.committer@chromium.org"));
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_UserEmailWithNonGoogleDomain) {
+  EXPECT_FALSE(IsCreditCardUploadEnabled("cool.user@hotmail.com"));
+  EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@johnsmith.com"));
+  EXPECT_FALSE(IsCreditCardUploadEnabled("fake.googler@google.net"));
+  EXPECT_FALSE(IsCreditCardUploadEnabled("fake.committer@chromium.com"));
+}
+
+TEST_F(AutofillExperimentsTest,
+       AllowUpload_UserEmailWithNonGoogleDomainIfExperimentEnabled) {
+  scoped_feature_list_.InitAndEnableFeature(
+      kAutofillUpstreamAllowAllEmailDomains);
+  EXPECT_TRUE(IsCreditCardUploadEnabled("cool.user@hotmail.com"));
+  EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@johnsmith.com"));
+  EXPECT_TRUE(IsCreditCardUploadEnabled("fake.googler@google.net"));
+  EXPECT_TRUE(IsCreditCardUploadEnabled("fake.committer@chromium.com"));
+}
+
+TEST_F(AutofillExperimentsTest,
+       AllowUpload_CommandLineSwitchOnEvenIfGroupDisabled) {
+  base::test::ScopedCommandLine scoped_command_line;
+  scoped_command_line.GetProcessCommandLine()->AppendSwitch(
+      switches::kEnableOfferUploadCreditCards);
+  EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Disabled"));
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_CommandLineSwitchOff) {
+  base::test::ScopedCommandLine scoped_command_line;
+  scoped_command_line.GetProcessCommandLine()->AppendSwitch(
+      switches::kDisableOfferUploadCreditCards);
+  EXPECT_FALSE(IsCreditCardUploadEnabled());
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameEmpty) {
+  EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@gmail.com", ""));
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameDisabled) {
+  EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Disabled"));
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameAnythingButDisabled) {
+  EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Enabled"));
+}
+
+}  // namespace autofill
diff --git a/components/browsing_data/content/counters/site_settings_counter.cc b/components/browsing_data/content/counters/site_settings_counter.cc
index 2e8e6c4c..9942a21 100644
--- a/components/browsing_data/content/counters/site_settings_counter.cc
+++ b/components/browsing_data/content/counters/site_settings_counter.cc
@@ -46,7 +46,10 @@
     map_->GetSettingsForOneType(type, content_settings::ResourceIdentifier(),
                                 &content_settings_list);
     for (const auto& content_setting : content_settings_list) {
-      if (content_setting.source == "preference") {
+      // TODO(crbug.com/762560): Check the conceptual SettingSource instead of
+      // ContentSettingPatternSource.source
+      if (content_setting.source == "preference" ||
+          content_setting.source == "notification_android") {
         base::Time last_modified = map_->GetSettingLastModifiedDate(
             content_setting.primary_pattern, content_setting.secondary_pattern,
             type);
diff --git a/components/browsing_data/core/counters/passwords_counter.cc b/components/browsing_data/core/counters/passwords_counter.cc
index 9ee62cf..e606a670 100644
--- a/components/browsing_data/core/counters/passwords_counter.cc
+++ b/components/browsing_data/core/counters/passwords_counter.cc
@@ -43,7 +43,8 @@
 }
 
 void PasswordsCounter::Count() {
-  cancelable_task_tracker()->TryCancelAll();
+  CancelAllRequests();
+
   // TODO(msramek): We don't actually need the logins themselves, just their
   // count. Consider implementing |PasswordStore::CountAutofillableLogins|.
   // This custom request should also allow us to specify the time range, so that
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc
index 1242611..a1f8295 100644
--- a/components/component_updater/component_updater_service.cc
+++ b/components/component_updater/component_updater_service.cc
@@ -275,7 +275,7 @@
 
   // Check if the request is too soon.
   const auto* component_state(GetComponentState(id));
-  if (component_state) {
+  if (component_state && !component_state->last_check.is_null()) {
     base::TimeDelta delta =
         base::TimeTicks::Now() - component_state->last_check;
     if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
diff --git a/components/download/components_unittests.filter b/components/download/components_unittests.filter
index f694bb6..3a41428 100644
--- a/components/download/components_unittests.filter
+++ b/components/download/components_unittests.filter
@@ -9,6 +9,7 @@
 DownloadServiceModelImplTest.*
 DownloadStoreTest.*
 FileMonitorTest.*
+NavigationMonitorImplTest.*
 NetworkListenerTest.*
 ProtoConversionsTest.*
 ServiceConfigImplTest.*
\ No newline at end of file
diff --git a/components/download/content/DEPS b/components/download/content/DEPS
index b72efab..98f5933d 100644
--- a/components/download/content/DEPS
+++ b/components/download/content/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/keyed_service",
   "+components/leveldb_proto",
   "+content/public/browser",
   "+content/public/test",
diff --git a/components/download/content/factory/BUILD.gn b/components/download/content/factory/BUILD.gn
index 46f834f0..96ccec7 100644
--- a/components/download/content/factory/BUILD.gn
+++ b/components/download/content/factory/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "download_service_factory.cc",
     "download_service_factory.h",
+    "navigation_monitor_factory.cc",
+    "navigation_monitor_factory.h",
   ]
 
   public_deps = [
@@ -17,6 +19,7 @@
     "//components/download/content/internal",
     "//components/download/internal",
     "//components/download/internal/proto",
+    "//components/keyed_service/content",
     "//components/leveldb_proto",
     "//content/public/browser",
     "//net",
diff --git a/components/download/content/factory/download_service_factory.cc b/components/download/content/factory/download_service_factory.cc
index 95fbf6a..8ccce889 100644
--- a/components/download/content/factory/download_service_factory.cc
+++ b/components/download/content/factory/download_service_factory.cc
@@ -4,6 +4,7 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/ptr_util.h"
+#include "components/download/content/factory/navigation_monitor_factory.h"
 #include "components/download/content/internal/download_driver_impl.h"
 #include "components/download/internal/client_set.h"
 #include "components/download/internal/config.h"
@@ -44,14 +45,18 @@
   auto model = base::MakeUnique<ModelImpl>(std::move(store));
   auto device_status_listener =
       base::MakeUnique<DeviceStatusListener>(config->network_change_delay);
+  NavigationMonitor* navigation_monitor =
+      NavigationMonitorFactory::GetForBrowserContext(
+          download_manager->GetBrowserContext());
   auto scheduler = base::MakeUnique<SchedulerImpl>(
       task_scheduler.get(), config.get(), client_set.get());
   auto file_monitor = base::MakeUnique<FileMonitorImpl>(
       files_storage_dir, background_task_runner, config->file_keep_alive_time);
   auto controller = base::MakeUnique<ControllerImpl>(
       config.get(), std::move(client_set), std::move(driver), std::move(model),
-      std::move(device_status_listener), std::move(scheduler),
-      std::move(task_scheduler), std::move(file_monitor), files_storage_dir);
+      std::move(device_status_listener), navigation_monitor,
+      std::move(scheduler), std::move(task_scheduler), std::move(file_monitor),
+      files_storage_dir);
   return new DownloadServiceImpl(std::move(config), std::move(controller));
 }
 
diff --git a/components/download/content/factory/navigation_monitor_factory.cc b/components/download/content/factory/navigation_monitor_factory.cc
new file mode 100644
index 0000000..c4b408a
--- /dev/null
+++ b/components/download/content/factory/navigation_monitor_factory.cc
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/content/factory/navigation_monitor_factory.h"
+
+#include "components/download/internal/navigation_monitor_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace download {
+
+// static
+NavigationMonitorFactory* NavigationMonitorFactory::GetInstance() {
+  return base::Singleton<NavigationMonitorFactory>::get();
+}
+
+download::NavigationMonitor* NavigationMonitorFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<download::NavigationMonitor*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+NavigationMonitorFactory::NavigationMonitorFactory()
+    : BrowserContextKeyedServiceFactory(
+          "download::NavigationMonitor",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+NavigationMonitorFactory::~NavigationMonitorFactory() = default;
+
+KeyedService* NavigationMonitorFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new NavigationMonitorImpl();
+}
+
+content::BrowserContext* NavigationMonitorFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return context;
+}
+
+}  // namespace download
diff --git a/components/download/content/factory/navigation_monitor_factory.h b/components/download/content/factory/navigation_monitor_factory.h
new file mode 100644
index 0000000..327b4976
--- /dev/null
+++ b/components/download/content/factory/navigation_monitor_factory.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOWNLOAD_CONTENT_FACTORY_NAVIGATION_MONITOR_FACTORY_H_
+#define COMPONENTS_DOWNLOAD_CONTENT_FACTORY_NAVIGATION_MONITOR_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace download {
+
+class NavigationMonitor;
+
+// Creates the DownloadNavigationMonitor instance.
+class NavigationMonitorFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns singleton instance of DownloadServiceFactory.
+  static NavigationMonitorFactory* GetInstance();
+
+  // Helper method to create the DownloadNavigationMonitor instance from
+  // |context| if it doesn't exist.
+  static download::NavigationMonitor* GetForBrowserContext(
+      content::BrowserContext* context);
+
+ private:
+  friend struct base::DefaultSingletonTraits<NavigationMonitorFactory>;
+
+  NavigationMonitorFactory();
+  ~NavigationMonitorFactory() override;
+
+  // BrowserContextKeyedServiceFactory implementation.
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(NavigationMonitorFactory);
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_CONTENT_FACTORY_NAVIGATION_MONITOR_FACTORY_H_
diff --git a/components/download/content/public/BUILD.gn b/components/download/content/public/BUILD.gn
index 4cb80da..3bbc9b6 100644
--- a/components/download/content/public/BUILD.gn
+++ b/components/download/content/public/BUILD.gn
@@ -11,6 +11,8 @@
   sources = [
     "all_download_item_notifier.cc",
     "all_download_item_notifier.h",
+    "download_navigation_observer.cc",
+    "download_navigation_observer.h",
   ]
 
   public_deps = [
@@ -18,6 +20,7 @@
   ]
 
   deps = [
+    "//components/download/public",
     "//content/public/browser",
   ]
 }
diff --git a/components/download/content/public/download_navigation_observer.cc b/components/download/content/public/download_navigation_observer.cc
new file mode 100644
index 0000000..e0636797
--- /dev/null
+++ b/components/download/content/public/download_navigation_observer.cc
@@ -0,0 +1,47 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/content/public/download_navigation_observer.h"
+
+#include "base/memory/ptr_util.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(download::DownloadNavigationObserver);
+
+namespace download {
+
+// static
+void DownloadNavigationObserver::CreateForWebContents(
+    content::WebContents* web_contents,
+    NavigationMonitor* navigation_monitor) {
+  DCHECK(web_contents);
+  if (!FromWebContents(web_contents)) {
+    web_contents->SetUserData(UserDataKey(),
+                              base::MakeUnique<DownloadNavigationObserver>(
+                                  web_contents, navigation_monitor));
+  }
+}
+
+DownloadNavigationObserver::DownloadNavigationObserver(
+    content::WebContents* web_contents,
+    NavigationMonitor* navigation_monitor)
+    : content::WebContentsObserver(web_contents),
+      navigation_monitor_(navigation_monitor) {}
+
+DownloadNavigationObserver::~DownloadNavigationObserver() = default;
+
+void DownloadNavigationObserver::DidStartLoading() {
+  NotifyNavigationEvent(NavigationEvent::START_NAVIGATION);
+}
+
+void DownloadNavigationObserver::DidStopLoading() {
+  NotifyNavigationEvent(NavigationEvent::NAVIGATION_COMPLETE);
+}
+
+void DownloadNavigationObserver::NotifyNavigationEvent(
+    NavigationEvent navigation_event) {
+  DCHECK(navigation_monitor_);
+  navigation_monitor_->OnNavigationEvent(navigation_event);
+}
+
+}  // namespace download
diff --git a/components/download/content/public/download_navigation_observer.h b/components/download/content/public/download_navigation_observer.h
new file mode 100644
index 0000000..a817953
--- /dev/null
+++ b/components/download/content/public/download_navigation_observer.h
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_DOWNLOAD_NAVIGATION_OBSERVER_H_
+#define COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_DOWNLOAD_NAVIGATION_OBSERVER_H_
+
+#include "base/macros.h"
+#include "components/download/public/navigation_monitor.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace download {
+
+// Forwards navigation events to download service.
+// Each DownloadNavigationObserver is associated with a particular WebContents.
+class DownloadNavigationObserver
+    : public content::WebContentsObserver,
+      public content::WebContentsUserData<DownloadNavigationObserver> {
+ public:
+  static void CreateForWebContents(content::WebContents* web_contents,
+                                   NavigationMonitor* navigation_monitor);
+
+  DownloadNavigationObserver(content::WebContents* web_contents,
+                             NavigationMonitor* navigation_monitor);
+  ~DownloadNavigationObserver() override;
+
+ private:
+  friend class content::WebContentsUserData<DownloadNavigationObserver>;
+
+  // content::WebContentsObserver implementation.
+  void DidStartLoading() override;
+  void DidStopLoading() override;
+
+  // Notifies |navigation_monitor_| about navigation events.
+  void NotifyNavigationEvent(NavigationEvent navigation_event);
+
+  // Used to inform the navigation events to download systems.
+  NavigationMonitor* navigation_monitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadNavigationObserver);
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_DOWNLOAD_NAVIGATION_OBSERVER_H_
diff --git a/components/download/internal/BUILD.gn b/components/download/internal/BUILD.gn
index 04f100c..5fd2a8b 100644
--- a/components/download/internal/BUILD.gn
+++ b/components/download/internal/BUILD.gn
@@ -40,6 +40,8 @@
     "model.h",
     "model_impl.cc",
     "model_impl.h",
+    "navigation_monitor_impl.cc",
+    "navigation_monitor_impl.h",
     "proto_conversions.cc",
     "proto_conversions.h",
     "scheduler/device_status.cc",
@@ -108,6 +110,7 @@
     "entry_utils_unittest.cc",
     "file_monitor_unittest.cc",
     "model_impl_unittest.cc",
+    "navigation_monitor_impl_unittests.cc",
     "proto_conversions_unittest.cc",
     "scheduler/device_status_listener_unittest.cc",
     "scheduler/scheduler_impl_unittest.cc",
diff --git a/components/download/internal/controller_impl.cc b/components/download/internal/controller_impl.cc
index 89973a77..33f82c5 100644
--- a/components/download/internal/controller_impl.cc
+++ b/components/download/internal/controller_impl.cc
@@ -21,6 +21,7 @@
 #include "components/download/internal/stats.h"
 #include "components/download/public/client.h"
 #include "components/download/public/download_metadata.h"
+#include "components/download/public/navigation_monitor.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace download {
@@ -78,6 +79,7 @@
     std::unique_ptr<DownloadDriver> driver,
     std::unique_ptr<Model> model,
     std::unique_ptr<DeviceStatusListener> device_status_listener,
+    NavigationMonitor* navigation_monitor,
     std::unique_ptr<Scheduler> scheduler,
     std::unique_ptr<TaskScheduler> task_scheduler,
     std::unique_ptr<FileMonitor> file_monitor,
diff --git a/components/download/internal/controller_impl.h b/components/download/internal/controller_impl.h
index b2df0c5..96a1a62 100644
--- a/components/download/internal/controller_impl.h
+++ b/components/download/internal/controller_impl.h
@@ -30,6 +30,7 @@
 class DownloadDriver;
 class FileMonitor;
 class Model;
+class NavigationMonitor;
 class Scheduler;
 
 struct Configuration;
@@ -49,6 +50,7 @@
                  std::unique_ptr<DownloadDriver> driver,
                  std::unique_ptr<Model> model,
                  std::unique_ptr<DeviceStatusListener> device_status_listener,
+                 NavigationMonitor* navigation_monitor,
                  std::unique_ptr<Scheduler> scheduler,
                  std::unique_ptr<TaskScheduler> task_scheduler,
                  std::unique_ptr<FileMonitor> file_monitor,
diff --git a/components/download/internal/controller_impl_unittest.cc b/components/download/internal/controller_impl_unittest.cc
index fa235024..2f1cb04 100644
--- a/components/download/internal/controller_impl_unittest.cc
+++ b/components/download/internal/controller_impl_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/download/internal/entry_utils.h"
 #include "components/download/internal/file_monitor.h"
 #include "components/download/internal/model_impl.h"
+#include "components/download/internal/navigation_monitor_impl.h"
 #include "components/download/internal/scheduler/scheduler.h"
 #include "components/download/internal/stats.h"
 #include "components/download/internal/test/empty_client.h"
@@ -179,7 +180,7 @@
     controller_ = base::MakeUnique<ControllerImpl>(
         config_.get(), std::move(client_set), std::move(driver),
         std::move(model), std::move(device_status_listener),
-        std::move(scheduler), std::move(task_scheduler),
+        &navigation_monitor, std::move(scheduler), std::move(task_scheduler),
         std::move(file_monitor), download_file_dir);
   }
 
@@ -212,6 +213,7 @@
 
   std::unique_ptr<ControllerImpl> controller_;
   std::unique_ptr<Configuration> config_;
+  NavigationMonitorImpl navigation_monitor;
   test::MockClient* client_;
   test::TestDownloadDriver* driver_;
   test::TestStore* store_;
diff --git a/components/download/internal/navigation_monitor_impl.cc b/components/download/internal/navigation_monitor_impl.cc
new file mode 100644
index 0000000..9b8df1a
--- /dev/null
+++ b/components/download/internal/navigation_monitor_impl.cc
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/internal/navigation_monitor_impl.h"
+
+#include "base/logging.h"
+
+namespace download {
+
+NavigationMonitorImpl::NavigationMonitorImpl() = default;
+
+NavigationMonitorImpl::~NavigationMonitorImpl() = default;
+
+void NavigationMonitorImpl::SetObserver(NavigationMonitor::Observer* observer) {
+  observer_ = observer;
+  if (observer_)
+    observer_->OnNavigationEvent();
+}
+
+void NavigationMonitorImpl::OnNavigationEvent(NavigationEvent event) {
+  // TODO(xingliu, shakti): Count navigation events and notify observer.
+  if (observer_)
+    observer_->OnNavigationEvent();
+}
+
+}  // namespace download
diff --git a/components/download/internal/navigation_monitor_impl.h b/components/download/internal/navigation_monitor_impl.h
new file mode 100644
index 0000000..6ab69bb
--- /dev/null
+++ b/components/download/internal/navigation_monitor_impl.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOWNLOAD_INTERNAL_NAVIGATION_MONITOR_IMPL_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_NAVIGATION_MONITOR_IMPL_H_
+
+#include "base/macros.h"
+#include "components/download/public/navigation_monitor.h"
+
+namespace download {
+
+class NavigationMonitorImpl : public NavigationMonitor {
+ public:
+  NavigationMonitorImpl();
+  ~NavigationMonitorImpl() override;
+
+  // NavigationMonitor implementation.
+  void SetObserver(NavigationMonitor::Observer* observer) override;
+  void OnNavigationEvent(NavigationEvent event) override;
+
+ private:
+  NavigationMonitor::Observer* observer_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(NavigationMonitorImpl);
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_INTERNAL_NAVIGATION_MONITOR_IMPL_H_
diff --git a/components/download/internal/navigation_monitor_impl_unittests.cc b/components/download/internal/navigation_monitor_impl_unittests.cc
new file mode 100644
index 0000000..ad129ddb
--- /dev/null
+++ b/components/download/internal/navigation_monitor_impl_unittests.cc
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/internal/navigation_monitor_impl.h"
+
+#include "base/memory/ptr_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace download {
+namespace {
+
+class MockNavigationMonitorObserver : public NavigationMonitor::Observer {
+ public:
+  MockNavigationMonitorObserver() = default;
+  ~MockNavigationMonitorObserver() override = default;
+  MOCK_METHOD0(OnNavigationEvent, void());
+};
+
+class NavigationMonitorImplTest : public testing::Test {
+ public:
+  NavigationMonitorImplTest() = default;
+  ~NavigationMonitorImplTest() override = default;
+
+  void SetUp() override {
+    navigation_monitor_ = base::MakeUnique<NavigationMonitorImpl>();
+    observer_ = base::MakeUnique<MockNavigationMonitorObserver>();
+  }
+
+  void TearDown() override {
+    navigation_monitor_.reset();
+    observer_.reset();
+  }
+
+ protected:
+  std::unique_ptr<NavigationMonitorImpl> navigation_monitor_;
+  std::unique_ptr<MockNavigationMonitorObserver> observer_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NavigationMonitorImplTest);
+};
+
+// Ensures the navigation events are piped to the observer.
+TEST_F(NavigationMonitorImplTest, NavigationEventPipe) {
+  EXPECT_CALL(*observer_.get(), OnNavigationEvent())
+      .Times(1)
+      .RetiresOnSaturation();
+  navigation_monitor_->SetObserver(observer_.get());
+  // TODO(xingliu, shakti): Test navigation event counting and observer calls.
+}
+
+}  // namespace
+}  // namespace download
diff --git a/components/download/public/BUILD.gn b/components/download/public/BUILD.gn
index c394cbd..d252bc1f 100644
--- a/components/download/public/BUILD.gn
+++ b/components/download/public/BUILD.gn
@@ -19,6 +19,7 @@
     "download_task_types.h",
     "features.cc",
     "features.h",
+    "navigation_monitor.h",
     "service_config.h",
     "task_scheduler.h",
   ]
diff --git a/components/download/public/navigation_monitor.h b/components/download/public/navigation_monitor.h
new file mode 100644
index 0000000..9054e84
--- /dev/null
+++ b/components/download/public/navigation_monitor.h
@@ -0,0 +1,48 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOWNLOAD_PUBLIC_NAVIGATION_MONITOR_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_NAVIGATION_MONITOR_H_
+
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace download {
+
+// Enum used to describe navigation event from WebContentsObserver.
+enum class NavigationEvent {
+  START_NAVIGATION = 0,
+  NAVIGATION_COMPLETE = 1,
+};
+
+// NavigationMonitor receives and forwards navigation events from any web
+// contents to download service.
+//
+// NavigationMonitor outlives any WebContentsObserver that send navigation
+// events to it.
+//
+// NavigationMonitor does NOT has ownership of WebContentsObserver, and is
+// essentially a decoupled singleton that glues download service with
+// WebContents and WebContentsObserver.
+class NavigationMonitor : public KeyedService {
+ public:
+  // Used to propagates the navigation events.
+  class Observer {
+   public:
+    virtual void OnNavigationEvent() = 0;
+    virtual ~Observer() = default;
+  };
+
+  // Start to listen to navigation event.
+  virtual void SetObserver(NavigationMonitor::Observer* observer) = 0;
+
+  // Called when navigation events happen.
+  virtual void OnNavigationEvent(NavigationEvent event) = 0;
+
+ protected:
+  ~NavigationMonitor() override{};
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_PUBLIC_NAVIGATION_MONITOR_H_
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index 86b1c54..fcdadbe 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -415,13 +415,9 @@
 bool Buffer::ProduceTransferableResource(
     LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
     bool secure_output_only,
-    bool client_usage,
     viz::TransferableResource* resource) {
   TRACE_EVENT0("exo", "Buffer::ProduceTransferableResource");
-
   DCHECK(attach_count_);
-  DLOG_IF(WARNING, !release_contents_callback_.IsCancelled() && client_usage)
-      << "Producing a texture mailbox for a buffer that has not been released";
 
   // If textures are lost, destroy them to ensure that we create new ones below.
   if (contents_texture_ && contents_texture_->IsLost())
diff --git a/components/exo/buffer.h b/components/exo/buffer.h
index 7be34f8..0c722be 100644
--- a/components/exo/buffer.h
+++ b/components/exo/buffer.h
@@ -55,7 +55,6 @@
   bool ProduceTransferableResource(
       LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
       bool secure_output_only,
-      bool client_usage,
       viz::TransferableResource* resource);
 
   // This should be called when the buffer is attached to a Surface.
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc
index b14749d..457c0e3 100644
--- a/components/exo/buffer_unittest.cc
+++ b/components/exo/buffer_unittest.cc
@@ -45,8 +45,8 @@
   buffer->OnAttach();
   viz::TransferableResource resource;
   // Produce a transferable resource for the contents of the buffer.
-  bool rv = buffer->ProduceTransferableResource(frame_sink_holder, false, true,
-                                                &resource);
+  bool rv =
+      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
   ASSERT_TRUE(rv);
 
   // Release buffer.
@@ -78,8 +78,8 @@
   buffer->OnAttach();
   // Acquire a texture transferable resource for the contents of the buffer.
   viz::TransferableResource resource;
-  bool rv = buffer->ProduceTransferableResource(frame_sink_holder, false, true,
-                                                &resource);
+  bool rv =
+      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
   ASSERT_TRUE(rv);
 
   scoped_refptr<viz::ContextProvider> context_provider =
@@ -105,7 +105,7 @@
   // Producing a new texture transferable resource for the contents of the
   // buffer.
   viz::TransferableResource new_resource;
-  rv = buffer->ProduceTransferableResource(frame_sink_holder, false, false,
+  rv = buffer->ProduceTransferableResource(frame_sink_holder, false,
                                            &new_resource);
   ASSERT_TRUE(rv);
   buffer->OnDetach();
@@ -134,8 +134,8 @@
   buffer->OnAttach();
   // Acquire a texture transferable resource for the contents of the buffer.
   viz::TransferableResource resource;
-  bool rv = buffer->ProduceTransferableResource(frame_sink_holder, false, true,
-                                                &resource);
+  bool rv =
+      buffer->ProduceTransferableResource(frame_sink_holder, false, &resource);
   ASSERT_TRUE(rv);
 
   static_cast<ui::InProcessContextFactory*>(
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc
index 1831ec5c..014b4930 100644
--- a/components/exo/pointer_unittest.cc
+++ b/components/exo/pointer_unittest.cc
@@ -11,6 +11,7 @@
 #include "components/exo/buffer.h"
 #include "components/exo/pointer_delegate.h"
 #include "components/exo/shell_surface.h"
+#include "components/exo/sub_surface.h"
 #include "components/exo/surface.h"
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/test/exo_test_helper.h"
@@ -152,7 +153,8 @@
                         gfx::Vector2d(1, 1));
 
   std::unique_ptr<Surface> sub_surface(new Surface);
-  surface->AddSubSurface(sub_surface.get());
+  std::unique_ptr<SubSurface> sub(
+      new SubSurface(sub_surface.get(), surface.get()));
   surface->SetSubSurfacePosition(sub_surface.get(), gfx::Point(5, 5));
   gfx::Size sub_buffer_size(5, 5);
   std::unique_ptr<Buffer> sub_buffer(
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index b3133051a..03065ce 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -640,13 +640,6 @@
   pending_orientation_ = orientation;
 }
 
-void ShellSurface::SetRectangularShadowEnabled(bool enabled) {
-  TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadowEnabled", "enabled",
-               enabled);
-  pending_shadow_underlay_in_surface_ = false;
-  shadow_enabled_ = enabled;
-}
-
 void ShellSurface::SetRectangularShadow_DEPRECATED(
     const gfx::Rect& content_bounds) {
   TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadow_DEPRECATED",
@@ -677,12 +670,6 @@
   shadow_background_opacity_ = opacity;
 }
 
-void ShellSurface::SetFrame(bool enabled) {
-  TRACE_EVENT1("exo", "ShellSurface::SetFrame", "enabled", enabled);
-
-  frame_enabled_ = enabled;
-}
-
 void ShellSurface::SetScale(double scale) {
   TRACE_EVENT1("exo", "ShellSurface::SetScale", "scale", scale);
 
@@ -839,6 +826,25 @@
   }
 }
 
+void ShellSurface::OnSetFrame(SurfaceFrameType type) {
+  // TODO(reveman): Allow frame to change after surface has been enabled.
+  switch (type) {
+    case SurfaceFrameType::NONE:
+      frame_enabled_ = shadow_enabled_ = false;
+      break;
+    case SurfaceFrameType::NORMAL:
+      frame_enabled_ = true;
+      pending_shadow_underlay_in_surface_ = false;
+      shadow_enabled_ = true;
+      break;
+    case SurfaceFrameType::SHADOW:
+      frame_enabled_ = false;
+      pending_shadow_underlay_in_surface_ = false;
+      shadow_enabled_ = true;
+      break;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // SurfaceObserver overrides:
 
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index ef75cab..f3add701 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -200,9 +200,6 @@
   // Set the pacity of the background for the window that has a shadow.
   void SetRectangularShadowBackgroundOpacity(float opacity);
 
-  // Enable/disable window frame.
-  void SetFrame(bool enabled);
-
   // Set scale factor for surface. The scale factor will be applied to surface
   // and all descendants.
   void SetScale(double scale);
@@ -232,6 +229,7 @@
   // Overridden from SurfaceDelegate:
   void OnSurfaceCommit() override;
   void OnSurfaceContentSizeChanged() override;
+  void OnSetFrame(SurfaceFrameType type) override;
 
   // Overridden from SurfaceObserver:
   void OnSurfaceDestroying(Surface* surface) override;
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 5c80600..a22d631 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/shell_test_api.h"
+#include "ash/system/tray/system_tray.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
@@ -34,6 +35,7 @@
 #include "ui/display/display.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/screen.h"
+#include "ui/events/test/event_generator.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/shadow.h"
 #include "ui/wm/core/shadow_controller.h"
@@ -825,7 +827,7 @@
   EXPECT_FALSE(shadow->layer()->visible());
 
   // 3) Enable a shadow.
-  shell_surface->SetRectangularShadowEnabled(true);
+  shell_surface->OnSetFrame(SurfaceFrameType::SHADOW);
   surface->Commit();
   EXPECT_TRUE(shadow->layer()->visible());
 
@@ -849,14 +851,14 @@
   EXPECT_NE(new_bounds, shadow->layer()->bounds());
 
   // 5) This should disable shadow.
-  shell_surface->SetRectangularShadowEnabled(false);
+  surface->SetFrame(SurfaceFrameType::NONE);
   surface->Commit();
 
   EXPECT_EQ(wm::ShadowElevation::NONE, GetShadowElevation(window));
   EXPECT_FALSE(shadow->layer()->visible());
 
   // 6) This should enable non surface shadow.
-  shell_surface->SetRectangularShadowEnabled(true);
+  surface->SetFrame(SurfaceFrameType::SHADOW);
   surface->Commit();
 
   EXPECT_EQ(wm::ShadowElevation::DEFAULT, GetShadowElevation(window));
@@ -993,12 +995,12 @@
   // Underlay should be created even without shadow.
   ASSERT_TRUE(shell_surface->shadow_underlay());
   EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible());
-  shell_surface->SetRectangularShadowEnabled(false);
+  surface->SetFrame(SurfaceFrameType::NONE);
   surface->Commit();
   // No underlay if there is no shadow.
   EXPECT_FALSE(shell_surface->shadow_underlay());
 
-  shell_surface->SetRectangularShadowEnabled(true);
+  surface->SetFrame(SurfaceFrameType::SHADOW);
   shell_surface->SetRectangularSurfaceShadow(gfx::Rect(10, 10, 100, 100));
   surface->Commit();
 
@@ -1132,5 +1134,42 @@
   EXPECT_FALSE(compositor->IsLocked());
 }
 
+// System tray should be activated if user presses tab key while shell surface
+// is active.
+TEST_F(ShellSurfaceTest, KeyboardNavigationWithSystemTray) {
+  const gfx::Size buffer_size(800, 600);
+  std::unique_ptr<Buffer> buffer(
+      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+  std::unique_ptr<Surface> surface(new Surface());
+  std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(
+      surface.get(), nullptr, ShellSurface::BoundsMode::CLIENT, gfx::Point(),
+      true, false, ash::kShellWindowId_DefaultContainer));
+
+  surface->Attach(buffer.get());
+  surface->Commit();
+
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+
+  // Show system tray.
+  ash::SystemTray* system_tray = GetPrimarySystemTray();
+  system_tray->ShowDefaultView(ash::BUBBLE_CREATE_NEW);
+  ASSERT_TRUE(system_tray->GetWidget());
+
+  // Confirm that system tray is not active at this time.
+  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
+  EXPECT_FALSE(
+      system_tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
+
+  // Send tab key event.
+  ui::test::EventGenerator& event_generator = GetEventGenerator();
+  event_generator.PressKey(ui::VKEY_TAB, ui::EF_NONE);
+  event_generator.ReleaseKey(ui::VKEY_TAB, ui::EF_NONE);
+
+  // Confirm that system tray is activated.
+  EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
+  EXPECT_TRUE(
+      system_tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive());
+}
+
 }  // namespace
 }  // namespace exo
diff --git a/components/exo/sub_surface.h b/components/exo/sub_surface.h
index 90d57a6a..3d72d3c 100644
--- a/components/exo/sub_surface.h
+++ b/components/exo/sub_surface.h
@@ -52,6 +52,7 @@
   void OnSurfaceCommit() override;
   void OnSurfaceContentSizeChanged() override;
   bool IsSurfaceSynchronized() const override;
+  void OnSetFrame(SurfaceFrameType type) override {}
 
   // Overridden from SurfaceObserver:
   void OnSurfaceDestroying(Surface* surface) override;
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 7b0c8bc..0e87b933 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -312,6 +312,8 @@
       FindListEntry(pending_sub_surfaces_, sub_surface));
   DCHECK(ListContainsEntry(sub_surfaces_, sub_surface));
   sub_surfaces_.erase(FindListEntry(sub_surfaces_, sub_surface));
+  // Force recreating resources when the surface is added to a tree again.
+  sub_surface->SurfaceHierarchyResourcesLost();
 }
 
 void Surface::SetSubSurfacePosition(Surface* sub_surface,
@@ -416,6 +418,13 @@
   pending_state_.alpha = alpha;
 }
 
+void Surface::SetFrame(SurfaceFrameType type) {
+  TRACE_EVENT1("exo", "Surface::SetFrame", "type", static_cast<uint32_t>(type));
+
+  if (delegate_)
+    delegate_->OnSetFrame(type);
+}
+
 void Surface::Commit() {
   TRACE_EVENT0("exo", "Surface::Commit");
 
@@ -426,7 +435,6 @@
 
 void Surface::CommitSurfaceHierarchy(
     const gfx::Point& origin,
-    LayerTreeFrameSinkHolder* frame_sink_holder,
     std::list<FrameCallback>* frame_callbacks,
     std::list<PresentationCallback>* presentation_callbacks) {
   if (needs_commit_surface_) {
@@ -449,10 +457,8 @@
     // We update contents if Attach() has been called since last commit.
     if (has_pending_contents_) {
       has_pending_contents_ = false;
-
       current_buffer_ = std::move(pending_buffer_);
-
-      UpdateResource(frame_sink_holder, true);
+      needs_update_resource_ = true;
     }
 
     // Move pending frame callbacks to the end of frame_callbacks.
@@ -506,8 +512,8 @@
     // Synchronsouly commit all pending state of the sub-surface and its
     // decendents.
     sub_surface->CommitSurfaceHierarchy(
-        origin + sub_surface_entry.second.OffsetFromOrigin(), frame_sink_holder,
-        frame_callbacks, presentation_callbacks);
+        origin + sub_surface_entry.second.OffsetFromOrigin(), frame_callbacks,
+        presentation_callbacks);
   }
 }
 
@@ -527,6 +533,9 @@
         device_scale_factor, frame_sink_holder, frame);
   }
 
+  if (needs_update_resource_)
+    UpdateResource(frame_sink_holder);
+
   AppendContentsToFrame(origin, device_scale_factor, frame);
 
   DCHECK(
@@ -616,12 +625,13 @@
   window_->SetProperty(kStylusOnlyKey, true);
 }
 
-void Surface::RecreateResources(LayerTreeFrameSinkHolder* frame_sink_holder) {
+void Surface::SurfaceHierarchyResourcesLost() {
+  // Update resource and full damage are needed for next frame.
+  needs_update_resource_ = true;
   damage_.setRect(
       SkIRect::MakeWH(content_size_.width(), content_size_.height()));
-  UpdateResource(frame_sink_holder, false);
   for (const auto& sub_surface : sub_surfaces_)
-    sub_surface.first->RecreateResources(frame_sink_holder);
+    sub_surface.first->SurfaceHierarchyResourcesLost();
 }
 
 bool Surface::FillsBoundsOpaquely() const {
@@ -680,14 +690,22 @@
   buffer_ = buffer;
 }
 
-void Surface::UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder,
-                             bool client_usage) {
-  if (current_buffer_.buffer() &&
-      current_buffer_.buffer()->ProduceTransferableResource(
-          frame_sink_holder, state_.only_visible_on_secure_output, client_usage,
-          &current_resource_)) {
-    current_resource_has_alpha_ =
-        FormatHasAlpha(current_buffer_.buffer()->GetFormat());
+void Surface::UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder) {
+  DCHECK(needs_update_resource_);
+  needs_update_resource_ = false;
+  if (current_buffer_.buffer()) {
+    if (current_buffer_.buffer()->ProduceTransferableResource(
+            frame_sink_holder, state_.only_visible_on_secure_output,
+            &current_resource_)) {
+      current_resource_has_alpha_ =
+          FormatHasAlpha(current_buffer_.buffer()->GetFormat());
+    } else {
+      current_resource_.id = 0;
+      // Use the buffer's size, so the AppendContentsToFrame() will append
+      // a SolidColorDrawQuad with the buffer's size.
+      current_resource_.size = current_buffer_.buffer()->GetSize();
+      current_resource_has_alpha_ = false;
+    }
   } else {
     current_resource_.id = 0;
     current_resource_.size = gfx::Size();
@@ -741,13 +759,17 @@
   buffer_to_target_matrix.postTranslate(origin.x(), origin.y());
   buffer_to_target_matrix.postScale(device_scale_factor, device_scale_factor);
 
+  bool are_contents_opaque =
+      !current_resource_has_alpha_ || state_.blend_mode == SkBlendMode::kSrc ||
+      state_.opaque_region.contains(gfx::RectToSkIRect(output_rect));
+
   viz::SharedQuadState* quad_state =
       render_pass->CreateAndAppendSharedQuadState();
   quad_state->SetAll(
       gfx::Transform(buffer_to_target_matrix),
       gfx::Rect(content_size_) /* quad_layer_rect */,
       output_rect /* visible_quad_layer_rect */, gfx::Rect() /* clip_rect */,
-      false /* is_clipped */, state_.alpha /* opacity */,
+      false /* is_clipped */, are_contents_opaque, state_.alpha /* opacity */,
       SkBlendMode::kSrcOver /* blend_mode */, 0 /* sorting_context_id */);
 
   if (current_resource_.id) {
@@ -768,13 +790,9 @@
       cc::TextureDrawQuad* texture_quad =
           render_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
       float vertex_opacity[4] = {1.0, 1.0, 1.0, 1.0};
-      bool needs_blending =
-          current_resource_has_alpha_ &&
-          state_.blend_mode != SkBlendMode::kSrc &&
-          !state_.opaque_region.contains(gfx::RectToSkIRect(output_rect));
 
       texture_quad->SetNew(
-          quad_state, quad_rect, quad_rect, needs_blending,
+          quad_state, quad_rect, quad_rect, !are_contents_opaque,
           current_resource_.id, true /* premultiplied_alpha */, uv_top_left,
           uv_bottom_right, SK_ColorTRANSPARENT /* background_color */,
           vertex_opacity, false /* y_flipped */, false /* nearest_neighbor */,
@@ -802,10 +820,11 @@
         << ") most be expressible using integers when viewport is not set";
     content_size = gfx::ToCeiledSize(state_.crop.size());
   } else {
-    content_size = gfx::ToCeiledSize(
-        gfx::ScaleSize(gfx::SizeF(ToTransformedSize(current_resource_.size,
-                                                    state_.buffer_transform)),
-                       1.0f / state_.buffer_scale));
+    auto size = current_buffer_.buffer() ? current_buffer_.buffer()->GetSize()
+                                         : gfx::Size();
+    content_size = gfx::ToCeiledSize(gfx::ScaleSize(
+        gfx::SizeF(ToTransformedSize(size, state_.buffer_transform)),
+        1.0f / state_.buffer_scale));
   }
 
   // Enable/disable sub-surface based on if it has contents.
diff --git a/components/exo/surface.h b/components/exo/surface.h
index bb62e99..f73180b 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "components/exo/layer_tree_frame_sink_holder.h"
+#include "components/exo/surface_delegate.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/resources/transferable_resource.h"
 #include "third_party/skia/include/core/SkBlendMode.h"
@@ -41,7 +42,6 @@
 class Buffer;
 class LayerTreeFrameSinkHolder;
 class Pointer;
-class SurfaceDelegate;
 class SurfaceObserver;
 class Surface;
 
@@ -132,6 +132,9 @@
   // This sets the alpha value that will be applied to the whole surface.
   void SetAlpha(float alpha);
 
+  // Request that surface should have the specified frame type.
+  void SetFrame(SurfaceFrameType type);
+
   // Surface state (damage regions, attached buffers, etc.) is double-buffered.
   // A Commit() call atomically applies all pending state, replacing the
   // current state. Commit() is not guaranteed to be synchronous. See
@@ -143,7 +146,6 @@
   // sub-surface with pending state.
   void CommitSurfaceHierarchy(
       const gfx::Point& origin,
-      LayerTreeFrameSinkHolder* frame_sink_holder,
       std::list<FrameCallback>* frame_callbacks,
       std::list<PresentationCallback>* presentation_callbacks);
 
@@ -205,8 +207,8 @@
   // Enables 'stylus-only' mode for the associated window.
   void SetStylusOnly();
 
-  // Recreates resources for the surface and sub surfaces.
-  void RecreateResources(LayerTreeFrameSinkHolder* frame_sink_holder);
+  // Notify surface that resources and subsurfaces' resources have been lost.
+  void SurfaceHierarchyResourcesLost();
 
   // Returns true if the surface's bounds should be filled opaquely.
   bool FillsBoundsOpaquely() const;
@@ -256,8 +258,7 @@
   // contents of the attached buffer (or id 0, if no buffer is attached).
   // UpdateSurface must be called afterwards to ensure the release callback
   // will be called.
-  void UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder,
-                      bool client_usage);
+  void UpdateResource(LayerTreeFrameSinkHolder* frame_sink_holder);
 
   // Puts the current surface into a draw quad, and appends the draw quads into
   // the |frame|.
@@ -265,6 +266,7 @@
                              float device_scale_factor,
                              cc::CompositorFrame* frame);
 
+  // Update surface content size base on current buffer size.
   void UpdateContentSize();
 
   // This returns true when the surface has some contents assigned to it.
@@ -336,6 +338,9 @@
   // CommitSurfaceHierarchy() has not yet been called.
   bool needs_commit_surface_ = false;
 
+  // This is true if UpdateResources() should be called.
+  bool needs_update_resource_ = true;
+
   // This is set when the compositing starts and passed to active frame
   // callbacks when compositing successfully ends.
   base::TimeTicks last_compositing_start_time_;
diff --git a/components/exo/surface_delegate.h b/components/exo/surface_delegate.h
index 2307cf2..a8b3109 100644
--- a/components/exo/surface_delegate.h
+++ b/components/exo/surface_delegate.h
@@ -7,6 +7,9 @@
 
 namespace exo {
 
+// Frame types that can be used to decorate a surface.
+enum class SurfaceFrameType { NONE, NORMAL, SHADOW };
+
 // Handles events on surfaces in context-specific ways.
 class SurfaceDelegate {
  public:
@@ -20,6 +23,9 @@
   // double-buffered state should be synchronized with parent surface.
   virtual bool IsSurfaceSynchronized() const = 0;
 
+  // Called when surface was requested specific frame type.
+  virtual void OnSetFrame(SurfaceFrameType type) = 0;
+
  protected:
   virtual ~SurfaceDelegate() {}
 };
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index 9d31f381..6d3c580 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -107,6 +107,8 @@
     host_window_->SetBounds(
         gfx::Rect(host_window_->bounds().origin(), gfx::Size()));
     root_surface_->SetSurfaceDelegate(nullptr);
+    // Force recreating resources when the surface is added to a tree again.
+    root_surface_->SurfaceHierarchyResourcesLost();
     root_surface_ = nullptr;
 
     active_frame_callbacks_.splice(active_frame_callbacks_.end(),
@@ -195,9 +197,8 @@
 // SurfaceDelegate overrides:
 
 void SurfaceTreeHost::OnSurfaceCommit() {
-  root_surface_->CommitSurfaceHierarchy(
-      gfx::Point(), layer_tree_frame_sink_holder_.get(), &frame_callbacks_,
-      &presentation_callbacks_);
+  root_surface_->CommitSurfaceHierarchy(gfx::Point(), &frame_callbacks_,
+                                        &presentation_callbacks_);
   SubmitCompositorFrame();
 }
 
@@ -270,7 +271,7 @@
 void SurfaceTreeHost::OnLostResources() {
   if (!host_window_->GetSurfaceId().is_valid() || !root_surface_)
     return;
-  root_surface_->RecreateResources(layer_tree_frame_sink_holder_.get());
+  root_surface_->SurfaceHierarchyResourcesLost();
   SubmitCompositorFrame();
 }
 
diff --git a/components/exo/surface_tree_host.h b/components/exo/surface_tree_host.h
index 7a67a60..437a05d 100644
--- a/components/exo/surface_tree_host.h
+++ b/components/exo/surface_tree_host.h
@@ -85,6 +85,7 @@
   void OnSurfaceCommit() override;
   void OnSurfaceContentSizeChanged() override;
   bool IsSurfaceSynchronized() const override;
+  void OnSetFrame(SurfaceFrameType type) override {}
 
   // Overridden from aura::WindowObserver:
   void OnWindowAddedToRootWindow(aura::Window* window) override;
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index f1bae38..a26ce41 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -19,6 +19,27 @@
   }
 }
 
+config("aura_shell_protocol_config") {
+  include_dirs = [ "." ]
+}
+
+source_set("aura_shell_protocol") {
+  sources = [
+    "aura-shell-client-protocol.h",
+    "aura-shell-server-protocol.h",
+    "aura-shell-protocol.c",
+  ]
+
+  deps = [
+    "//third_party/wayland:wayland_util",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+
+  public_configs = [ ":aura_shell_protocol_config" ]
+}
+
 source_set("wayland") {
   sources = [
     "scoped_wl.cc",
@@ -30,6 +51,7 @@
   defines = [ "EXO_IMPLEMENTATION" ]
 
   deps = [
+    ":aura_shell_protocol",
     "//ash",
     "//ash/public/cpp:ash_public_cpp",
     "//base",
@@ -100,6 +122,7 @@
     "clients/client_helper.h",
   ]
   deps = [
+    ":aura_shell_protocol",
     "//base",
     "//skia",
     "//third_party/wayland:wayland_client",
diff --git a/components/exo/wayland/aura-shell-client-protocol.h b/components/exo/wayland/aura-shell-client-protocol.h
new file mode 100644
index 0000000..2792ac45
--- /dev/null
+++ b/components/exo/wayland/aura-shell-client-protocol.h
@@ -0,0 +1,224 @@
+/* Generated by wayland-scanner 1.13.0 */
+
+#ifndef AURA_SHELL_CLIENT_PROTOCOL_H
+#define AURA_SHELL_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_aura_shell The aura_shell protocol
+ * @section page_ifaces_aura_shell Interfaces
+ * - @subpage page_iface_zaura_shell - aura_shell
+ * - @subpage page_iface_zaura_surface - aura shell interface to a wl_surface
+ * @section page_copyright_aura_shell Copyright
+ * <pre>
+ *
+ * Copyright 2017 The Chromium Authors.
+ *
+ * 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_surface;
+struct zaura_shell;
+struct zaura_surface;
+
+/**
+ * @page page_iface_zaura_shell zaura_shell
+ * @section page_iface_zaura_shell_desc Description
+ *
+ * The global interface exposing aura shell capabilities is used to
+ * instantiate an interface extension for a wl_surface object.
+ * This extended interface will then allow the client to use aura shell
+ * specific functionality.
+ * @section page_iface_zaura_shell_api API
+ * See @ref iface_zaura_shell.
+ */
+/**
+ * @defgroup iface_zaura_shell The zaura_shell interface
+ *
+ * The global interface exposing aura shell capabilities is used to
+ * instantiate an interface extension for a wl_surface object.
+ * This extended interface will then allow the client to use aura shell
+ * specific functionality.
+ */
+extern const struct wl_interface zaura_shell_interface;
+/**
+ * @page page_iface_zaura_surface zaura_surface
+ * @section page_iface_zaura_surface_desc Description
+ *
+ * An additional interface to a wl_surface object, which allows the
+ * client to access aura shell specific functionality for surface.
+ * @section page_iface_zaura_surface_api API
+ * See @ref iface_zaura_surface.
+ */
+/**
+ * @defgroup iface_zaura_surface The zaura_surface interface
+ *
+ * An additional interface to a wl_surface object, which allows the
+ * client to access aura shell specific functionality for surface.
+ */
+extern const struct wl_interface zaura_surface_interface;
+
+#ifndef ZAURA_SHELL_ERROR_ENUM
+#define ZAURA_SHELL_ERROR_ENUM
+enum zaura_shell_error {
+	/**
+	 * the surface already has an aura surface object associated
+	 */
+	ZAURA_SHELL_ERROR_AURA_SURFACE_EXISTS = 0,
+};
+#endif /* ZAURA_SHELL_ERROR_ENUM */
+
+#define ZAURA_SHELL_GET_AURA_SURFACE 0
+
+
+/**
+ * @ingroup iface_zaura_shell
+ */
+#define ZAURA_SHELL_GET_AURA_SURFACE_SINCE_VERSION 1
+
+/** @ingroup iface_zaura_shell */
+static inline void
+zaura_shell_set_user_data(struct zaura_shell *zaura_shell, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zaura_shell, user_data);
+}
+
+/** @ingroup iface_zaura_shell */
+static inline void *
+zaura_shell_get_user_data(struct zaura_shell *zaura_shell)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zaura_shell);
+}
+
+static inline uint32_t
+zaura_shell_get_version(struct zaura_shell *zaura_shell)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zaura_shell);
+}
+
+/** @ingroup iface_zaura_shell */
+static inline void
+zaura_shell_destroy(struct zaura_shell *zaura_shell)
+{
+	wl_proxy_destroy((struct wl_proxy *) zaura_shell);
+}
+
+/**
+ * @ingroup iface_zaura_shell
+ *
+ * Instantiate an interface extension for the given wl_surface to
+ * provide aura shell functionality. If the given wl_surface is not
+ * associated with a shell surface, the shell_surface_missing protocol
+ * error is raised.
+ */
+static inline struct zaura_surface *
+zaura_shell_get_aura_surface(struct zaura_shell *zaura_shell, struct wl_surface *surface)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) zaura_shell,
+			 ZAURA_SHELL_GET_AURA_SURFACE, &zaura_surface_interface, NULL, surface);
+
+	return (struct zaura_surface *) id;
+}
+
+#ifndef ZAURA_SURFACE_FRAME_TYPE_ENUM
+#define ZAURA_SURFACE_FRAME_TYPE_ENUM
+/**
+ * @ingroup iface_zaura_surface
+ * different frame types
+ *
+ * Frame types that can be used to decorate a surface.
+ */
+enum zaura_surface_frame_type {
+	/**
+	 * no frame
+	 */
+	ZAURA_SURFACE_FRAME_TYPE_NONE = 0,
+	/**
+	 * caption with shadow
+	 */
+	ZAURA_SURFACE_FRAME_TYPE_NORMAL = 1,
+	/**
+	 * shadow only
+	 */
+	ZAURA_SURFACE_FRAME_TYPE_SHADOW = 2,
+};
+#endif /* ZAURA_SURFACE_FRAME_TYPE_ENUM */
+
+#define ZAURA_SURFACE_SET_FRAME 0
+
+
+/**
+ * @ingroup iface_zaura_surface
+ */
+#define ZAURA_SURFACE_SET_FRAME_SINCE_VERSION 1
+
+/** @ingroup iface_zaura_surface */
+static inline void
+zaura_surface_set_user_data(struct zaura_surface *zaura_surface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zaura_surface, user_data);
+}
+
+/** @ingroup iface_zaura_surface */
+static inline void *
+zaura_surface_get_user_data(struct zaura_surface *zaura_surface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zaura_surface);
+}
+
+static inline uint32_t
+zaura_surface_get_version(struct zaura_surface *zaura_surface)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zaura_surface);
+}
+
+/** @ingroup iface_zaura_surface */
+static inline void
+zaura_surface_destroy(struct zaura_surface *zaura_surface)
+{
+	wl_proxy_destroy((struct wl_proxy *) zaura_surface);
+}
+
+/**
+ * @ingroup iface_zaura_surface
+ *
+ * Suggests a surface should use a specific frame.
+ */
+static inline void
+zaura_surface_set_frame(struct zaura_surface *zaura_surface, uint32_t type)
+{
+	wl_proxy_marshal((struct wl_proxy *) zaura_surface,
+			 ZAURA_SURFACE_SET_FRAME, type);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/components/exo/wayland/aura-shell-protocol.c b/components/exo/wayland/aura-shell-protocol.c
new file mode 100644
index 0000000..61bb7b5
--- /dev/null
+++ b/components/exo/wayland/aura-shell-protocol.c
@@ -0,0 +1,58 @@
+/* Generated by wayland-scanner 1.13.0 */
+
+/*
+ * Copyright 2017 The Chromium Authors.
+ *
+ * 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_surface_interface;
+extern const struct wl_interface zaura_surface_interface;
+
+static const struct wl_interface *types[] = {
+	NULL,
+	&zaura_surface_interface,
+	&wl_surface_interface,
+};
+
+static const struct wl_message zaura_shell_requests[] = {
+	{ "get_aura_surface", "no", types + 1 },
+};
+
+WL_EXPORT const struct wl_interface zaura_shell_interface = {
+	"zaura_shell", 1,
+	1, zaura_shell_requests,
+	0, NULL,
+};
+
+static const struct wl_message zaura_surface_requests[] = {
+	{ "set_frame", "u", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface zaura_surface_interface = {
+	"zaura_surface", 1,
+	1, zaura_surface_requests,
+	0, NULL,
+};
+
diff --git a/components/exo/wayland/aura-shell-server-protocol.h b/components/exo/wayland/aura-shell-server-protocol.h
new file mode 100644
index 0000000..37b9a9e
--- /dev/null
+++ b/components/exo/wayland/aura-shell-server-protocol.h
@@ -0,0 +1,175 @@
+/* Generated by wayland-scanner 1.13.0 */
+
+#ifndef AURA_SHELL_SERVER_PROTOCOL_H
+#define AURA_SHELL_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_aura_shell The aura_shell protocol
+ * @section page_ifaces_aura_shell Interfaces
+ * - @subpage page_iface_zaura_shell - aura_shell
+ * - @subpage page_iface_zaura_surface - aura shell interface to a wl_surface
+ * @section page_copyright_aura_shell Copyright
+ * <pre>
+ *
+ * Copyright 2017 The Chromium Authors.
+ *
+ * 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_surface;
+struct zaura_shell;
+struct zaura_surface;
+
+/**
+ * @page page_iface_zaura_shell zaura_shell
+ * @section page_iface_zaura_shell_desc Description
+ *
+ * The global interface exposing aura shell capabilities is used to
+ * instantiate an interface extension for a wl_surface object.
+ * This extended interface will then allow the client to use aura shell
+ * specific functionality.
+ * @section page_iface_zaura_shell_api API
+ * See @ref iface_zaura_shell.
+ */
+/**
+ * @defgroup iface_zaura_shell The zaura_shell interface
+ *
+ * The global interface exposing aura shell capabilities is used to
+ * instantiate an interface extension for a wl_surface object.
+ * This extended interface will then allow the client to use aura shell
+ * specific functionality.
+ */
+extern const struct wl_interface zaura_shell_interface;
+/**
+ * @page page_iface_zaura_surface zaura_surface
+ * @section page_iface_zaura_surface_desc Description
+ *
+ * An additional interface to a wl_surface object, which allows the
+ * client to access aura shell specific functionality for surface.
+ * @section page_iface_zaura_surface_api API
+ * See @ref iface_zaura_surface.
+ */
+/**
+ * @defgroup iface_zaura_surface The zaura_surface interface
+ *
+ * An additional interface to a wl_surface object, which allows the
+ * client to access aura shell specific functionality for surface.
+ */
+extern const struct wl_interface zaura_surface_interface;
+
+#ifndef ZAURA_SHELL_ERROR_ENUM
+#define ZAURA_SHELL_ERROR_ENUM
+enum zaura_shell_error {
+	/**
+	 * the surface already has an aura surface object associated
+	 */
+	ZAURA_SHELL_ERROR_AURA_SURFACE_EXISTS = 0,
+};
+#endif /* ZAURA_SHELL_ERROR_ENUM */
+
+/**
+ * @ingroup iface_zaura_shell
+ * @struct zaura_shell_interface
+ */
+struct zaura_shell_interface {
+	/**
+	 * extend surface interface for aura shell
+	 *
+	 * Instantiate an interface extension for the given wl_surface to
+	 * provide aura shell functionality. If the given wl_surface is not
+	 * associated with a shell surface, the shell_surface_missing
+	 * protocol error is raised.
+	 * @param id the new aura surface interface id
+	 * @param surface the surface
+	 */
+	void (*get_aura_surface)(struct wl_client *client,
+				 struct wl_resource *resource,
+				 uint32_t id,
+				 struct wl_resource *surface);
+};
+
+
+/**
+ * @ingroup iface_zaura_shell
+ */
+#define ZAURA_SHELL_GET_AURA_SURFACE_SINCE_VERSION 1
+
+#ifndef ZAURA_SURFACE_FRAME_TYPE_ENUM
+#define ZAURA_SURFACE_FRAME_TYPE_ENUM
+/**
+ * @ingroup iface_zaura_surface
+ * different frame types
+ *
+ * Frame types that can be used to decorate a surface.
+ */
+enum zaura_surface_frame_type {
+	/**
+	 * no frame
+	 */
+	ZAURA_SURFACE_FRAME_TYPE_NONE = 0,
+	/**
+	 * caption with shadow
+	 */
+	ZAURA_SURFACE_FRAME_TYPE_NORMAL = 1,
+	/**
+	 * shadow only
+	 */
+	ZAURA_SURFACE_FRAME_TYPE_SHADOW = 2,
+};
+#endif /* ZAURA_SURFACE_FRAME_TYPE_ENUM */
+
+/**
+ * @ingroup iface_zaura_surface
+ * @struct zaura_surface_interface
+ */
+struct zaura_surface_interface {
+	/**
+	 * request a frame for surface
+	 *
+	 * Suggests a surface should use a specific frame.
+	 * @param type the new frame type
+	 */
+	void (*set_frame)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  uint32_t type);
+};
+
+
+/**
+ * @ingroup iface_zaura_surface
+ */
+#define ZAURA_SURFACE_SET_FRAME_SINCE_VERSION 1
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index df7898b..8571aa4 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -4,6 +4,7 @@
 
 #include "components/exo/wayland/clients/client_base.h"
 
+#include <aura-shell-client-protocol.h>
 #include <fcntl.h>
 #include <linux-dmabuf-unstable-v1-client-protocol.h>
 #include <presentation-time-client-protocol.h>
@@ -102,6 +103,9 @@
   } else if (strcmp(interface, "wp_presentation") == 0) {
     globals->presentation.reset(static_cast<wp_presentation*>(
         wl_registry_bind(registry, id, &wp_presentation_interface, 1)));
+  } else if (strcmp(interface, "zaura_shell") == 0) {
+    globals->aura_shell.reset(static_cast<zaura_shell*>(
+        wl_registry_bind(registry, id, &zaura_shell_interface, 1)));
   } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
     globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>(
         wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 1)));
@@ -263,6 +267,10 @@
     LOG(ERROR) << "Can't find seat interface";
     return false;
   }
+  if (!globals_.aura_shell) {
+    LOG(ERROR) << "Can't find aura shell interface";
+    return false;
+  }
 
 #if defined(OZONE_PLATFORM_GBM)
   sk_sp<const GrGLInterface> native_interface;
@@ -378,6 +386,17 @@
 
   wl_shell_surface_set_title(shell_surface.get(), params.title.c_str());
 
+  std::unique_ptr<zaura_surface> aura_surface(
+      static_cast<zaura_surface*>(
+          zaura_shell_get_aura_surface(globals_.aura_shell.get(),
+                                       surface_.get())));
+  if (!aura_surface) {
+    LOG(ERROR) << "Can't get aura surface";
+    return false;
+  }
+
+  zaura_surface_set_frame(aura_surface.get(), ZAURA_SURFACE_FRAME_TYPE_NORMAL);
+
   if (fullscreen_) {
     wl_shell_surface_set_fullscreen(shell_surface.get(),
                                     WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
diff --git a/components/exo/wayland/clients/client_base.h b/components/exo/wayland/clients/client_base.h
index 1ae68e4..74135ce6 100644
--- a/components/exo/wayland/clients/client_base.h
+++ b/components/exo/wayland/clients/client_base.h
@@ -60,6 +60,7 @@
     std::unique_ptr<wl_shell> shell;
     std::unique_ptr<wl_seat> seat;
     std::unique_ptr<wl_subcompositor> subcompositor;
+    std::unique_ptr<zaura_shell> aura_shell;
   };
 
   struct Buffer {
diff --git a/components/exo/wayland/clients/client_helper.cc b/components/exo/wayland/clients/client_helper.cc
index b7c859d..33b3301 100644
--- a/components/exo/wayland/clients/client_helper.cc
+++ b/components/exo/wayland/clients/client_helper.cc
@@ -43,6 +43,8 @@
 DEFAULT_DELETER(wp_presentation, wp_presentation_destroy)
 DEFAULT_DELETER(struct wp_presentation_feedback,
                 wp_presentation_feedback_destroy)
+DEFAULT_DELETER(zaura_shell, zaura_shell_destroy)
+DEFAULT_DELETER(zaura_surface, zaura_surface_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 cbb7039..4ed8743a 100644
--- a/components/exo/wayland/clients/client_helper.h
+++ b/components/exo/wayland/clients/client_helper.h
@@ -13,6 +13,7 @@
 #include <memory>
 
 #include "base/scoped_generic.h"
+#include "components/exo/wayland/aura-shell-client-protocol.h"
 
 #if defined(OZONE_PLATFORM_GBM)
 #include <gbm.h>
@@ -44,6 +45,8 @@
 DEFAULT_DELETER_FDECL(wl_touch)
 DEFAULT_DELETER_FDECL(wp_presentation)
 DEFAULT_DELETER_FDECL(struct wp_presentation_feedback)
+DEFAULT_DELETER_FDECL(zaura_shell)
+DEFAULT_DELETER_FDECL(zaura_surface)
 DEFAULT_DELETER_FDECL(zwp_linux_buffer_params_v1)
 DEFAULT_DELETER_FDECL(zwp_linux_dmabuf_v1)
 
diff --git a/components/exo/wayland/protocol/aura-shell.xml b/components/exo/wayland/protocol/aura-shell.xml
new file mode 100644
index 0000000..01f8e33
--- /dev/null
+++ b/components/exo/wayland/protocol/aura-shell.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="aura_shell">
+
+  <copyright>
+    Copyright 2017 The Chromium Authors.
+
+    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.
+  </copyright>
+
+  <interface name="zaura_shell" version="1">
+    <description summary="aura_shell">
+      The global interface exposing aura shell capabilities is used to
+      instantiate an interface extension for a wl_surface object.
+      This extended interface will then allow the client to use aura shell
+      specific functionality.
+    </description>
+
+    <enum name="error">
+      <entry name="aura_surface_exists" value="0"
+	     summary="the surface already has an aura surface object associated"/>
+    </enum>
+
+    <request name="get_aura_surface">
+      <description summary="extend surface interface for aura shell">
+	Instantiate an interface extension for the given wl_surface to
+	provide aura shell functionality. If the given wl_surface is not
+	associated with a shell surface, the shell_surface_missing protocol
+	error is raised.
+      </description>
+
+      <arg name="id" type="new_id" interface="zaura_surface"
+	   summary="the new aura surface interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="zaura_surface" version="1">
+    <description summary="aura shell interface to a wl_surface">
+      An additional interface to a wl_surface object, which allows the
+      client to access aura shell specific functionality for surface.
+    </description>
+
+    <enum name="frame_type">
+      <description summary="different frame types">
+	Frame types that can be used to decorate a surface.
+      </description>
+      <entry name="none" value="0" summary="no frame"/>
+      <entry name="normal" value="1" summary="caption with shadow" />
+      <entry name="shadow" value="2" summary="shadow only"/>
+    </enum>
+
+    <request name="set_frame">
+      <description summary="request a frame for surface">
+	Suggests a surface should use a specific frame.
+      </description>
+      <arg name="type" type="uint" summary="the new frame type"/>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index fefe543..e1a4eba 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -5,6 +5,7 @@
 #include "components/exo/wayland/server.h"
 
 #include <alpha-compositing-unstable-v1-server-protocol.h>
+#include <aura-shell-server-protocol.h>
 #include <gaming-input-unstable-v1-server-protocol.h>
 #include <gaming-input-unstable-v2-server-protocol.h>
 #include <grp.h>
@@ -79,7 +80,6 @@
 #include "ui/base/class_property.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/ui_features.h"
-#include "ui/compositor/compositor_vsync_manager.h"
 #include "ui/display/display_observer.h"
 #include "ui/display/manager/managed_display_info.h"
 #include "ui/display/screen.h"
@@ -208,29 +208,33 @@
 }
 
 // A property key containing the surface resource that is associated with
-// window. If unset, no surface resource is associated with window.
+// window. If unset, no surface resource is associated with surface object.
 DEFINE_UI_CLASS_PROPERTY_KEY(wl_resource*, kSurfaceResourceKey, nullptr);
 
 // A property key containing a boolean set to true if a viewport is associated
-// with window.
+// with with surface object.
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasViewportKey, false);
 
 // A property key containing a boolean set to true if a security object is
-// associated with window.
+// associated with surface object.
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasSecurityKey, false);
 
 // A property key containing a boolean set to true if a blending object is
-// associated with window.
+// associated with surface object.
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasBlendingKey, false);
 
 // A property key containing a boolean set to true if the stylus_tool
-// object is associated with a window.
+// object is associated with surface object.
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasStylusToolKey, false);
 
 // A property key containing the data offer resource that is associated with
 // data offer object.
 DEFINE_UI_CLASS_PROPERTY_KEY(wl_resource*, kDataOfferResourceKey, nullptr);
 
+// A property key containing a boolean set to true if na aura surface object is
+// associated with surface object.
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasAuraSurfaceKey, false);
+
 wl_resource* GetSurfaceResource(Surface* surface) {
   return surface->GetProperty(kSurfaceResourceKey);
 }
@@ -1061,13 +1065,7 @@
 }
 
 void shell_surface_set_toplevel(wl_client* client, wl_resource* resource) {
-  ShellSurface* shell_surface = GetUserDataAs<ShellSurface>(resource);
-  if (shell_surface->enabled())
-    return;
-
-  shell_surface->SetFrame(true);
-  shell_surface->SetRectangularShadowEnabled(true);
-  shell_surface->SetEnabled(true);
+  GetUserDataAs<ShellSurface>(resource)->SetEnabled(true);
 }
 
 void shell_surface_set_transient(wl_client* client,
@@ -1115,10 +1113,8 @@
     shell_surface->SetContainer(ash::kShellWindowId_SystemModalContainer);
     shell_surface->SetActivatable(false);
   } else {
-    shell_surface->SetFrame(true);
     shell_surface->SetParent(parent_shell_surface);
   }
-  shell_surface->SetRectangularShadowEnabled(true);
   shell_surface->SetEnabled(true);
 }
 
@@ -2635,24 +2631,115 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// aura_surface_interface:
+
+class AuraSurface : public SurfaceObserver {
+ public:
+  explicit AuraSurface(Surface* surface) : surface_(surface) {
+    surface_->AddSurfaceObserver(this);
+    surface_->SetProperty(kSurfaceHasAuraSurfaceKey, true);
+  }
+  ~AuraSurface() override {
+    if (surface_) {
+      surface_->RemoveSurfaceObserver(this);
+      surface_->SetProperty(kSurfaceHasAuraSurfaceKey, false);
+    }
+  }
+
+  void SetFrame(SurfaceFrameType type) {
+    if (surface_)
+      surface_->SetFrame(type);
+  }
+
+  // Overridden from SurfaceObserver:
+  void OnSurfaceDestroying(Surface* surface) override {
+    surface->RemoveSurfaceObserver(this);
+    surface_ = nullptr;
+  }
+
+ private:
+  Surface* surface_;
+
+  DISALLOW_COPY_AND_ASSIGN(AuraSurface);
+};
+
+SurfaceFrameType ToSurfaceFrameType(uint32_t frame_type) {
+  switch (frame_type) {
+    case ZAURA_SURFACE_FRAME_TYPE_NONE:
+      return SurfaceFrameType::NONE;
+    case ZAURA_SURFACE_FRAME_TYPE_NORMAL:
+      return SurfaceFrameType::NORMAL;
+    case ZAURA_SURFACE_FRAME_TYPE_SHADOW:
+      return SurfaceFrameType::SHADOW;
+    default:
+      DLOG(WARNING) << "Unsupported frame type: " << frame_type;
+      return SurfaceFrameType::NONE;
+  }
+}
+
+void aura_surface_set_frame(wl_client* client, wl_resource* resource,
+                            uint32_t type) {
+  GetUserDataAs<AuraSurface>(resource)->SetFrame(ToSurfaceFrameType(type));
+}
+
+const struct zaura_surface_interface aura_surface_implementation = {
+    aura_surface_set_frame};
+
+////////////////////////////////////////////////////////////////////////////////
+// aura_shell_interface:
+
+void aura_shell_get_aura_surface(wl_client* client,
+                                 wl_resource* resource,
+                                 uint32_t id,
+                                 wl_resource* surface_resource) {
+  Surface* surface = GetUserDataAs<Surface>(surface_resource);
+  if (surface->GetProperty(kSurfaceHasAuraSurfaceKey)) {
+    wl_resource_post_error(
+        resource,
+        ZAURA_SHELL_ERROR_AURA_SURFACE_EXISTS,
+        "an aura surface object for that surface already exists");
+    return;
+  }
+
+  wl_resource* aura_surface_resource =
+      wl_resource_create(client, &zaura_surface_interface, 1, id);
+
+  SetImplementation(aura_surface_resource, &aura_surface_implementation,
+                    base::MakeUnique<AuraSurface>(surface));
+}
+
+const struct zaura_shell_interface aura_shell_implementation = {
+    aura_shell_get_aura_surface};
+
+void bind_aura_shell(wl_client* client,
+                     void* data,
+                     uint32_t version,
+                     uint32_t id) {
+  wl_resource* resource =
+      wl_resource_create(client, &zaura_shell_interface, 1, id);
+
+  wl_resource_set_implementation(resource, &aura_shell_implementation,
+                                 nullptr, nullptr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // vsync_timing_interface:
 
-// Implements VSync timing interface by monitoring a compositor for updates
-// to VSync parameters.
-class VSyncTiming final : public ui::CompositorVSyncManager::Observer {
+// Implements VSync timing interface by monitoring updates to VSync parameters.
+class VSyncTiming final : public WMHelper::VSyncObserver {
  public:
-  ~VSyncTiming() { vsync_manager_->RemoveObserver(this); }
+  ~VSyncTiming() override {
+    WMHelper::GetInstance()->RemoveVSyncObserver(this);
+  }
 
-  static std::unique_ptr<VSyncTiming> Create(ui::Compositor* compositor,
-                                             wl_resource* timing_resource) {
-    std::unique_ptr<VSyncTiming> vsync_timing(
-        new VSyncTiming(compositor, timing_resource));
+  static std::unique_ptr<VSyncTiming> Create(wl_resource* timing_resource) {
+    std::unique_ptr<VSyncTiming> vsync_timing(new VSyncTiming(timing_resource));
     // Note: AddObserver() will call OnUpdateVSyncParameters.
-    vsync_timing->vsync_manager_->AddObserver(vsync_timing.get());
+    WMHelper::GetInstance()->AddVSyncObserver(vsync_timing.get());
     return vsync_timing;
   }
 
-  // Overridden from ui::CompositorVSyncManager::Observer:
+  // Overridden from WMHelper::VSyncObserver:
   void OnUpdateVSyncParameters(base::TimeTicks timebase,
                                base::TimeDelta interval) override {
     uint64_t timebase_us = timebase.ToInternalValue();
@@ -2687,12 +2774,8 @@
   }
 
  private:
-  VSyncTiming(ui::Compositor* compositor, wl_resource* timing_resource)
-      : vsync_manager_(compositor->vsync_manager()),
-        timing_resource_(timing_resource) {}
-
-  // The VSync manager being observed.
-  scoped_refptr<ui::CompositorVSyncManager> vsync_manager_;
+  explicit VSyncTiming(wl_resource* timing_resource)
+      : timing_resource_(timing_resource) {}
 
   // The VSync timing resource.
   wl_resource* const timing_resource_;
@@ -2723,13 +2806,8 @@
                                      wl_resource* output) {
   wl_resource* timing_resource =
       wl_resource_create(client, &zcr_vsync_timing_v1_interface, 1, id);
-
-  // TODO(reveman): Multi-display support.
-  ui::Compositor* compositor =
-      ash::Shell::GetPrimaryRootWindow()->layer()->GetCompositor();
-
   SetImplementation(timing_resource, &vsync_timing_implementation,
-                    VSyncTiming::Create(compositor, timing_resource));
+                    VSyncTiming::Create(timing_resource));
 }
 
 const struct zcr_vsync_feedback_v1_interface vsync_feedback_implementation = {
@@ -4518,6 +4596,8 @@
                    display_, bind_alpha_compositing);
   wl_global_create(wl_display_.get(), &zcr_remote_shell_v1_interface,
                    remote_shell_version, display_, bind_remote_shell);
+  wl_global_create(wl_display_.get(), &zaura_shell_interface, 1, display_,
+                   bind_aura_shell);
   wl_global_create(wl_display_.get(), &zcr_gaming_input_v1_interface, 1,
                    display_, bind_gaming_input_v1_DEPRECATED);
   wl_global_create(wl_display_.get(), &zcr_gaming_input_v2_interface, 1,
diff --git a/components/exo/wm_helper.cc b/components/exo/wm_helper.cc
index ca2882f..a56e8607 100644
--- a/components/exo/wm_helper.cc
+++ b/components/exo/wm_helper.cc
@@ -104,6 +104,16 @@
   aura::client::SetDragDropDelegate(window, nullptr);
 }
 
+void WMHelper::AddVSyncObserver(VSyncObserver* observer) {
+  vsync_observers_.AddObserver(observer);
+  // Mimic CompositorVSyncManager::AddObserver's notification on addition.
+  observer->OnUpdateVSyncParameters(vsync_timebase_, vsync_interval_);
+}
+
+void WMHelper::RemoveVSyncObserver(VSyncObserver* observer) {
+  vsync_observers_.RemoveObserver(observer);
+}
+
 void WMHelper::NotifyWindowActivated(aura::Window* gained_active,
                                      aura::Window* lost_active) {
   for (ActivationObserver& observer : activation_observers_)
@@ -156,6 +166,14 @@
     observer.OnDisplayConfigurationChanged();
 }
 
+void WMHelper::NotifyUpdateVSyncParameters(base::TimeTicks timebase,
+                                           base::TimeDelta interval) {
+  vsync_timebase_ = timebase;
+  vsync_interval_ = interval;
+  for (VSyncObserver& observer : vsync_observers_)
+    observer.OnUpdateVSyncParameters(timebase, interval);
+}
+
 void WMHelper::OnDragEntered(const ui::DropTargetEvent& event) {
   for (DragDropObserver& observer : drag_drop_observers_)
     observer.OnDragEntered(event);
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index 69d72cf..ae16562 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -94,6 +94,15 @@
     virtual ~DragDropObserver() {}
   };
 
+  class VSyncObserver {
+   public:
+    virtual void OnUpdateVSyncParameters(base::TimeTicks timebase,
+                                         base::TimeDelta interval) = 0;
+
+   protected:
+    virtual ~VSyncObserver() {}
+  };
+
   ~WMHelper() override;
 
   static void SetInstance(WMHelper* helper);
@@ -117,6 +126,8 @@
   void RemoveDragDropObserver(DragDropObserver* observer);
   void SetDragDropDelegate(aura::Window*);
   void ResetDragDropDelegate(aura::Window*);
+  void AddVSyncObserver(VSyncObserver* observer);
+  void RemoveVSyncObserver(VSyncObserver* observer);
 
   virtual const display::ManagedDisplayInfo& GetDisplayInfo(
       int64_t display_id) const = 0;
@@ -154,6 +165,8 @@
   void NotifyTabletModeEnded();
   void NotifyKeyboardDeviceConfigurationChanged();
   void NotifyDisplayConfigurationChanged();
+  void NotifyUpdateVSyncParameters(base::TimeTicks timebase,
+                                   base::TimeDelta interval);
 
  private:
   base::ObserverList<ActivationObserver> activation_observers_;
@@ -163,6 +176,11 @@
   base::ObserverList<InputDeviceEventObserver> input_device_event_observers_;
   base::ObserverList<DisplayConfigurationObserver> display_config_observers_;
   base::ObserverList<DragDropObserver> drag_drop_observers_;
+  base::ObserverList<VSyncObserver> vsync_observers_;
+
+  // The most recently cached VSync parameters, sent to observers on addition.
+  base::TimeTicks vsync_timebase_;
+  base::TimeDelta vsync_interval_;
 
   DISALLOW_COPY_AND_ASSIGN(WMHelper);
 };
diff --git a/components/exo/wm_helper_ash.cc b/components/exo/wm_helper_ash.cc
index 3a6cd897..9d4d18a7 100644
--- a/components/exo/wm_helper_ash.cc
+++ b/components/exo/wm_helper_ash.cc
@@ -26,15 +26,18 @@
   if (ash::Shell::GetAshConfig() != ash::Config::MUS)
     ash::Shell::Get()->cursor_manager()->AddObserver(this);
   ash::Shell::Get()->window_tree_host_manager()->AddObserver(this);
-  aura::client::FocusClient* focus_client =
-      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
-  focus_client->AddObserver(this);
+  aura::Window* primary_root = ash::Shell::GetPrimaryRootWindow();
+  aura::client::GetFocusClient(primary_root)->AddObserver(this);
   ui::InputDeviceManager::GetInstance()->AddObserver(this);
+  // TODO(reveman): Multi-display support.
+  vsync_manager_ = primary_root->layer()->GetCompositor()->vsync_manager();
+  vsync_manager_->AddObserver(this);
 }
 
 WMHelperAsh::~WMHelperAsh() {
   if (!ash::Shell::HasInstance())
     return;
+  vsync_manager_->RemoveObserver(this);
   aura::client::FocusClient* focus_client =
       aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   focus_client->RemoveObserver(this);
@@ -176,4 +179,9 @@
   NotifyKeyboardDeviceConfigurationChanged();
 }
 
+void WMHelperAsh::OnUpdateVSyncParameters(base::TimeTicks timebase,
+                                          base::TimeDelta interval) {
+  NotifyUpdateVSyncParameters(timebase, interval);
+}
+
 }  // namespace exo
diff --git a/components/exo/wm_helper_ash.h b/components/exo/wm_helper_ash.h
index 4a951b7..78273320 100644
--- a/components/exo/wm_helper_ash.h
+++ b/components/exo/wm_helper_ash.h
@@ -11,6 +11,7 @@
 #include "components/exo/wm_helper.h"
 #include "ui/aura/client/cursor_client_observer.h"
 #include "ui/aura/client/focus_change_observer.h"
+#include "ui/compositor/compositor_vsync_manager.h"
 #include "ui/events/devices/input_device_event_observer.h"
 #include "ui/wm/public/activation_change_observer.h"
 
@@ -23,7 +24,8 @@
                     public aura::client::CursorClientObserver,
                     public ash::TabletModeObserver,
                     public ash::WindowTreeHostManager::Observer,
-                    public ui::InputDeviceEventObserver {
+                    public ui::InputDeviceEventObserver,
+                    public ui::CompositorVSyncManager::Observer {
  public:
   WMHelperAsh();
   ~WMHelperAsh() override;
@@ -69,7 +71,14 @@
   // Overridden from ui::InputDeviceEventObserver:
   void OnKeyboardDeviceConfigurationChanged() override;
 
+  // ui::CompositorVSyncManager::Observer:
+  void OnUpdateVSyncParameters(base::TimeTicks timebase,
+                               base::TimeDelta interval) override;
+
  private:
+  // The VSync manager being observed.
+  scoped_refptr<ui::CompositorVSyncManager> vsync_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(WMHelperAsh);
 };
 
diff --git a/components/feature_engagement/public/event_constants.cc b/components/feature_engagement/public/event_constants.cc
index b2fb65c..d1d9d36 100644
--- a/components/feature_engagement/public/event_constants.cc
+++ b/components/feature_engagement/public/event_constants.cc
@@ -8,7 +8,10 @@
 
 namespace events {
 
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+const char kBookmarkAdded[] = "bookmark_added";
+const char kBookmarkSessionTimeMet[] = "bookmark_session_time_met";
+
 const char kOmniboxInteraction[] = "omnibox_used";
 const char kNewTabSessionTimeMet[] = "new_tab_session_time_met";
 
diff --git a/components/feature_engagement/public/event_constants.h b/components/feature_engagement/public/event_constants.h
index e6d514b2..ed140602 100644
--- a/components/feature_engagement/public/event_constants.h
+++ b/components/feature_engagement/public/event_constants.h
@@ -11,9 +11,18 @@
 
 namespace events {
 
-#if defined(OS_WIN) || defined(OS_LINUX)
-// All the events declared below are the string names
-// of deferred onboarding events for the New Tab.
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+// All the events declared below are the string names of deferred onboarding
+// events for the Bookmark feature.
+
+// The user has added a Bookmark (one-off event).
+extern const char kBookmarkAdded[];
+// The user has satisfied the session time requirement to show the BookmarkPromo
+// by accumulating 5 hours of active session time (one-off event).
+extern const char kBookmarkSessionTimeMet[];
+
+// All the events declared below are the string names of deferred onboarding
+// events for the New Tab.
 
 // The user has interacted with the omnibox.
 extern const char kOmniboxInteraction[];
@@ -21,8 +30,8 @@
 // by accumulating 2 hours of active session time (one-off event).
 extern const char kNewTabSessionTimeMet[];
 
-// All the events declared below are the string names
-// of deferred onboarding events for the Incognito Window
+// All the events declared below are the string names of deferred onboarding
+// events for the Incognito Window.
 
 // The user has deleted browsing history.
 extern const char kHistoryDeleted[];
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index eb66d1f..11ac76a9 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -29,7 +29,9 @@
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+const base::Feature kIPHBookmarkFeature{"IPH_Bookmark",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHIncognitoWindowFeature{
     "IPH_IncognitoWindow", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kIPHNewTabFeature{"IPH_NewTab",
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index 52052f50..7b8148d 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -29,7 +29,8 @@
 extern const base::Feature kIPHMediaDownloadFeature;
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+extern const base::Feature kIPHBookmarkFeature;
 extern const base::Feature kIPHIncognitoWindowFeature;
 extern const base::Feature kIPHNewTabFeature;
 #endif  // defined(OS_WIN) || defined(OS_LINUX)
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index d2971fe..9eb3455b 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -23,7 +23,8 @@
     &kIPHChromeHomeExpandFeature,
     &kIPHMediaDownloadFeature,
 #endif  // defined(OS_ANDROID)
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+    &kIPHBookmarkFeature,
     &kIPHIncognitoWindowFeature,
     &kIPHNewTabFeature,
 #endif  // defined(OS_WIN) || defined(OS_LINUX)
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index b260327f..7bdd1ab02 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -54,7 +54,8 @@
 DEFINE_VARIATION_PARAM(kIPHChromeHomeExpandFeature, "IPH_ChromeHomeExpand");
 DEFINE_VARIATION_PARAM(kIPHMediaDownloadFeature, "IPH_MediaDownload");
 #endif  // defined(OS_ANDROID)
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+DEFINE_VARIATION_PARAM(kIPHBookmarkFeature, "IPH_Bookmark");
 DEFINE_VARIATION_PARAM(kIPHIncognitoWindowFeature, "IPH_IncognitoWindow");
 DEFINE_VARIATION_PARAM(kIPHNewTabFeature, "IPH_NewTab");
 #endif  // defined(OS_WIN) || defined(OS_LINUX)
@@ -79,7 +80,8 @@
         VARIATION_ENTRY(kIPHDownloadPageScreenshotFeature),
         VARIATION_ENTRY(kIPHChromeHomeExpandFeature),
         VARIATION_ENTRY(kIPHMediaDownloadFeature),
-#elif defined(OS_WIN) || defined(OS_LINUX)
+#elif defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+        VARIATION_ENTRY(kIPHBookmarkFeature),
         VARIATION_ENTRY(kIPHIncognitoWindowFeature),
         VARIATION_ENTRY(kIPHNewTabFeature),
 #elif defined(OS_IOS)
diff --git a/components/history/core/browser/browsing_history_driver.h b/components/history/core/browser/browsing_history_driver.h
index 5bde74f..ea5db19 100644
--- a/components/history/core/browser/browsing_history_driver.h
+++ b/components/history/core/browser/browsing_history_driver.h
@@ -29,7 +29,8 @@
   // Callback for QueryHistory().
   virtual void OnQueryComplete(
       const std::vector<BrowsingHistoryService::HistoryEntry>& results,
-      const BrowsingHistoryService::QueryResultsInfo& query_results_info) = 0;
+      const BrowsingHistoryService::QueryResultsInfo& query_results_info,
+      base::OnceClosure continuation_closure) = 0;
 
   // Callback for RemoveVisits().
   virtual void OnRemoveVisitsComplete() = 0;
diff --git a/components/history/core/browser/browsing_history_service.cc b/components/history/core/browser/browsing_history_service.cc
index 96b43ef..8041ce6a 100644
--- a/components/history/core/browser/browsing_history_service.cc
+++ b/components/history/core/browser/browsing_history_service.cc
@@ -8,7 +8,6 @@
 
 #include <algorithm>
 #include <map>
-#include <set>
 #include <utility>
 
 #include "base/bind_helpers.h"
@@ -41,19 +40,63 @@
   NUM_WEB_HISTORY_QUERY_BUCKETS
 };
 
-// Returns true if |entry| represents a local visit that had no corresponding
-// visit on the server.
-bool IsLocalOnlyResult(const BrowsingHistoryService::HistoryEntry& entry) {
-  return entry.entry_type == BrowsingHistoryService::HistoryEntry::LOCAL_ENTRY;
-}
-
 void RecordMetricsForNoticeAboutOtherFormsOfBrowsingHistory(bool shown) {
   UMA_HISTOGRAM_BOOLEAN("History.ShownHeaderAboutOtherFormsOfBrowsingHistory",
                         shown);
 }
 
+QueryOptions OptionsWithEndTime(QueryOptions original_options,
+                                base::Time end_time) {
+  QueryOptions options(original_options);
+  options.end_time = end_time;
+  return options;
+}
+
+// The status of the result from a particular history source.
+enum QuerySourceStatus {
+  // Not a continuation and no response yet.
+  UNINITIALIZED,
+  // Could not query the particular source.
+  NO_DEPENDENCY,
+  // Only used for web, when we stop waiting for a response due to timeout.
+  TIMED_OUT,
+  // Only used for remote, response was error or empty.
+  FAILURE,
+  // Successfully retrieved results, but there are more left.
+  MORE_RESULTS,
+  // Successfully retrieved results and we reached the end of results.
+  REACHED_BEGINNING,
+};
+
+bool CanRetry(QuerySourceStatus status) {
+  // TODO(skym): Should we be retrying on FAILURE?
+  return status == MORE_RESULTS || status == FAILURE || status == TIMED_OUT;
+}
+
 }  // namespace
 
+struct BrowsingHistoryService::QueryHistoryState
+    : public base::RefCounted<BrowsingHistoryService::QueryHistoryState> {
+  QueryHistoryState() = default;
+
+  base::string16 search_text;
+  QueryOptions original_options;
+
+  QuerySourceStatus local_status = UNINITIALIZED;
+  // Should always be sorted in reverse chronological order.
+  std::vector<HistoryEntry> local_results;
+  base::Time local_end_time_for_continuation;
+
+  QuerySourceStatus remote_status = UNINITIALIZED;
+  // Should always be sorted in reverse chronological order.
+  std::vector<HistoryEntry> remote_results;
+  base::Time remote_end_time_for_continuation;
+
+ private:
+  friend class base::RefCounted<BrowsingHistoryService::QueryHistoryState>;
+  ~QueryHistoryState() = default;
+};
+
 BrowsingHistoryService::HistoryEntry::HistoryEntry(
     BrowsingHistoryService::HistoryEntry::EntryType entry_type,
     const GURL& url,
@@ -94,12 +137,20 @@
     BrowsingHistoryDriver* driver,
     HistoryService* local_history,
     syncer::SyncService* sync_service)
-    : has_pending_delete_request_(false),
+    : BrowsingHistoryService(driver,
+                             local_history,
+                             sync_service,
+                             std::make_unique<base::OneShotTimer>()) {}
+
+BrowsingHistoryService::BrowsingHistoryService(
+    BrowsingHistoryDriver* driver,
+    HistoryService* local_history,
+    syncer::SyncService* sync_service,
+    std::unique_ptr<base::Timer> web_history_timer)
+    : web_history_timer_(std::move(web_history_timer)),
       history_service_observer_(this),
       web_history_service_observer_(this),
       sync_service_observer_(this),
-      has_synced_results_(false),
-      has_other_forms_of_browsing_history_(false),
       driver_(driver),
       local_history_(local_history),
       sync_service_(sync_service),
@@ -143,13 +194,14 @@
   }
 }
 
-void BrowsingHistoryService::WebHistoryTimeout() {
-  has_synced_results_ = false;
-  query_results_info_.sync_timed_out = true;
+void BrowsingHistoryService::WebHistoryTimeout(
+    scoped_refptr<QueryHistoryState> state) {
+  state->remote_status = TIMED_OUT;
 
+  // Don't reset |web_history_request_| so we can still record histogram.
   // TODO(dubroy): Communicate the failure to the front end.
   if (!query_task_tracker_.HasTrackedTasks())
-    ReturnResultsToDriver();
+    ReturnResultsToDriver(std::move(state));
 
   UMA_HISTOGRAM_ENUMERATION("WebHistory.QueryCompletion",
                             WEB_HISTORY_QUERY_TIMED_OUT,
@@ -158,83 +210,109 @@
 
 void BrowsingHistoryService::QueryHistory(const base::string16& search_text,
                                           const QueryOptions& options) {
+  scoped_refptr<QueryHistoryState> state =
+      base::MakeRefCounted<QueryHistoryState>();
+  state->search_text = search_text;
+  state->original_options = options;
+  state->local_end_time_for_continuation = options.end_time;
+  state->remote_end_time_for_continuation = options.end_time;
+  QueryHistoryInternal(std::move(state));
+}
+
+void BrowsingHistoryService::QueryHistoryInternal(
+    scoped_refptr<QueryHistoryState> state) {
   // Anything in-flight is invalid.
   query_task_tracker_.TryCancelAll();
   web_history_request_.reset();
-  query_results_.clear();
 
-  // TODO(skym): Should |query_results_info_| be reset to default values
-  // instead?
-  // Set this to false until the results actually arrive.
-  query_results_info_.has_synced_results = false;
+  bool should_return_results_immediately = true;
+  size_t desired_count =
+      static_cast<size_t>(state->original_options.EffectiveMaxCount());
 
   if (local_history_) {
-    local_history_->QueryHistory(
-        search_text, options,
-        base::Bind(&BrowsingHistoryService::QueryComplete,
-                   weak_factory_.GetWeakPtr(), search_text, options),
-        &query_task_tracker_);
+    if (state->local_results.size() < desired_count &&
+        state->local_status != REACHED_BEGINNING) {
+      should_return_results_immediately = false;
+      local_history_->QueryHistory(
+          state->search_text,
+          OptionsWithEndTime(state->original_options,
+                             state->local_end_time_for_continuation),
+          base::Bind(&BrowsingHistoryService::QueryComplete,
+                     weak_factory_.GetWeakPtr(), state),
+          &query_task_tracker_);
+    }
+  } else {
+    state->local_status = NO_DEPENDENCY;
   }
 
-  // Set this to false until the results actually arrive.
-  query_results_info_.has_synced_results = false;
-
   WebHistoryService* web_history = driver_->GetWebHistoryService();
   if (web_history) {
-    web_history_query_results_.clear();
+    if (state->remote_results.size() < desired_count &&
+        state->remote_status != REACHED_BEGINNING) {
+      // Start a timer with timeout before we make the actual query, otherwise
+      // tests get confused when completion callback is run synchronously.
+      web_history_timer_->Start(
+          FROM_HERE, base::TimeDelta::FromSeconds(kWebHistoryTimeoutSeconds),
+          base::Bind(&BrowsingHistoryService::WebHistoryTimeout,
+                     weak_factory_.GetWeakPtr(), state));
 
-    // Start a timer with timeout before we make the actual query, otherwise
-    // tests get confused when completion callback is run synchronously.
-    web_history_timer_.Start(
-        FROM_HERE, base::TimeDelta::FromSeconds(kWebHistoryTimeoutSeconds),
-        this, &BrowsingHistoryService::WebHistoryTimeout);
-
-    net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
-        net::DefinePartialNetworkTrafficAnnotation("web_history_query",
-                                                   "web_history_service",
-                                                   R"(
-          semantics {
-            description:
-              "If history sync is enabled, this downloads the synced history "
-              "from history.google.com."
-            trigger:
-              "Synced history is downloaded when user opens the history page, "
-              "searches on the history page, or scrolls down the history page "
-              "to see more results. This is only the case if the user is "
-              "signed in and history sync is enabled."
-            data:
-              "The history query text (or empty strings if all results are to "
-              "be fetched), the begin and end timestamps, and the maximum "
-              "number of results to be fetched. The request also includes a "
-              "version info token to resolve transaction conflicts, and an "
-              "OAuth2 token authenticating the user."
-          }
-          policy {
-            chrome_policy {
-              SyncDisabled {
-                SyncDisabled: true
-              }
+      net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
+          net::DefinePartialNetworkTrafficAnnotation("web_history_query",
+                                                     "web_history_service",
+                                                     R"(
+            semantics {
+              description:
+                "If history sync is enabled, this downloads the synced "
+                "history from history.google.com."
+              trigger:
+                "Synced history is downloaded when user opens the history "
+                "page, searches on the history page, or scrolls down the "
+                "history page to see more results. This is only the case if "
+                "the user is signed in and history sync is enabled."
+              data:
+                "The history query text (or empty strings if all results are "
+                "to be fetched), the begin and end timestamps, and the maximum "
+                "number of results to be fetched. The request also includes a "
+                "version info token to resolve transaction conflicts, and an "
+                "OAuth2 token authenticating the user."
             }
-          })");
-    web_history_request_ = web_history->QueryHistory(
-        search_text, options,
-        base::Bind(&BrowsingHistoryService::WebHistoryQueryComplete,
-                   weak_factory_.GetWeakPtr(), search_text, options,
-                   clock_->Now()),
-        partial_traffic_annotation);
+            policy {
+              chrome_policy {
+                SyncDisabled {
+                  SyncDisabled: true
+                }
+              }
+            })");
+      should_return_results_immediately = false;
+      web_history_request_ = web_history->QueryHistory(
+          state->search_text,
+          OptionsWithEndTime(state->original_options,
+                             state->remote_end_time_for_continuation),
+          base::Bind(&BrowsingHistoryService::WebHistoryQueryComplete,
+                     weak_factory_.GetWeakPtr(), state, clock_->Now()),
+          partial_traffic_annotation);
 
-    // Test the existence of other forms of browsing history.
-    driver_->ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
-        sync_service_, web_history,
-        base::Bind(
-            &BrowsingHistoryService::OtherFormsOfBrowsingHistoryQueryComplete,
-            weak_factory_.GetWeakPtr()));
+      // Test the existence of other forms of browsing history.
+      driver_->ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
+          sync_service_, web_history,
+          base::Bind(
+              &BrowsingHistoryService::OtherFormsOfBrowsingHistoryQueryComplete,
+              weak_factory_.GetWeakPtr()));
+    }
   } else {
+    state->remote_status = NO_DEPENDENCY;
     // The notice could not have been shown, because there is no web history.
     RecordMetricsForNoticeAboutOtherFormsOfBrowsingHistory(false);
     has_synced_results_ = false;
     has_other_forms_of_browsing_history_ = false;
   }
+
+  // If we avoid assuming delegated queries are returning asynchronous, then we
+  // cannot check tracker/timer, and instead have to rely on local logic for
+  // this choice. Note that in unit tests Web History returns synchronously.
+  if (should_return_results_immediately) {
+    ReturnResultsToDriver(std::move(state));
+  }
 }
 
 void BrowsingHistoryService::RemoveVisits(
@@ -337,193 +415,278 @@
 
 // static
 void BrowsingHistoryService::MergeDuplicateResults(
-    std::vector<BrowsingHistoryService::HistoryEntry>* results) {
-  std::vector<BrowsingHistoryService::HistoryEntry> new_results;
+    QueryHistoryState* state,
+    std::vector<HistoryEntry>* results) {
+  DCHECK(state);
+  DCHECK(results);
+  DCHECK(results->empty());
+
+  // Will be used later to decide if we need to hold back results. This requires
+  // results to be sorted.
+  base::Time youngest_local = state->local_results.empty()
+                                  ? base::Time()
+                                  : state->local_results.rbegin()->time;
+  base::Time youngest_remote = state->remote_results.empty()
+                                   ? base::Time()
+                                   : state->remote_results.rbegin()->time;
+
+  std::vector<HistoryEntry> sorted;
+  sorted.assign(std::make_move_iterator(state->local_results.begin()),
+                std::make_move_iterator(state->local_results.end()));
+  state->local_results.clear();
+  sorted.insert(sorted.end(),
+                std::make_move_iterator(state->remote_results.begin()),
+                std::make_move_iterator(state->remote_results.end()));
+  state->remote_results.clear();
+  std::sort(sorted.begin(), sorted.end(), HistoryEntry::SortByTimeDescending);
+
   // Pre-reserve the size of the new vector. Since we're working with pointers
   // later on not doing this could lead to the vector being resized and to
   // pointers to invalid locations.
-  new_results.reserve(results->size());
+  std::vector<HistoryEntry> deduped;
+  deduped.reserve(sorted.size());
+
   // Maps a URL to the most recent entry on a particular day.
-  std::map<GURL, BrowsingHistoryService::HistoryEntry*> current_day_entries;
+  std::map<GURL, HistoryEntry*> current_day_entries;
 
   // Keeps track of the day that |current_day_urls| is holding the URLs for,
   // in order to handle removing per-day duplicates.
   base::Time current_day_midnight;
 
-  std::sort(results->begin(), results->end(),
-            HistoryEntry::SortByTimeDescending);
-
-  for (std::vector<BrowsingHistoryService::HistoryEntry>::const_iterator it =
-           results->begin();
-       it != results->end(); ++it) {
+  for (HistoryEntry& entry : sorted) {
     // Reset the list of found URLs when a visit from a new day is encountered.
-    if (current_day_midnight != it->time.LocalMidnight()) {
+    if (current_day_midnight != entry.time.LocalMidnight()) {
       current_day_entries.clear();
-      current_day_midnight = it->time.LocalMidnight();
+      current_day_midnight = entry.time.LocalMidnight();
     }
 
     // Keep this visit if it's the first visit to this URL on the current day.
-    if (current_day_entries.count(it->url) == 0) {
-      new_results.push_back(*it);
-      current_day_entries[it->url] = &new_results.back();
+    if (current_day_entries.count(entry.url) == 0) {
+      deduped.push_back(std::move(entry));
+      current_day_entries[entry.url] = &deduped.back();
     } else {
       // Keep track of the timestamps of all visits to the URL on the same day.
-      BrowsingHistoryService::HistoryEntry* entry =
-          current_day_entries[it->url];
-      entry->all_timestamps.insert(it->all_timestamps.begin(),
-                                   it->all_timestamps.end());
+      HistoryEntry* matching_entry = current_day_entries[entry.url];
+      matching_entry->all_timestamps.insert(entry.all_timestamps.begin(),
+                                            entry.all_timestamps.end());
 
-      if (entry->entry_type != it->entry_type) {
-        entry->entry_type =
-            BrowsingHistoryService::HistoryEntry::COMBINED_ENTRY;
+      if (matching_entry->entry_type != entry.entry_type) {
+        matching_entry->entry_type = HistoryEntry::COMBINED_ENTRY;
       }
     }
   }
-  results->swap(new_results);
+
+  // If the beginning of either source was not reached, that means there are
+  // more results from that source, and then other source needs to have its data
+  // held back until the former source catches up. This only send the UI history
+  // entries in the correct order. Subsequent continuation requests will get the
+  // delayed entries.
+  base::Time youngest_allowed = base::Time();
+  if (state->local_status == MORE_RESULTS) {
+    youngest_allowed = std::max(youngest_allowed, youngest_local);
+    state->local_end_time_for_continuation = youngest_local;
+  }
+  if (state->remote_status == MORE_RESULTS) {
+    youngest_allowed = std::max(youngest_allowed, youngest_remote);
+    state->remote_end_time_for_continuation = youngest_remote;
+  } else if (CanRetry(state->remote_status)) {
+    // TODO(skym): It is unclear if this is the best behavior. The UI is going
+    // to behave incorrectly if out of order results are received. So to
+    // guarantee that doesn't happen, use |youngest_local| for continuation
+    // calls. This will result in missing history entries for the failed calls.
+    // crbug.com/685866 is related to this problem.
+    state->remote_end_time_for_continuation = youngest_local;
+  }
+
+  HistoryEntry search_entry;
+  search_entry.time = youngest_allowed;
+  auto threshold_iter =
+      std::upper_bound(deduped.begin(), deduped.end(), search_entry,
+                       HistoryEntry::SortByTimeDescending);
+
+  // Everything from threshold_iter to deduped.end() should either be all local
+  // or all remote, never a mix.
+  if (threshold_iter != deduped.end()) {
+    if (threshold_iter->entry_type == HistoryEntry::LOCAL_ENTRY) {
+      state->local_results.assign(std::make_move_iterator(threshold_iter),
+                                  std::make_move_iterator(deduped.end()));
+    } else if (threshold_iter->entry_type == HistoryEntry::REMOTE_ENTRY) {
+      state->remote_results.assign(std::make_move_iterator(threshold_iter),
+                                   std::make_move_iterator(deduped.end()));
+    } else {
+      NOTREACHED();
+    }
+    deduped.erase(threshold_iter, deduped.end());
+  }
+  *results = std::move(deduped);
 }
 
-void BrowsingHistoryService::QueryComplete(const base::string16& search_text,
-                                           const QueryOptions& options,
-                                           QueryResults* results) {
-  DCHECK_EQ(0U, query_results_.size());
-  query_results_.reserve(results->size());
+void BrowsingHistoryService::QueryComplete(
+    scoped_refptr<QueryHistoryState> state,
+    QueryResults* results) {
+  std::vector<HistoryEntry>& output = state->local_results;
+  output.reserve(output.size() + results->size());
 
   for (size_t i = 0; i < results->size(); ++i) {
     URLResult const& page = (*results)[i];
     // TODO(dubroy): Use sane time (crbug.com/146090) here when it's ready.
-    query_results_.push_back(
-        HistoryEntry(HistoryEntry::LOCAL_ENTRY, page.url(), page.title(),
-                     page.visit_time(), std::string(), !search_text.empty(),
-                     page.snippet().text(), page.blocked_visit()));
+    output.push_back(HistoryEntry(HistoryEntry::LOCAL_ENTRY, page.url(),
+                                  page.title(), page.visit_time(),
+                                  std::string(), !state->search_text.empty(),
+                                  page.snippet().text(), page.blocked_visit()));
   }
 
-  query_results_info_.search_text = search_text;
-  query_results_info_.reached_beginning_of_local = results->reached_beginning();
+  state->local_status =
+      results->reached_beginning() ? REACHED_BEGINNING : MORE_RESULTS;
 
-  if (!web_history_timer_.IsRunning())
-    ReturnResultsToDriver();
+  if (!web_history_timer_->IsRunning())
+    ReturnResultsToDriver(std::move(state));
 }
 
-void BrowsingHistoryService::ReturnResultsToDriver() {
-  // Combine the local and remote results into |query_results_|, and remove
-  // any duplicates.
-  if (!web_history_query_results_.empty()) {
-    int local_result_count = query_results_.size();
-    query_results_.insert(query_results_.end(),
-                          web_history_query_results_.begin(),
-                          web_history_query_results_.end());
-    MergeDuplicateResults(&query_results_);
+void BrowsingHistoryService::ReturnResultsToDriver(
+    scoped_refptr<QueryHistoryState> state) {
+  std::vector<HistoryEntry> results;
+
+  // Always merge remote results, because Web History does not deduplicate .
+  // Local history should be using per-query deduplication, but if we are in a
+  // continuation, it's possible that we have carried over pending entries along
+  // with new results, and these two sets may contain duplicates. Assuming every
+  // call to Web History is successful, we shouldn't be able to have empty sync
+  // results at the same time as we have pending local.
+  if (state->remote_results.size()) {
+    int local_result_count = state->local_results.size();
+    MergeDuplicateResults(state.get(), &results);
 
     if (local_result_count) {
       // In the best case, we expect that all local results are duplicated on
       // the server. Keep track of how many are missing.
-      int missing_count = std::count_if(
-          query_results_.begin(), query_results_.end(), IsLocalOnlyResult);
+      int missing_count = 0;
+      for (const HistoryEntry& entry : results) {
+        missing_count +=
+            entry.entry_type ==
+                    BrowsingHistoryService::HistoryEntry::LOCAL_ENTRY
+                ? entry.all_timestamps.size()
+                : 0;
+      }
+      DCHECK_GE(local_result_count, missing_count);
       UMA_HISTOGRAM_PERCENTAGE("WebHistory.LocalResultMissingOnServer",
                                missing_count * 100.0 / local_result_count);
     }
+  } else {
+    // TODO(skym): Is the optimization to skip merge on local only results worth
+    // the complexity increase here?
+    if (state->local_status == MORE_RESULTS && !state->local_results.empty()) {
+      state->local_end_time_for_continuation =
+          state->local_results.rbegin()->time;
+    }
+    results = std::move(state->local_results);
   }
 
-  driver_->OnQueryComplete(query_results_, query_results_info_);
+  QueryResultsInfo info;
+  info.search_text = state->search_text;
+  info.reached_beginning =
+      !CanRetry(state->local_status) && !CanRetry(state->remote_status);
+  info.sync_timed_out = state->remote_status == TIMED_OUT;
+  info.has_synced_results = state->remote_status == MORE_RESULTS ||
+                            state->remote_status == REACHED_BEGINNING;
+  base::OnceClosure continuation =
+      base::Bind(&BrowsingHistoryService::QueryHistoryInternal,
+                 weak_factory_.GetWeakPtr(), std::move(state));
+  driver_->OnQueryComplete(results, info, std::move(continuation));
   driver_->HasOtherFormsOfBrowsingHistory(has_other_forms_of_browsing_history_,
                                           has_synced_results_);
-
-  query_results_.clear();
-  web_history_query_results_.clear();
 }
 
 void BrowsingHistoryService::WebHistoryQueryComplete(
-    const base::string16& search_text,
-    const history::QueryOptions& options,
+    scoped_refptr<QueryHistoryState> state,
     base::Time start_time,
     WebHistoryService::Request* request,
     const base::DictionaryValue* results_value) {
   base::TimeDelta delta = clock_->Now() - start_time;
   UMA_HISTOGRAM_TIMES("WebHistory.ResponseTime", delta);
 
-  // TODO(skym): Compare |request| to |web_history_request_| instead of checking
-  // the timer, which is susceptible to races.
   // If the response came in too late, do nothing.
   // TODO(dubroy): Maybe show a banner, and prompt the user to reload?
-  if (!web_history_timer_.IsRunning())
+  if (!web_history_timer_->IsRunning())
     return;
-  web_history_timer_.Stop();
+  web_history_timer_->Stop();
+  web_history_request_.reset();
 
   UMA_HISTOGRAM_ENUMERATION(
       "WebHistory.QueryCompletion",
       results_value ? WEB_HISTORY_QUERY_SUCCEEDED : WEB_HISTORY_QUERY_FAILED,
       NUM_WEB_HISTORY_QUERY_BUCKETS);
 
-  DCHECK_EQ(0U, web_history_query_results_.size());
-  const base::ListValue* events = nullptr;
-  if (results_value && results_value->GetList("event", &events)) {
-    web_history_query_results_.reserve(events->GetSize());
-    for (unsigned int i = 0; i < events->GetSize(); ++i) {
-      const base::DictionaryValue* event = nullptr;
-      const base::DictionaryValue* result = nullptr;
-      const base::ListValue* results = nullptr;
-      const base::ListValue* ids = nullptr;
-      base::string16 url;
-      base::string16 title;
-      base::Time visit_time;
+  if (results_value) {
+    has_synced_results_ = true;
+    const base::ListValue* events = nullptr;
+    if (results_value->GetList("event", &events)) {
+      state->remote_results.reserve(state->remote_results.size() +
+                                    events->GetSize());
+      for (unsigned int i = 0; i < events->GetSize(); ++i) {
+        const base::DictionaryValue* event = nullptr;
+        const base::DictionaryValue* result = nullptr;
+        const base::ListValue* results = nullptr;
+        const base::ListValue* ids = nullptr;
+        base::string16 url;
+        base::string16 title;
+        base::Time visit_time;
 
-      if (!(events->GetDictionary(i, &event) &&
-            event->GetList("result", &results) &&
-            results->GetDictionary(0, &result) &&
-            result->GetString("url", &url) && result->GetList("id", &ids) &&
-            ids->GetSize() > 0)) {
-        continue;
-      }
-
-      // Ignore any URLs that should not be shown in the history page.
-      GURL gurl(url);
-      if (driver_->ShouldHideWebHistoryUrl(gurl))
-        continue;
-
-      // Title is optional, so the return value is ignored here.
-      result->GetString("title", &title);
-
-      // Extract the timestamps of all the visits to this URL.
-      // They are referred to as "IDs" by the server.
-      for (int j = 0; j < static_cast<int>(ids->GetSize()); ++j) {
-        const base::DictionaryValue* id = nullptr;
-        std::string timestamp_string;
-        int64_t timestamp_usec = 0;
-
-        if (!ids->GetDictionary(j, &id) ||
-            !id->GetString("timestamp_usec", &timestamp_string) ||
-            !base::StringToInt64(timestamp_string, &timestamp_usec)) {
-          NOTREACHED() << "Unable to extract timestamp.";
+        if (!(events->GetDictionary(i, &event) &&
+              event->GetList("result", &results) &&
+              results->GetDictionary(0, &result) &&
+              result->GetString("url", &url) && result->GetList("id", &ids) &&
+              ids->GetSize() > 0)) {
           continue;
         }
-        // The timestamp on the server is a Unix time.
-        base::Time time = base::Time::UnixEpoch() +
-                          base::TimeDelta::FromMicroseconds(timestamp_usec);
 
-        // Get the ID of the client that this visit came from.
-        std::string client_id;
-        id->GetString("client_id", &client_id);
+        // Ignore any URLs that should not be shown in the history page.
+        GURL gurl(url);
+        if (driver_->ShouldHideWebHistoryUrl(gurl))
+          continue;
 
-        web_history_query_results_.push_back(
-            HistoryEntry(HistoryEntry::REMOTE_ENTRY, gurl, title, time,
-                         client_id, !search_text.empty(), base::string16(),
-                         /* blocked_visit */ false));
+        // Title is optional, so the return value is ignored here.
+        result->GetString("title", &title);
+
+        // Extract the timestamps of all the visits to this URL.
+        // They are referred to as "IDs" by the server.
+        for (int j = 0; j < static_cast<int>(ids->GetSize()); ++j) {
+          const base::DictionaryValue* id = nullptr;
+          std::string timestamp_string;
+          int64_t timestamp_usec = 0;
+
+          if (!ids->GetDictionary(j, &id) ||
+              !id->GetString("timestamp_usec", &timestamp_string) ||
+              !base::StringToInt64(timestamp_string, &timestamp_usec)) {
+            NOTREACHED() << "Unable to extract timestamp.";
+            continue;
+          }
+          // The timestamp on the server is a Unix time.
+          base::Time time = base::Time::UnixEpoch() +
+                            base::TimeDelta::FromMicroseconds(timestamp_usec);
+
+          // Get the ID of the client that this visit came from.
+          std::string client_id;
+          id->GetString("client_id", &client_id);
+
+          state->remote_results.push_back(HistoryEntry(
+              HistoryEntry::REMOTE_ENTRY, gurl, title, time, client_id,
+              !state->search_text.empty(), base::string16(),
+              /* blocked_visit */ false));
+        }
       }
     }
-  }
-
-  query_results_info_.sync_timed_out = false;
-  has_synced_results_ = results_value != nullptr;
-  query_results_info_.has_synced_results = has_synced_results_;
-
-  if (results_value) {
     std::string continuation_token;
     results_value->GetString("continuation_token", &continuation_token);
-    query_results_info_.reached_beginning_of_sync = continuation_token.empty();
+    state->remote_status =
+        continuation_token.empty() ? REACHED_BEGINNING : MORE_RESULTS;
+  } else {
+    has_synced_results_ = false;
+    state->remote_status = FAILURE;
   }
 
   if (!query_task_tracker_.HasTrackedTasks())
-    ReturnResultsToDriver();
+    ReturnResultsToDriver(std::move(state));
 }
 
 void BrowsingHistoryService::OtherFormsOfBrowsingHistoryQueryComplete(
diff --git a/components/history/core/browser/browsing_history_service.h b/components/history/core/browser/browsing_history_service.h
index 42ea9ff..41d15e9 100644
--- a/components/history/core/browser/browsing_history_service.h
+++ b/components/history/core/browser/browsing_history_service.h
@@ -15,6 +15,7 @@
 #include "base/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "base/strings/string16.h"
@@ -82,6 +83,7 @@
     EntryType entry_type;
 
     GURL url;
+
     base::string16 title;  // Title of the entry. May be empty.
 
     // The time of the entry. Usually this will be the time of the most recent
@@ -112,18 +114,18 @@
     // The query search text.
     base::string16 search_text;
 
-    // Whether the query reached the beginning of the local database.
-    bool reached_beginning_of_local = false;
+    // Whether this query reached the end of all results, or if there are more
+    // history entries that can be fetched through paging.
+    bool reached_beginning = false;
 
     // Whether the last call to Web History timed out.
     bool sync_timed_out = false;
 
     // Whether the last call to Web History returned successfully with a message
-    // body.
+    // body. During continuation queries we are not guaranteed to always make a
+    // call to WebHistory, and this value could reflect the state from previous
+    // queries.
     bool has_synced_results = false;
-
-    // Whether the query reached the beginning of the synced history results.
-    bool reached_beginning_of_sync = false;
   };
 
   BrowsingHistoryService(BrowsingHistoryDriver* driver,
@@ -131,45 +133,58 @@
                          syncer::SyncService* sync_service);
   ~BrowsingHistoryService() override;
 
-  // Core implementation of history querying.
+  // Start a new query with the given parameters.
   void QueryHistory(const base::string16& search_text,
                     const QueryOptions& options);
 
   // Removes |items| from history.
-  void RemoveVisits(
-      const std::vector<BrowsingHistoryService::HistoryEntry>& items);
+  void RemoveVisits(const std::vector<HistoryEntry>& items);
 
   // SyncServiceObserver implementation.
   void OnStateChanged(syncer::SyncService* sync) override;
 
-  // Merges duplicate entries from the query results, only retaining the most
-  // recent visit to a URL on a particular day. That visit contains the
-  // timestamps of the other visits.
-  static void MergeDuplicateResults(
-      std::vector<BrowsingHistoryService::HistoryEntry>* results);
-
-  // Callback from the history system when a history query has completed.
-  // Exposed for testing.
-  void QueryComplete(const base::string16& search_text,
-                     const QueryOptions& options,
-                     QueryResults* results);
+ protected:
+  // Constructor that allows specifying more dependencies for unit tests.
+  BrowsingHistoryService(BrowsingHistoryDriver* driver,
+                         HistoryService* local_history,
+                         syncer::SyncService* sync_service,
+                         std::unique_ptr<base::Timer> web_history_timer);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(::BrowsingHistoryHandlerTest,
                            ObservingWebHistoryDeletions);
 
+  // Used to hold and track query state between asynchronous calls.
+  struct QueryHistoryState;
+
+  // Moves results from |state| into |results|, merging both remote and local
+  // results together and maintaining reverse chronological order. Any results
+  // with the same URL will be merged together for each day. Often holds back
+  // some results in |state| from one of the two sources to ensure that they're
+  // always returned to the driver in correct order. This function also updates
+  // the end times in |state| for both sources that the next query should be
+  // made against.
+  static void MergeDuplicateResults(QueryHistoryState* state,
+                                    std::vector<HistoryEntry>* results);
+
+  // Core implementation of history querying.
+  void QueryHistoryInternal(scoped_refptr<QueryHistoryState> state);
+
+  // Callback from the history system when a history query has completed.
+  void QueryComplete(scoped_refptr<QueryHistoryState> state,
+                     QueryResults* results);
+
   // Combines the query results from the local history database and the history
   // server, and sends the combined results to the
   // BrowsingHistoryDriver.
-  void ReturnResultsToDriver();
+  void ReturnResultsToDriver(scoped_refptr<QueryHistoryState> state);
 
   // Callback from |web_history_timer_| when a response from web history has
   // not been received in time.
-  void WebHistoryTimeout();
+  void WebHistoryTimeout(scoped_refptr<QueryHistoryState> state);
 
   // Callback from the WebHistoryService when a query has completed.
-  void WebHistoryQueryComplete(const base::string16& search_text,
-                               const history::QueryOptions& options,
+  void WebHistoryQueryComplete(scoped_refptr<QueryHistoryState> state,
                                base::Time start_time,
                                WebHistoryService::Request* request,
                                const base::DictionaryValue* results_value);
@@ -203,7 +218,7 @@
   std::unique_ptr<WebHistoryService::Request> web_history_request_;
 
   // True if there is a pending delete requests to the history service.
-  bool has_pending_delete_request_;
+  bool has_pending_delete_request_ = false;
 
   // Tracker for delete requests to the history service.
   base::CancelableTaskTracker delete_task_tracker_;
@@ -211,17 +226,8 @@
   // The list of URLs that are in the process of being deleted.
   std::set<GURL> urls_to_be_deleted_;
 
-  // The info value that is returned to the driver with the query results.
-  BrowsingHistoryService::QueryResultsInfo query_results_info_;
-
-  // The list of query results received from the history service.
-  std::vector<HistoryEntry> query_results_;
-
-  // The list of query results received from the history server.
-  std::vector<HistoryEntry> web_history_query_results_;
-
   // Timer used to implement a timeout on a Web History response.
-  base::OneShotTimer web_history_timer_;
+  std::unique_ptr<base::Timer> web_history_timer_;
 
   // HistoryService (local history) observer.
   ScopedObserver<HistoryService, HistoryServiceObserver>
@@ -235,13 +241,11 @@
   ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver>
       sync_service_observer_;
 
-  // TODO(skym): Why is this duplicated between this field and
-  // |query_results_info_.has_synced_results|? Can we simplify?
   // Whether the last call to Web History returned synced results.
-  bool has_synced_results_;
+  bool has_synced_results_ = false;
 
   // Whether there are other forms of browsing history on the history server.
-  bool has_other_forms_of_browsing_history_;
+  bool has_other_forms_of_browsing_history_ = false;
 
   BrowsingHistoryDriver* driver_;
 
diff --git a/components/history/core/browser/browsing_history_service_unittest.cc b/components/history/core/browser/browsing_history_service_unittest.cc
index d15c8c2..f20b5d40e 100644
--- a/components/history/core/browser/browsing_history_service_unittest.cc
+++ b/components/history/core/browser/browsing_history_service_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/timer/mock_timer.h"
 #include "base/values.h"
 #include "components/history/core/browser/browsing_history_driver.h"
 #include "components/history/core/browser/history_db_task.h"
@@ -39,6 +40,9 @@
 const char kUrl2[] = "http://www.two.com";
 const char kUrl3[] = "http://www.three.com";
 const char kUrl4[] = "http://www.four.com";
+const char kUrl5[] = "http://www.five.com";
+const char kUrl6[] = "http://www.six.com";
+const char kUrl7[] = "http://www.seven.com";
 
 const HistoryEntry::EntryType kLocal = HistoryEntry::LOCAL_ENTRY;
 const HistoryEntry::EntryType kRemote = HistoryEntry::REMOTE_ENTRY;
@@ -100,12 +104,19 @@
 
   int GetHistoryDeletedCount() { return history_deleted_count_; }
 
+  void RunContinuation() {
+    EXPECT_TRUE(continuation_closure_);
+    std::move(continuation_closure_).Run();
+  }
+
  private:
   // BrowsingHistoryDriver implementation.
-  void OnQueryComplete(const std::vector<HistoryEntry>& results,
-                       const BrowsingHistoryService::QueryResultsInfo&
-                           query_results_info) override {
+  void OnQueryComplete(
+      const std::vector<HistoryEntry>& results,
+      const BrowsingHistoryService::QueryResultsInfo& query_results_info,
+      base::OnceClosure continuation_closure) override {
     query_results_.push_back(QueryResult(results, query_results_info));
+    continuation_closure_ = std::move(continuation_closure);
   }
   void OnRemoveVisitsComplete() override {}
   void OnRemoveVisitsFailed() override {}
@@ -124,6 +135,7 @@
 
   int history_deleted_count_ = 0;
   std::vector<QueryResult> query_results_;
+  base::OnceClosure continuation_closure_;
   WebHistoryService* web_history_;
 };
 
@@ -139,7 +151,7 @@
     ExpireHistoryCompletionCallback(base::Bind(&DoNothing), &request, true);
   }
 
- private:
+ protected:
   class TestRequest : public WebHistoryService::Request {
    private:
     // WebHistoryService::Request implementation.
@@ -156,6 +168,29 @@
   };
 };
 
+class TimeoutWebHistoryService : public TestWebHistoryService {
+ private:
+  // WebHistoryService implementation.
+  Request* CreateRequest(const GURL& url,
+                         const CompletionCallback& callback,
+                         const net::PartialNetworkTrafficAnnotationTag&
+                             partial_traffic_annotation) override {
+    return new TestWebHistoryService::TestRequest();
+  }
+};
+
+class TestBrowsingHistoryService : public BrowsingHistoryService {
+ public:
+  TestBrowsingHistoryService(BrowsingHistoryDriver* driver,
+                             HistoryService* local_history,
+                             syncer::SyncService* sync_service,
+                             std::unique_ptr<base::Timer> timer)
+      : BrowsingHistoryService(driver,
+                               local_history,
+                               sync_service,
+                               std::move(timer)) {}
+};
+
 class BrowsingHistoryServiceTest : public ::testing::Test {
  protected:
   // WebHistory API is to pass time ranges as the number of microseconds since
@@ -169,17 +204,17 @@
         driver_(&web_history_) {
     EXPECT_TRUE(history_dir_.CreateUniqueTempDir());
     local_history_ = CreateHistoryService(history_dir_.GetPath(), true);
-
-    // Default initialization, tests can override with ResetService().
-    browsing_history_service_ = std::make_unique<BrowsingHistoryService>(
-        driver(), local_history(), sync());
+    ResetService(driver(), local_history(), sync());
   }
 
   void ResetService(BrowsingHistoryDriver* driver,
                     HistoryService* local_history,
                     syncer::SyncService* sync_service) {
-    browsing_history_service_ = std::make_unique<BrowsingHistoryService>(
-        driver, local_history, sync_service);
+    std::unique_ptr<base::MockTimer> timer =
+        std::make_unique<base::MockTimer>(false, false);
+    timer_ = timer.get();
+    browsing_history_service_ = std::make_unique<TestBrowsingHistoryService>(
+        driver, local_history, sync_service, std::move(timer));
   }
 
   void BlockUntilHistoryProcessesPendingRequests() {
@@ -195,20 +230,6 @@
     return baseline_time_ + TimeDelta::FromHours(hour_offset);
   }
 
-  // For each item in |test_results|, create a new HistoryEntry representing the
-  // and insert it into |results|.
-  void AddQueryResults(const std::vector<TestResult>& test_results,
-                       std::vector<HistoryEntry>* results) {
-    for (const TestResult& result : test_results) {
-      HistoryEntry entry;
-      entry.time = OffsetToTime(result.hour_offset);
-      entry.url = GURL(result.url);
-      entry.all_timestamps.insert(entry.time.ToInternalValue());
-      entry.entry_type = result.type;
-      results->push_back(entry);
-    }
-  }
-
   void AddHistory(const std::vector<TestResult>& data) {
     for (const TestResult& entry : data) {
       if (entry.type == kLocal) {
@@ -231,6 +252,12 @@
               static_cast<int>(actual.entry_type));
   }
 
+  TestBrowsingHistoryDriver::QueryResult QueryHistory(size_t max_count = 0) {
+    QueryOptions options;
+    options.max_count = max_count;
+    return QueryHistory(options);
+  }
+
   TestBrowsingHistoryDriver::QueryResult QueryHistory(
       const QueryOptions& options) {
     size_t previous_results_count = driver()->GetQueryResults().size();
@@ -242,40 +269,37 @@
     return *all_results.rbegin();
   }
 
-  void VerifyQueryResult(bool reached_beginning_of_local,
+  TestBrowsingHistoryDriver::QueryResult ContinueQuery() {
+    size_t previous_results_count = driver()->GetQueryResults().size();
+    driver()->RunContinuation();
+    BlockUntilHistoryProcessesPendingRequests();
+    const std::vector<TestBrowsingHistoryDriver::QueryResult> all_results =
+        driver()->GetQueryResults();
+    EXPECT_EQ(previous_results_count + 1, all_results.size());
+    return *all_results.rbegin();
+  }
+
+  void VerifyQueryResult(bool reached_beginning,
                          bool has_synced_results,
-                         bool reached_beginning_of_sync,
                          const std::vector<TestResult>& expected_entries,
                          TestBrowsingHistoryDriver::QueryResult result) {
-    EXPECT_EQ(reached_beginning_of_local,
-              result.second.reached_beginning_of_local);
+    EXPECT_EQ(reached_beginning, result.second.reached_beginning);
     EXPECT_EQ(has_synced_results, result.second.has_synced_results);
     EXPECT_FALSE(result.second.sync_timed_out);
-    EXPECT_EQ(reached_beginning_of_sync,
-              result.second.reached_beginning_of_sync);
     EXPECT_EQ(expected_entries.size(), result.first.size());
     for (size_t i = 0; i < expected_entries.size(); ++i) {
       VerifyEntry(expected_entries[i], result.first[i]);
     }
   }
 
-  void QueryAndVerifySingleQueryResult(
-      bool reached_beginning_of_local,
-      bool has_synced_results,
-      bool reached_beginning_of_sync,
-      const std::vector<TestResult>& expected_entries) {
-    EXPECT_EQ(0U, driver()->GetQueryResults().size());
-    TestBrowsingHistoryDriver::QueryResult result =
-        QueryHistory(QueryOptions());
-    VerifyQueryResult(reached_beginning_of_local, has_synced_results,
-                      reached_beginning_of_sync, expected_entries, result);
-  }
-
   HistoryService* local_history() { return local_history_.get(); }
   TestWebHistoryService* web_history() { return &web_history_; }
   TestSyncService* sync() { return &sync_service_; }
   TestBrowsingHistoryDriver* driver() { return &driver_; }
-  BrowsingHistoryService* service() { return browsing_history_service_.get(); }
+  base::MockTimer* timer() { return timer_; }
+  TestBrowsingHistoryService* service() {
+    return browsing_history_service_.get();
+  }
 
  private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
@@ -289,152 +313,59 @@
   TestWebHistoryService web_history_;
   TestSyncService sync_service_;
   TestBrowsingHistoryDriver driver_;
-  std::unique_ptr<BrowsingHistoryService> browsing_history_service_;
+  base::MockTimer* timer_;
+  std::unique_ptr<TestBrowsingHistoryService> browsing_history_service_;
 };
 
-// Tests that the MergeDuplicateResults method correctly removes duplicate
-// visits to the same URL on the same day.
-TEST_F(BrowsingHistoryServiceTest, MergeDuplicateResults) {
-  {
-    // Basic test that duplicates on the same day are removed.
-    const std::vector<TestResult> test_data{
-        {kUrl1, 0, kLocal},
-        {kUrl2, 1, kLocal},
-        {kUrl1, 2, kLocal},
-        {kUrl1, 3, kLocal}  // Most recent.
-    };
-    std::vector<HistoryEntry> results;
-    AddQueryResults(test_data, &results);
-    BrowsingHistoryService::MergeDuplicateResults(&results);
-
-    ASSERT_EQ(2U, results.size());
-    VerifyEntry(test_data[3], results[0]);
-    VerifyEntry(test_data[1], results[1]);
-  }
-
-  {
-    // Test that a duplicate URL on the next day is not removed.
-    const std::vector<TestResult> test_data{
-        {kUrl1, 0, kLocal},
-        {kUrl1, 23, kLocal},
-        {kUrl1, 24, kLocal},  // Most recent.
-    };
-    std::vector<HistoryEntry> results;
-    AddQueryResults(test_data, &results);
-    BrowsingHistoryService::MergeDuplicateResults(&results);
-
-    ASSERT_EQ(2U, results.size());
-    VerifyEntry(test_data[2], results[0]);
-    VerifyEntry(test_data[1], results[1]);
-  }
-
-  {
-    // Test multiple duplicates across multiple days.
-    const std::vector<TestResult> test_data{
-        // First day.
-        {kUrl2, 0, kLocal},
-        {kUrl1, 1, kLocal},
-        {kUrl2, 2, kLocal},
-        {kUrl1, 3, kLocal},
-
-        // Second day.
-        {kUrl2, 24, kLocal},
-        {kUrl1, 25, kLocal},
-        {kUrl2, 26, kLocal},
-        {kUrl1, 27, kLocal},  // Most recent.
-    };
-    std::vector<HistoryEntry> results;
-    AddQueryResults(test_data, &results);
-    BrowsingHistoryService::MergeDuplicateResults(&results);
-
-    ASSERT_EQ(4U, results.size());
-    VerifyEntry(test_data[7], results[0]);
-    VerifyEntry(test_data[6], results[1]);
-    VerifyEntry(test_data[3], results[2]);
-    VerifyEntry(test_data[2], results[3]);
-  }
-
-  {
-    // Test that timestamps for duplicates are properly saved.
-    const std::vector<TestResult> test_data{
-        {kUrl1, 0, kLocal},
-        {kUrl2, 1, kLocal},
-        {kUrl1, 2, kLocal},
-        {kUrl1, 3, kLocal}  // Most recent.
-    };
-    std::vector<HistoryEntry> results;
-    AddQueryResults(test_data, &results);
-    BrowsingHistoryService::MergeDuplicateResults(&results);
-
-    ASSERT_EQ(2U, results.size());
-    VerifyEntry(test_data[3], results[0]);
-    VerifyEntry(test_data[1], results[1]);
-    EXPECT_EQ(3u, results[0].all_timestamps.size());
-    EXPECT_EQ(1u, results[1].all_timestamps.size());
-  }
-}
-
 TEST_F(BrowsingHistoryServiceTest, QueryHistoryNoSources) {
   driver()->SetWebHistory(nullptr);
   ResetService(driver(), nullptr, nullptr);
-
-  // TODO(skym): Fix service to return results when neither local or web
-  // history dependencies are given. Right now it never attempts to invoke
-  // callback.
-  // QueryAndVerifySingleQueryResult(false, false, {});
-  service()->QueryHistory(base::string16(), QueryOptions());
-  BlockUntilHistoryProcessesPendingRequests();
+  VerifyQueryResult(/*reached_beginning*/ true,
+                    /*has_synced_results*/ false, {}, QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryJustLocal) {
   driver()->SetWebHistory(nullptr);
   ResetService(driver(), local_history(), nullptr);
-  QueryAndVerifySingleQueryResult(/*reached_beginning_of_local*/ true,
-                                  /*has_synced_results*/ false,
-                                  /*reached_beginning_of_sync*/ false, {});
+  VerifyQueryResult(/*reached_beginning*/ true,
+                    /*has_synced_results*/ false, {}, QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, QueryHistoryJustLocal) {
   driver()->SetWebHistory(nullptr);
   ResetService(driver(), local_history(), nullptr);
-
   AddHistory({{kUrl1, 1, kLocal}});
-  QueryAndVerifySingleQueryResult(/*reached_beginning_of_local*/ true,
-                                  /*has_synced_results*/ false,
-                                  /*reached_beginning_of_sync*/ false,
-                                  {{kUrl1, 1, kLocal}});
+  VerifyQueryResult(/*reached_beginning*/ true,
+                    /*has_synced_results*/ false, {{kUrl1, 1, kLocal}},
+                    QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryJustWeb) {
   ResetService(driver(), nullptr, nullptr);
-  QueryAndVerifySingleQueryResult(/*reached_beginning_of_local*/ false,
-                                  /*has_synced_results*/ true,
-                                  /*reached_beginning_of_sync*/ true, {});
+  VerifyQueryResult(/*reached_beginning*/ true,
+                    /*has_synced_results*/ true, {}, QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryDelayedWeb) {
   driver()->SetWebHistory(nullptr);
   ResetService(driver(), nullptr, sync());
   driver()->SetWebHistory(web_history());
-  QueryAndVerifySingleQueryResult(/*reached_beginning_of_local*/ false,
-                                  /*has_synced_results*/ true,
-                                  /*reached_beginning_of_sync*/ true, {});
+  VerifyQueryResult(/*reached_beginning*/ true,
+                    /*has_synced_results*/ true, {}, QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, QueryHistoryJustWeb) {
   ResetService(driver(), nullptr, sync());
   AddHistory({{kUrl1, 1, kRemote}});
-  QueryAndVerifySingleQueryResult(/*reached_beginning_of_local*/ false,
-                                  /*has_synced_results*/ true,
-                                  /*reached_beginning_of_sync*/ true,
-                                  {{kUrl1, 1, kRemote}});
+  VerifyQueryResult(/*reached_beginning*/ true,
+                    /*has_synced_results*/ true, {{kUrl1, 1, kRemote}},
+                    QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, EmptyQueryHistoryBothSources) {
   ResetService(driver(), local_history(), sync());
-  QueryAndVerifySingleQueryResult(/*reached_beginning_of_local*/ true,
-                                  /*has_synced_results*/ true,
-                                  /*reached_beginning_of_sync*/ true, {});
+  VerifyQueryResult(/*reached_beginning*/ true,
+                    /*has_synced_results*/ true, {}, QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, QueryHistoryAllSources) {
@@ -443,10 +374,10 @@
               {kUrl2, 2, kLocal},
               {kUrl3, 3, kRemote},
               {kUrl1, 4, kRemote}});
-  QueryAndVerifySingleQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true,
-      {{kUrl1, 4, kBoth}, {kUrl3, 3, kRemote}, {kUrl2, 2, kLocal}});
+  VerifyQueryResult(
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
+      {{kUrl1, 4, kBoth}, {kUrl3, 3, kRemote}, {kUrl2, 2, kLocal}},
+      QueryHistory());
 }
 
 TEST_F(BrowsingHistoryServiceTest, QueryHistoryLocalTimeRanges) {
@@ -457,14 +388,13 @@
   QueryOptions options;
   options.begin_time = OffsetToTime(2);
   options.end_time = OffsetToTime(4);
-  // Having a |reached_beginning_of_local| value of false here seems
+  // Having a |reached_beginning| value of false here seems
   // counterintuitive. Seems to be for paging by |begin_time| instead of
   // |count|. If the local history implementation changes, feel free to update
   // this value, all this test cares about is that BrowsingHistoryService passes
   // the values through correctly.
-  VerifyQueryResult(/*reached_beginning_of_local*/ false,
+  VerifyQueryResult(/*reached_beginning*/ false,
                     /*has_synced_results*/ true,
-                    /*reached_beginning_of_sync*/ true,
                     {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}},
                     QueryHistory(options));
 }
@@ -478,75 +408,252 @@
   options.begin_time = OffsetToTime(2);
   options.end_time = OffsetToTime(4);
   VerifyQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true,
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
       {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}}, QueryHistory(options));
 }
 
-TEST_F(BrowsingHistoryServiceTest, QueryHistoryLocalPaging) {
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryLocalPagingPartial) {
   AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
-
-  QueryOptions options;
-  options.max_count = 2;
-  VerifyQueryResult(/*reached_beginning_of_local*/ false,
+  VerifyQueryResult(/*reached_beginning*/ false,
                     /*has_synced_results*/ true,
-                    /*reached_beginning_of_sync*/ true,
-                    {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}},
-                    QueryHistory(options));
-
-  options.end_time = OffsetToTime(2);
+                    {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}}, QueryHistory(2));
   VerifyQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true, {{kUrl1, 1, kLocal}},
-      QueryHistory(options));
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
+      {{kUrl1, 1, kLocal}}, ContinueQuery());
+}
 
-  options.end_time = Time();
-  options.max_count = 3;
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryLocalPagingFull) {
+  AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
   VerifyQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true,
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
       {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}, {kUrl1, 1, kLocal}},
-      QueryHistory(options));
-
-  options.end_time = OffsetToTime(1);
+      QueryHistory(3));
   VerifyQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true, {}, QueryHistory(options));
+      /*reached_beginning*/ true, /*has_synced_results*/ true, {},
+      ContinueQuery());
 }
 
-TEST_F(BrowsingHistoryServiceTest, QueryHistoryRemotePaging) {
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryRemotePagingPartial) {
   AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
-
-  QueryOptions options;
-  options.max_count = 2;
-  VerifyQueryResult(/*reached_beginning_of_local*/ true,
+  VerifyQueryResult(/*reached_beginning*/ false,
                     /*has_synced_results*/ true,
-                    /*reached_beginning_of_sync*/ false,
                     {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}},
-                    QueryHistory(options));
-
-  options.end_time = OffsetToTime(2);
+                    QueryHistory(2));
   VerifyQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true, {{kUrl1, 1, kRemote}},
-      QueryHistory(options));
-
-  options.end_time = Time();
-  options.max_count = 3;
-  VerifyQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true,
-      {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}, {kUrl1, 1, kRemote}},
-      QueryHistory(options));
-
-  options.end_time = OffsetToTime(1);
-  VerifyQueryResult(
-      /*reached_beginning_of_local*/ true, /*has_synced_results*/ true,
-      /*reached_beginning_of_sync*/ true, {}, QueryHistory(options));
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
+      {{kUrl1, 1, kRemote}}, ContinueQuery());
 }
 
-// TODO(skym, crbug.com/728727): Add more test cases, particularly when
-// QueryHistory returns partial results and sequential calls are made.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryRemotePagingFull) {
+  AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
+  VerifyQueryResult(
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
+      {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}, {kUrl1, 1, kRemote}},
+      QueryHistory(3));
+  VerifyQueryResult(
+      /*reached_beginning*/ true, /*has_synced_results*/ true, {},
+      ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesSameDay) {
+  AddHistory({{kUrl1, 0, kRemote},
+              {kUrl2, 1, kRemote},
+              {kUrl1, 2, kRemote},
+              {kUrl1, 3, kRemote}});
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl1, 3, kRemote}, {kUrl2, 1, kRemote}}, QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesNextDayNotRemoved) {
+  AddHistory({{kUrl1, 0, kRemote}, {kUrl1, 23, kRemote}, {kUrl1, 24, kRemote}});
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl1, 24, kRemote}, {kUrl1, 23, kRemote}},
+                    QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesMultipleDays) {
+  AddHistory({{kUrl2, 0, kRemote},
+              {kUrl1, 1, kRemote},
+              {kUrl2, 2, kRemote},
+              {kUrl1, 3, kRemote},
+              {kUrl2, 24, kRemote},
+              {kUrl1, 25, kRemote},
+              {kUrl2, 26, kRemote},
+              {kUrl1, 27, kRemote}});
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl1, 27, kRemote},
+                     {kUrl2, 26, kRemote},
+                     {kUrl1, 3, kRemote},
+                     {kUrl2, 2, kRemote}},
+                    QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, MergeDuplicatesVerifyTimestamps) {
+  AddHistory({{kUrl1, 0, kRemote},
+              {kUrl2, 1, kRemote},
+              {kUrl1, 2, kRemote},
+              {kUrl1, 3, kRemote}});
+  auto results = QueryHistory();
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl1, 3, kRemote}, {kUrl2, 1, kRemote}}, results);
+  EXPECT_EQ(3U, results.first[0].all_timestamps.size());
+  EXPECT_EQ(1U, results.first[1].all_timestamps.size());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryMerge) {
+  AddHistory({{kUrl1, 1, kRemote},
+              {kUrl2, 2, kRemote},
+              {kUrl3, 3, kLocal},
+              {kUrl1, 4, kLocal}});
+  VerifyQueryResult(
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
+      {{kUrl1, 4, kBoth}, {kUrl3, 3, kLocal}, {kUrl2, 2, kRemote}},
+      QueryHistory());
+}
+
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryPending) {
+  AddHistory({{kUrl1, 1, kRemote},
+              {kUrl2, 2, kRemote},
+              {kUrl3, 3, kLocal},
+              {kUrl4, 4, kLocal}});
+  VerifyQueryResult(
+      /*reached_beginning*/ false, /*has_synced_results*/ true,
+      {{kUrl4, 4, kLocal}}, QueryHistory(1));
+  VerifyQueryResult(
+      /*reached_beginning*/ false, /*has_synced_results*/ true,
+      {{kUrl3, 3, kLocal}, {kUrl2, 2, kRemote}}, ContinueQuery());
+  VerifyQueryResult(
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
+      {{kUrl1, 1, kRemote}}, ContinueQuery());
+}
+
+// A full request worth of local results will sit in pending, resulting in us
+// being able to delete local history before our next query and we should still
+// see the local entry.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryFullLocalPending) {
+  AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
+  VerifyQueryResult(
+      /*reached_beginning*/ false, /*has_synced_results*/ true,
+      {{kUrl3, 3, kRemote}}, QueryHistory(1));
+
+  local_history()->DeleteURL(GURL(kUrl1));
+  VerifyQueryResult(
+      /*reached_beginning*/ true, /*has_synced_results*/ true,
+      {{kUrl2, 2, kRemote}, {kUrl1, 1, kLocal}}, ContinueQuery());
+}
+
+// Part of a request worth of local results will sit in pending, resulting in us
+// seeing extra local results on our next request.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryPartialLocalPending) {
+  AddHistory({{kUrl1, 1, kLocal},
+              {kUrl2, 2, kLocal},
+              {kUrl3, 3, kRemote},
+              {kUrl4, 4, kLocal},
+              {kUrl5, 5, kRemote},
+              {kUrl6, 6, kRemote},
+              {kUrl7, 7, kLocal}});
+  VerifyQueryResult(
+      /*reached_beginning*/ false, /*has_synced_results*/ true,
+      {{kUrl7, 7, kLocal}, {kUrl6, 6, kRemote}, {kUrl5, 5, kRemote}},
+      QueryHistory(2));
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl4, 4, kLocal},
+                     {kUrl3, 3, kRemote},
+                     {kUrl2, 2, kLocal},
+                     {kUrl1, 1, kLocal}},
+                    ContinueQuery());
+}
+
+// A full request worth of remote results will sit in pending, resulting in us
+// being able to delete remote history before our next query and we should still
+// see the remote entry.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryFullRemotePending) {
+  AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
+  VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ true,
+                    {{kUrl3, 3, kLocal}}, QueryHistory(1));
+
+  web_history()->ClearSyncedVisits();
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl2, 2, kLocal}, {kUrl1, 1, kRemote}}, ContinueQuery());
+}
+
+// Part of a request worth of remote results will sit in pending, resulting in
+// us seeing extra remote results on our next request.
+TEST_F(BrowsingHistoryServiceTest, QueryHistoryPartialRemotePending) {
+  AddHistory({{kUrl1, 1, kRemote},
+              {kUrl2, 2, kRemote},
+              {kUrl3, 3, kLocal},
+              {kUrl4, 4, kRemote},
+              {kUrl5, 5, kLocal},
+              {kUrl6, 6, kLocal},
+              {kUrl7, 7, kRemote}});
+  VerifyQueryResult(
+      /*reached_beginning*/ false, /*has_synced_results*/ true,
+      {{kUrl7, 7, kRemote}, {kUrl6, 6, kLocal}, {kUrl5, 5, kLocal}},
+      QueryHistory(2));
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl4, 4, kRemote},
+                     {kUrl3, 3, kLocal},
+                     {kUrl2, 2, kRemote},
+                     {kUrl1, 1, kRemote}},
+                    ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, RetryOnRemoteFailureEmpty) {
+  web_history()->SetupFakeResponse(false, 0);
+  VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ false,
+                    {}, QueryHistory());
+  web_history()->SetupFakeResponse(true, net::HTTP_OK);
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true, {},
+                    ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, RetryOnRemoteFailurePagingRemote) {
+  AddHistory({{kUrl1, 1, kRemote}, {kUrl2, 2, kRemote}, {kUrl3, 3, kRemote}});
+  VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ true,
+                    {{kUrl3, 3, kRemote}, {kUrl2, 2, kRemote}},
+                    QueryHistory(2));
+
+  web_history()->SetupFakeResponse(false, 0);
+  VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ false,
+                    {}, ContinueQuery());
+
+  web_history()->SetupFakeResponse(true, net::HTTP_OK);
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl1, 1, kRemote}}, ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, RetryOnRemoteFailurePagingLocal) {
+  AddHistory({{kUrl1, 1, kLocal}, {kUrl2, 2, kLocal}, {kUrl3, 3, kLocal}});
+  web_history()->SetupFakeResponse(false, 0);
+  VerifyQueryResult(/*reached_beginning*/ false, /*has_synced_results*/ false,
+                    {{kUrl3, 3, kLocal}, {kUrl2, 2, kLocal}}, QueryHistory(2));
+
+  web_history()->SetupFakeResponse(true, net::HTTP_OK);
+  VerifyQueryResult(/*reached_beginning*/ true, /*has_synced_results*/ true,
+                    {{kUrl1, 1, kLocal}}, ContinueQuery());
+}
+
+TEST_F(BrowsingHistoryServiceTest, WebHistoryTimeout) {
+  TimeoutWebHistoryService timeout;
+  driver()->SetWebHistory(&timeout);
+  ResetService(driver(), local_history(), sync());
+  EXPECT_EQ(0U, driver()->GetQueryResults().size());
+  service()->QueryHistory(base::string16(), QueryOptions());
+  EXPECT_EQ(0U, driver()->GetQueryResults().size());
+  BlockUntilHistoryProcessesPendingRequests();
+  timer()->Fire();
+  EXPECT_EQ(1U, driver()->GetQueryResults().size());
+  EXPECT_FALSE(driver()->GetQueryResults()[0].second.reached_beginning);
+  EXPECT_FALSE(driver()->GetQueryResults()[0].second.has_synced_results);
+  EXPECT_TRUE(driver()->GetQueryResults()[0].second.sync_timed_out);
+
+  // WebHistoryService will DCHECK if we destroy it before the observer in
+  // BrowsingHistoryService is removed, so reset our first
+  // BrowsingHistoryService before |timeout| goes out of scope.
+  driver()->SetWebHistory(nullptr);
+  ResetService(driver(), nullptr, nullptr);
+}
 
 TEST_F(BrowsingHistoryServiceTest, ObservingWebHistory) {
   ResetService(driver(), nullptr, sync());
diff --git a/components/infobars/core/infobar_delegate.cc b/components/infobars/core/infobar_delegate.cc
index c3c0c97..4719771 100644
--- a/components/infobars/core/infobar_delegate.cc
+++ b/components/infobars/core/infobar_delegate.cc
@@ -93,10 +93,6 @@
   return nullptr;
 }
 
-PermissionInfoBarDelegate* InfoBarDelegate::AsPermissionInfoBarDelegate() {
-  return nullptr;
-}
-
 PopupBlockedInfoBarDelegate* InfoBarDelegate::AsPopupBlockedInfoBarDelegate() {
   return nullptr;
 }
@@ -126,11 +122,6 @@
 }
 
 #if defined(OS_ANDROID)
-MediaStreamInfoBarDelegateAndroid*
-InfoBarDelegate::AsMediaStreamInfoBarDelegateAndroid() {
-  return nullptr;
-}
-
 offline_pages::OfflinePageInfoBarDelegate*
 InfoBarDelegate::AsOfflinePageInfoBarDelegate() {
   return nullptr;
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 398cee4..d07b82aa 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -14,7 +14,6 @@
 class HungRendererInfoBarDelegate;
 class InsecureContentInfoBarDelegate;
 class NativeAppInfoBarDelegate;
-class PermissionInfoBarDelegate;
 class PopupBlockedInfoBarDelegate;
 class RegisterProtocolHandlerInfoBarDelegate;
 class ScreenCaptureInfoBarDelegate;
@@ -22,8 +21,6 @@
 class ThreeDAPIInfoBarDelegate;
 
 #if defined(OS_ANDROID)
-class MediaStreamInfoBarDelegateAndroid;
-
 namespace offline_pages {
 class OfflinePageInfoBarDelegate;
 }
@@ -75,22 +72,22 @@
     APP_BANNER_INFOBAR_DELEGATE_DESKTOP = 2,
     ANDROID_DOWNLOAD_MANAGER_DUPLICATE_INFOBAR_DELEGATE = 3,
     CHROME_DUPLICATE_DOWNLOAD_INFOBAR_DELEGATE = 4,
-    DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID = 5,
+    // Removed: DOWNLOAD_REQUEST_INFOBAR_DELEGATE_ANDROID = 5,
     // Removed: FULLSCREEN_INFOBAR_DELEGATE = 6,
     HUNG_PLUGIN_INFOBAR_DELEGATE = 7,
     HUNG_RENDERER_INFOBAR_DELEGATE = 8,
-    MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID = 9,
+    // Removed: MEDIA_STREAM_INFOBAR_DELEGATE_ANDROID = 9,
     MEDIA_THROTTLE_INFOBAR_DELEGATE = 10,
-    REQUEST_QUOTA_INFOBAR_DELEGATE = 11,
+    // Removed: REQUEST_QUOTA_INFOBAR_DELEGATE = 11,
     DEV_TOOLS_CONFIRM_INFOBAR_DELEGATE = 12,
     EXTENSION_DEV_TOOLS_INFOBAR_DELEGATE = 13,
     INCOGNITO_CONNECTABILITY_INFOBAR_DELEGATE = 14,
     THEME_INSTALLED_INFOBAR_DELEGATE = 15,
-    GEOLOCATION_INFOBAR_DELEGATE_ANDROID = 16,
+    // Removed: GEOLOCATION_INFOBAR_DELEGATE_ANDROID = 16,
     THREE_D_API_INFOBAR_DELEGATE = 17,
     // Removed: INSECURE_CONTENT_INFOBAR_DELEGATE = 18,
-    MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID = 19,
-    PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID = 20,
+    // Removed: MIDI_PERMISSION_INFOBAR_DELEGATE_ANDROID = 19,
+    // Removed: PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_ANDROID = 20,
     NACL_INFOBAR_DELEGATE = 21,
     // Removed: DATA_REDUCTION_PROXY_INFOBAR_DELEGATE_ANDROID = 22,
     NOTIFICATION_PERMISSION_INFOBAR_DELEGATE = 23,
@@ -99,7 +96,7 @@
     SAVE_PASSWORD_INFOBAR_DELEGATE = 26,
     PEPPER_BROKER_INFOBAR_DELEGATE = 27,
     PERMISSION_UPDATE_INFOBAR_DELEGATE = 28,
-    DURABLE_STORAGE_PERMISSION_INFOBAR_DELEGATE_ANDROID = 29,
+    // Removed: DURABLE_STORAGE_PERMISSION_INFOBAR_DELEGATE_ANDROID = 29,
     // Removed: NPAPI_REMOVAL_INFOBAR_DELEGATE = 30,
     OUTDATED_PLUGIN_INFOBAR_DELEGATE = 31,
     PLUGIN_METRO_MODE_INFOBAR_DELEGATE = 32,
@@ -219,7 +216,6 @@
   virtual HungRendererInfoBarDelegate* AsHungRendererInfoBarDelegate();
   virtual InsecureContentInfoBarDelegate* AsInsecureContentInfoBarDelegate();
   virtual NativeAppInfoBarDelegate* AsNativeAppInfoBarDelegate();
-  virtual PermissionInfoBarDelegate* AsPermissionInfoBarDelegate();
   virtual PopupBlockedInfoBarDelegate* AsPopupBlockedInfoBarDelegate();
   virtual RegisterProtocolHandlerInfoBarDelegate*
       AsRegisterProtocolHandlerInfoBarDelegate();
@@ -228,8 +224,6 @@
   virtual ThreeDAPIInfoBarDelegate* AsThreeDAPIInfoBarDelegate();
   virtual translate::TranslateInfoBarDelegate* AsTranslateInfoBarDelegate();
 #if defined(OS_ANDROID)
-  virtual MediaStreamInfoBarDelegateAndroid*
-  AsMediaStreamInfoBarDelegateAndroid();
   virtual offline_pages::OfflinePageInfoBarDelegate*
   AsOfflinePageInfoBarDelegate();
 #endif
diff --git a/components/network_error_logging/BUILD.gn b/components/network_error_logging/BUILD.gn
new file mode 100644
index 0000000..65d2d6e3
--- /dev/null
+++ b/components/network_error_logging/BUILD.gn
@@ -0,0 +1,34 @@
+# 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.
+
+component("network_error_logging") {
+  sources = [
+    "network_error_logging_export.h",
+    "network_error_logging_service.cc",
+    "network_error_logging_service.h",
+  ]
+
+  defines = [ "NETWORK_ERROR_LOGGING_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+    "//net",
+    "//url",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "network_error_logging_service_unittest.cc",
+  ]
+
+  deps = [
+    ":network_error_logging",
+    "//base",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/network_error_logging/DEPS b/components/network_error_logging/DEPS
new file mode 100644
index 0000000..c902051
--- /dev/null
+++ b/components/network_error_logging/DEPS
@@ -0,0 +1,7 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include_rules = [
+  "+net",
+]
diff --git a/components/network_error_logging/OWNERS b/components/network_error_logging/OWNERS
new file mode 100644
index 0000000..edfcd71
--- /dev/null
+++ b/components/network_error_logging/OWNERS
@@ -0,0 +1,4 @@
+juliatuttle@chromium.org
+mgersh@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/components/network_error_logging/network_error_logging_export.h b/components/network_error_logging/network_error_logging_export.h
new file mode 100644
index 0000000..7a13cb52
--- /dev/null
+++ b/components/network_error_logging/network_error_logging_export.h
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_EXPORT_H_
+#define COMPONENTS_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(NETWORK_ERROR_LOGGING_IMPLEMENTATION)
+#define NETWORK_ERROR_LOGGING_EXPORT __declspec(dllexport)
+#else
+#define NETWORK_ERROR_LOGGING_EXPORT __declspec(dllimport)
+#endif
+
+#else  // defined(WIN32)
+
+#if defined(NETWORK_ERROR_LOGGING_IMPLEMENTATION)
+#define NETWORK_ERROR_LOGGING_EXPORT __attribute__((visibility("default")))
+#else
+#define NETWORK_ERROR_LOGGING_EXPORT
+#endif
+
+#endif  // defined(WIN32)
+#else   // defined(COMPONENT_BUILD)
+
+#define NETWORK_ERROR_LOGGING_EXPORT
+
+#endif
+
+#endif  // COMPONENTS_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_EXPORT_H_
diff --git a/components/network_error_logging/network_error_logging_service.cc b/components/network_error_logging/network_error_logging_service.cc
new file mode 100644
index 0000000..5a999b7
--- /dev/null
+++ b/components/network_error_logging/network_error_logging_service.cc
@@ -0,0 +1,55 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/network_error_logging/network_error_logging_service.h"
+
+#include <memory>
+#include <string>
+
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "net/base/net_errors.h"
+#include "net/reporting/reporting_service.h"
+#include "url/origin.h"
+
+namespace features {
+
+const base::Feature kNetworkErrorLogging{"NetworkErrorLogging",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace features
+
+namespace network_error_logging {
+
+// static
+std::unique_ptr<NetworkErrorLoggingService>
+NetworkErrorLoggingService::Create() {
+  if (!base::FeatureList::IsEnabled(features::kNetworkErrorLogging))
+    return std::unique_ptr<NetworkErrorLoggingService>();
+
+  // Would be MakeUnique, but the constructor is private so MakeUnique can't see
+  // it.
+  return base::WrapUnique(new NetworkErrorLoggingService());
+}
+
+NetworkErrorLoggingService::~NetworkErrorLoggingService() {}
+
+void NetworkErrorLoggingService::SetReportingService(
+    net::ReportingService* reporting_service) {
+  reporting_service_ = reporting_service;
+}
+
+void NetworkErrorLoggingService::OnHeader(const url::Origin& origin,
+                                          const std::string& value) {}
+
+void NetworkErrorLoggingService::OnNetworkError(
+    const url::Origin& origin,
+    net::Error error,
+    ErrorDetailsCallback details_callback) {}
+
+NetworkErrorLoggingService::NetworkErrorLoggingService()
+    : reporting_service_(nullptr) {}
+
+}  // namespace network_error_logging
diff --git a/components/network_error_logging/network_error_logging_service.h b/components/network_error_logging/network_error_logging_service.h
new file mode 100644
index 0000000..fd3bb5fc
--- /dev/null
+++ b/components/network_error_logging/network_error_logging_service.h
@@ -0,0 +1,63 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_SERVICE_H_
+#define COMPONENTS_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "components/network_error_logging/network_error_logging_export.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/network_error_logging_delegate.h"
+
+namespace net {
+class ReportingService;
+}  // namespace net
+
+namespace url {
+class Origin;
+}  // namespace url
+
+namespace features {
+extern const base::Feature NETWORK_ERROR_LOGGING_EXPORT kNetworkErrorLogging;
+}  // namespace features
+
+namespace network_error_logging {
+
+class NETWORK_ERROR_LOGGING_EXPORT NetworkErrorLoggingService
+    : public net::NetworkErrorLoggingDelegate {
+ public:
+  // Creates the NetworkErrorLoggingService.
+  //
+  // Will return nullptr if Network Error Logging is disabled via
+  // base::FeatureList.
+  static std::unique_ptr<NetworkErrorLoggingService> Create();
+
+  // net::NetworkErrorLoggingDelegate implementation:
+
+  ~NetworkErrorLoggingService() override;
+
+  void SetReportingService(net::ReportingService* reporting_service) override;
+
+  void OnHeader(const url::Origin& origin, const std::string& value) override;
+
+  void OnNetworkError(const url::Origin& origin,
+                      net::Error error,
+                      ErrorDetailsCallback details_callback) override;
+
+ private:
+  NetworkErrorLoggingService();
+
+  // Unowned.
+  net::ReportingService* reporting_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkErrorLoggingService);
+};
+
+}  // namespace network_error_logging
+
+#endif  // COMPONENTS_NETWORK_ERROR_LOGGING_NETWORK_ERROR_LOGGING_SERVICE_H_
diff --git a/components/network_error_logging/network_error_logging_service_unittest.cc b/components/network_error_logging/network_error_logging_service_unittest.cc
new file mode 100644
index 0000000..681798a
--- /dev/null
+++ b/components/network_error_logging/network_error_logging_service_unittest.cc
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/network_error_logging/network_error_logging_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class NetworkErrorLoggingServiceTest : public ::testing::Test {
+ protected:
+  NetworkErrorLoggingServiceTest() {
+    scoped_feature_list_.InitAndEnableFeature(features::kNetworkErrorLogging);
+    service_ = network_error_logging::NetworkErrorLoggingService::Create();
+  }
+
+  network_error_logging::NetworkErrorLoggingService* service() {
+    return service_.get();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<network_error_logging::NetworkErrorLoggingService> service_;
+};
+
+TEST_F(NetworkErrorLoggingServiceTest, FeatureDisabled) {
+  // N.B. This test does not actually use the test fixture.
+
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(features::kNetworkErrorLogging);
+
+  auto service = network_error_logging::NetworkErrorLoggingService::Create();
+  EXPECT_FALSE(service);
+}
+
+TEST_F(NetworkErrorLoggingServiceTest, FeatureEnabled) {
+  EXPECT_TRUE(service());
+}
+
+}  // namespace
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
index c6420b89..5291ffa 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -309,6 +309,21 @@
   }
 }
 
+void AddDismissedArchivedIdsToRequest(
+    const base::circular_deque<std::unique_ptr<RemoteSuggestion>>& archived,
+    RequestParams* request_params) {
+  // We add all archived, dismissed IDs to the request (the archive is limited
+  // to kMaxArchivedSuggestionCount suggestions). They don't get persisted,
+  // which means that the user very recently dismissed them and that they are
+  // usually not many.
+  for (auto it = archived.begin(); it != archived.end(); ++it) {
+    const RemoteSuggestion& suggestion = **it;
+    if (suggestion.is_dismissed()) {
+      request_params->excluded_ids.insert(suggestion.id());
+    }
+  }
+}
+
 }  // namespace
 
 RemoteSuggestionsProviderImpl::RemoteSuggestionsProviderImpl(
@@ -494,14 +509,17 @@
   // added first to truncate them less.
   if (fetched_category.has_value()) {
     DCHECK(category_contents_.count(*fetched_category));
-    AddDismissedIdsToRequest(
-        category_contents_.find(*fetched_category)->second.dismissed, &result);
+    const CategoryContent& content =
+        category_contents_.find(*fetched_category)->second;
+    AddDismissedIdsToRequest(content.dismissed, &result);
+    AddDismissedArchivedIdsToRequest(content.archived, &result);
   }
   for (const auto& map_entry : category_contents_) {
     if (fetched_category.has_value() && map_entry.first == *fetched_category) {
       continue;
     }
     AddDismissedIdsToRequest(map_entry.second.dismissed, &result);
+    AddDismissedArchivedIdsToRequest(map_entry.second.archived, &result);
   }
   return result;
 }
@@ -606,14 +624,16 @@
     return;
   }
 
-  if (content->dismissed.empty()) {
-    return;
+  if (!content->dismissed.empty()) {
+    database_->DeleteSnippets(GetSuggestionIDVector(content->dismissed));
+    // The image got already deleted when the suggestion was dismissed.
+    content->dismissed.clear();
   }
 
-  database_->DeleteSnippets(GetSuggestionIDVector(content->dismissed));
-  // The image got already deleted when the suggestion was dismissed.
-
-  content->dismissed.clear();
+  // Update the archive.
+  for (const auto& suggestion : content->archived) {
+    suggestion->set_dismissed(false);
+  }
 }
 
 // static
@@ -1038,22 +1058,26 @@
 void RemoteSuggestionsProviderImpl::DismissSuggestionFromCategoryContent(
     CategoryContent* content,
     const std::string& id_within_category) {
-  auto it =
-      std::find_if(content->suggestions.begin(), content->suggestions.end(),
-                   [&id_within_category](
-                       const std::unique_ptr<RemoteSuggestion>& suggestion) {
-                     return suggestion->id() == id_within_category;
-                   });
-  if (it == content->suggestions.end()) {
-    return;
+  auto id_predicate = [&id_within_category](
+                          const std::unique_ptr<RemoteSuggestion>& suggestion) {
+    return suggestion->id() == id_within_category;
+  };
+
+  auto it = std::find_if(content->suggestions.begin(),
+                         content->suggestions.end(), id_predicate);
+  if (it != content->suggestions.end()) {
+    (*it)->set_dismissed(true);
+    database_->SaveSnippet(**it);
+    content->dismissed.push_back(std::move(*it));
+    content->suggestions.erase(it);
+  } else {
+    // Check the archive.
+    auto archive_it = std::find_if(content->archived.begin(),
+                                   content->archived.end(), id_predicate);
+    if (archive_it != content->archived.end()) {
+      (*archive_it)->set_dismissed(true);
+    }
   }
-
-  (*it)->set_dismissed(true);
-
-  database_->SaveSnippet(**it);
-
-  content->dismissed.push_back(std::move(*it));
-  content->suggestions.erase(it);
 }
 
 void RemoteSuggestionsProviderImpl::DeleteCategories(
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
index 804b8bd..ae50314c 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
@@ -489,7 +489,7 @@
   MockScheduler* scheduler() { return scheduler_.get(); }
   FakeBreakingNewsListener* fake_breaking_news_listener() {
     return fake_breaking_news_listener_;
-  };
+  }
 
   void FetchTheseSuggestions(
       RemoteSuggestionsProviderImpl* provider,
@@ -2435,6 +2435,105 @@
 }
 
 TEST_F(RemoteSuggestionsProviderImplTest,
+       ShouldExcludeDismissedFetchedMoreSuggestions) {
+  // This tests verifies that dismissing an article seen in the fetch-more state
+  // (i.e., an article that has been fetched via fetch-more) will be excluded in
+  // future fetches.
+  auto provider = MakeSuggestionsProvider(
+      /*use_mock_prefetched_pages_tracker=*/false,
+      /*use_fake_breaking_news_listener=*/false,
+      /*use_mock_remote_suggestions_status_service=*/false);
+
+  FetchedCategoryBuilder category_builder;
+  category_builder.SetCategory(articles_category());
+  const int kSuggestionsCount = 5;
+  for (int i = 0; i < kSuggestionsCount; ++i) {
+    category_builder.AddSuggestionViaBuilder(RemoteSuggestionBuilder().AddId(
+        base::StringPrintf("http://abc.com/%d", i)));
+  }
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(category_builder.Build());
+
+  FetchMoreTheseSuggestions(
+      provider.get(), articles_category(),
+      /*known_suggestion_ids=*/std::set<std::string>(),
+      /*fetch_done_callback=*/
+      base::Bind([](Status status, std::vector<ContentSuggestion> suggestions) {
+        ASSERT_THAT(suggestions, SizeIs(5));
+      }),
+      Status::Success(), std::move(fetched_categories));
+
+  // Dismiss them.
+  for (int i = 0; i < kSuggestionsCount; ++i) {
+    provider->DismissSuggestion(
+        MakeArticleID(base::StringPrintf("http://abc.com/%d", i)));
+  }
+
+  EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
+      .WillOnce(Return(true))
+      .RetiresOnSaturation();
+  EXPECT_CALL(
+      *mock_suggestions_fetcher(),
+      FetchSnippets(Field(&RequestParams::excluded_ids,
+                          ElementsAre("http://abc.com/0", "http://abc.com/1",
+                                      "http://abc.com/2", "http://abc.com/3",
+                                      "http://abc.com/4")),
+                    _));
+  provider->Fetch(
+      articles_category(), std::set<std::string>(),
+      base::Bind([](Status status_code,
+                    std::vector<ContentSuggestion> suggestions) {}));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest, ClearDismissedAfterFetchMore) {
+  auto provider = MakeSuggestionsProvider(
+      /*use_mock_prefetched_pages_tracker=*/false,
+      /*use_fake_breaking_news_listener=*/false,
+      /*use_mock_remote_suggestions_status_service=*/false);
+  FetchedCategoryBuilder category_builder;
+  category_builder.SetCategory(articles_category());
+  category_builder.AddSuggestionViaBuilder(
+      RemoteSuggestionBuilder().AddId(base::StringPrintf("http://abc.com")));
+  std::vector<FetchedCategory> fetched_categories;
+  fetched_categories.push_back(category_builder.Build());
+
+  FetchMoreTheseSuggestions(
+      provider.get(), articles_category(),
+      /*known_suggestion_ids=*/std::set<std::string>(),
+      /*fetch_done_callback=*/
+      base::Bind(
+          [](Status status, std::vector<ContentSuggestion> suggestions) {}),
+      Status::Success(), std::move(fetched_categories));
+
+  provider->DismissSuggestion(MakeArticleID("http://abc.com"));
+
+  EXPECT_CALL(*scheduler(), AcquireQuotaForInteractiveFetch())
+      .WillRepeatedly(Return(true));
+
+  // Make sure the article got marked as dismissed.
+  InSequence s;
+  EXPECT_CALL(*mock_suggestions_fetcher(),
+              FetchSnippets(Field(&RequestParams::excluded_ids,
+                                  ElementsAre("http://abc.com")),
+                            _));
+  provider->Fetch(
+      articles_category(), std::set<std::string>(),
+      base::Bind([](Status status_code,
+                    std::vector<ContentSuggestion> suggestions) {}));
+
+  // Clear dismissals.
+  provider->ClearDismissedSuggestionsForDebugging(articles_category());
+
+  // Fetch and verify the article is not marked as dismissed anymore.
+  EXPECT_CALL(*mock_suggestions_fetcher(),
+              FetchSnippets(Field(&RequestParams::excluded_ids, IsEmpty()), _));
+  provider->Fetch(
+      articles_category(), std::set<std::string>(),
+      base::Bind([](Status status_code,
+                    std::vector<ContentSuggestion> suggestions) {}));
+}
+
+TEST_F(RemoteSuggestionsProviderImplTest,
        ShouldExcludeDismissedSuggestionsFromAllCategoriesWhenFetchingMore) {
   auto provider = MakeSuggestionsProvider(
       /*use_mock_prefetched_pages_tracker=*/false,
@@ -2797,9 +2896,8 @@
                    MakeArticleID("http://prefetched.com/1"))));
 }
 
-TEST_F(
-    RemoteSuggestionsProviderImplTest,
-    ShouldKeepMostRecentlyFetchedPrefetchedSuggestionsFirstAfterFetchWhenEnabled) {
+TEST_F(RemoteSuggestionsProviderImplTest,
+       KeepMostRecentlyFetchedPrefetchedSuggestionsFirstAfterFetchWhenEnabled) {
   EnableKeepingPrefetchedContentSuggestions(
       kMaxAdditionalPrefetchedSuggestions,
       kMaxAgeForAdditionalPrefetchedSuggestion);
diff --git a/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc b/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc
index 343ab5f..49f953c 100644
--- a/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/add_unique_urls_task_unittest.cc
@@ -16,6 +16,7 @@
 #include "components/offline_pages/core/prefetch/prefetch_types.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
 #include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -36,49 +37,21 @@
 const base::string16 kTestTitle4 = base::ASCIIToUTF16("Title 4");
 }  // namespace
 
-class AddUniqueUrlsTaskTest : public testing::Test {
+class AddUniqueUrlsTaskTest : public TaskTestBase {
  public:
   AddUniqueUrlsTaskTest();
   ~AddUniqueUrlsTaskTest() override = default;
 
-  void SetUp() override;
-  void TearDown() override;
-
-  PrefetchStore* store() { return store_test_util_.store(); }
-
-  PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
-
-  void PumpLoop();
-
   // Returns all items stored in a map keyed with client id.
   std::map<std::string, PrefetchItem> GetAllItems();
 
   TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
 
  private:
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  base::ThreadTaskRunnerHandle task_runner_handle_;
-  PrefetchStoreTestUtil store_test_util_;
   TestPrefetchDispatcher dispatcher_;
 };
 
-AddUniqueUrlsTaskTest::AddUniqueUrlsTaskTest()
-    : task_runner_(new base::TestSimpleTaskRunner),
-      task_runner_handle_(task_runner_),
-      store_test_util_(task_runner_) {}
-
-void AddUniqueUrlsTaskTest::SetUp() {
-  store_test_util_.BuildStoreInMemory();
-}
-
-void AddUniqueUrlsTaskTest::TearDown() {
-  store_test_util_.DeleteStore();
-  PumpLoop();
-}
-
-void AddUniqueUrlsTaskTest::PumpLoop() {
-  task_runner_->RunUntilIdle();
-}
+AddUniqueUrlsTaskTest::AddUniqueUrlsTaskTest() {}
 
 std::map<std::string, PrefetchItem> AddUniqueUrlsTaskTest::GetAllItems() {
   std::set<PrefetchItem> set;
@@ -90,13 +63,23 @@
   return map;
 }
 
+TEST_F(AddUniqueUrlsTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  AddUniqueUrlsTask task(dispatcher(), store(), kTestNamespace, {});
+  ExpectTaskCompletes(&task);
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(AddUniqueUrlsTaskTest, AddTaskInEmptyStore) {
   std::vector<PrefetchURL> urls;
   urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
   urls.push_back(PrefetchURL{kClientId2, kTestURL2, kTestTitle2});
   AddUniqueUrlsTask task(dispatcher(), store(), kTestNamespace, urls);
+  ExpectTaskCompletes(&task);
   task.Run();
-  PumpLoop();
+  RunUntilIdle();
 
   std::map<std::string, PrefetchItem> items = GetAllItems();
   ASSERT_EQ(2u, items.size());
@@ -116,20 +99,23 @@
   std::vector<PrefetchURL> urls;
   urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
   AddUniqueUrlsTask task1(dispatcher(), store(), kTestNamespace, urls);
+  ExpectTaskCompletes(&task1);
   task1.Run();
-  PumpLoop();
+  RunUntilIdle();
   EXPECT_EQ(1, dispatcher()->task_schedule_count);
 
   // AddUniqueUrlsTask with no URLs should not increment task schedule count.
   AddUniqueUrlsTask task2(dispatcher(), store(), kTestNamespace, {});
+  ExpectTaskCompletes(&task2);
   task2.Run();
-  PumpLoop();
+  RunUntilIdle();
   // The task schedule count should not have changed with no new URLs.
   EXPECT_EQ(1, dispatcher()->task_schedule_count);
 
   AddUniqueUrlsTask task3(dispatcher(), store(), kTestNamespace, urls);
+  ExpectTaskCompletes(&task3);
   task3.Run();
-  PumpLoop();
+  RunUntilIdle();
   // The task schedule count should not have changed with no new URLs.
   EXPECT_EQ(1, dispatcher()->task_schedule_count);
 }
@@ -139,8 +125,9 @@
   urls.push_back(PrefetchURL{kClientId1, kTestURL1, kTestTitle1});
   urls.push_back(PrefetchURL{kClientId2, kTestURL2, kTestTitle2});
   AddUniqueUrlsTask task1(dispatcher(), store(), kTestNamespace, urls);
+  ExpectTaskCompletes(&task1);
   task1.Run();
-  PumpLoop();
+  RunUntilIdle();
   EXPECT_EQ(1, dispatcher()->task_schedule_count);
 
   urls.clear();
@@ -149,8 +136,9 @@
   urls.push_back(PrefetchURL{kClientId3, kTestURL3, kTestTitle3});
 
   AddUniqueUrlsTask task2(dispatcher(), store(), kTestNamespace, urls);
+  ExpectTaskCompletes(&task2);
   task2.Run();
-  PumpLoop();
+  RunUntilIdle();
   EXPECT_EQ(2, dispatcher()->task_schedule_count);
 
   std::map<std::string, PrefetchItem> items = GetAllItems();
@@ -175,8 +163,9 @@
   urls.push_back(PrefetchURL{kClientId2, kTestURL2, kTestTitle2});
   urls.push_back(PrefetchURL{kClientId3, kTestURL3, kTestTitle3});
   AddUniqueUrlsTask task1(dispatcher(), store(), kTestNamespace, urls);
+  ExpectTaskCompletes(&task1);
   task1.Run();
-  PumpLoop();
+  RunUntilIdle();
   EXPECT_EQ(1, dispatcher()->task_schedule_count);
 
   // ZombifyPrefetchItem returns the number of affected items.
@@ -192,8 +181,9 @@
   // ID-3 is still requested, so it is ignored.
   // ID-4 is added.
   AddUniqueUrlsTask task2(dispatcher(), store(), kTestNamespace, urls);
+  ExpectTaskCompletes(&task2);
   task2.Run();
-  PumpLoop();
+  RunUntilIdle();
   EXPECT_EQ(2, dispatcher()->task_schedule_count);
 
   std::map<std::string, PrefetchItem> items = GetAllItems();
diff --git a/components/offline_pages/core/prefetch/download_archives_task.cc b/components/offline_pages/core/prefetch/download_archives_task.cc
index ec27ad8..cfc03b3 100644
--- a/components/offline_pages/core/prefetch/download_archives_task.cc
+++ b/components/offline_pages/core/prefetch/download_archives_task.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/guid.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "components/offline_pages/core/offline_time_utils.h"
@@ -22,15 +23,10 @@
 
 namespace {
 
-struct ItemReadyForDownload {
-  int64_t offline_id;
-  std::string archive_body_name;
-  int64_t archive_body_length;
-};
+using DownloadItem = DownloadArchivesTask::DownloadItem;
+using ItemsToDownload = DownloadArchivesTask::ItemsToDownload;
 
-using ItemsReadyForDownload = std::vector<ItemReadyForDownload>;
-
-ItemsReadyForDownload FindItemsReadyForDownload(sql::Connection* db) {
+ItemsToDownload FindItemsReadyForDownload(sql::Connection* db) {
   static const char kSql[] =
       "SELECT offline_id, archive_body_name, archive_body_length"
       " FROM prefetch_items"
@@ -39,11 +35,11 @@
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
   statement.BindInt(0, static_cast<int>(PrefetchItemState::RECEIVED_BUNDLE));
 
-  ItemsReadyForDownload items_to_download;
+  ItemsToDownload items_to_download;
   while (statement.Step()) {
     items_to_download.push_back({statement.ColumnInt64(0),
                                  statement.ColumnString(1),
-                                 statement.ColumnInt64(2)});
+                                 statement.ColumnInt64(2), std::string()});
   }
 
   return items_to_download;
@@ -81,8 +77,8 @@
   return statement.Run();
 }
 
-std::unique_ptr<DownloadArchivesTask::ItemsToDownload>
-SelectAndMarkItemsForDownloadSync(sql::Connection* db) {
+std::unique_ptr<ItemsToDownload> SelectAndMarkItemsForDownloadSync(
+    sql::Connection* db) {
   if (!db)
     return nullptr;
 
@@ -109,16 +105,15 @@
   if (available_quota <= 0)
     return nullptr;
 
-  ItemsReadyForDownload ready_items = FindItemsReadyForDownload(db);
+  ItemsToDownload ready_items = FindItemsReadyForDownload(db);
   if (ready_items.empty())
     return nullptr;
 
   // Below implementation is a greedy algorithm that selects the next item we
   // can download without quota violation and maximum concurrent downloads
   // violation, as ordered by the |FindItemsReadyForDownload| function.
-  auto items_to_download =
-      base::MakeUnique<DownloadArchivesTask::ItemsToDownload>();
-  for (const auto& ready_item : ready_items) {
+  auto items_to_download = base::MakeUnique<ItemsToDownload>();
+  for (auto& ready_item : ready_items) {
     // Concurrent downloads check.
     if (*concurrent_downloads >= DownloadArchivesTask::kMaxConcurrentDownloads)
       break;
@@ -133,7 +128,8 @@
     std::string guid = base::GenerateGUID();
     if (!MarkItemAsDownloading(db, ready_item.offline_id, guid))
       return nullptr;
-    items_to_download->push_back({guid, ready_item.archive_body_name});
+    ready_item.guid = guid;
+    items_to_download->emplace_back(ready_item);
     ++(*concurrent_downloads);
   }
 
@@ -177,6 +173,10 @@
     for (const auto& download_item : *items_to_download) {
       prefetch_downloader_->StartDownload(download_item.guid,
                                           download_item.archive_body_name);
+      // Reports expected archive size in KiB (accepting values up to 100 MiB).
+      UMA_HISTOGRAM_COUNTS_100000(
+          "OfflinePages.Prefetching.DownloadExpectedFileSize",
+          download_item.archive_body_length / 1024);
     }
   }
 
diff --git a/components/offline_pages/core/prefetch/download_archives_task.h b/components/offline_pages/core/prefetch/download_archives_task.h
index 4f15535..6efc0f9 100644
--- a/components/offline_pages/core/prefetch/download_archives_task.h
+++ b/components/offline_pages/core/prefetch/download_archives_task.h
@@ -26,12 +26,12 @@
 
   // Represents item to be downloaded as a result of running the task.
   struct DownloadItem {
-    std::string guid;
+    int64_t offline_id;
     std::string archive_body_name;
+    int64_t archive_body_length;
+    std::string guid;
   };
 
-  // Result of lookup of items ready to be downloaded. First element of the pair
-  // is offline ID, second is archive body name.
   using ItemsToDownload = std::vector<DownloadItem>;
 
   DownloadArchivesTask(PrefetchStore* prefetch_store,
diff --git a/components/offline_pages/core/prefetch/download_archives_task_unittest.cc b/components/offline_pages/core/prefetch/download_archives_task_unittest.cc
index 5a039d2..97ea4de 100644
--- a/components/offline_pages/core/prefetch/download_archives_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/download_archives_task_unittest.cc
@@ -8,6 +8,7 @@
 #include <set>
 
 #include "base/guid.h"
+#include "base/test/histogram_tester.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_downloader_quota.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
@@ -68,6 +69,14 @@
   return item.offline_id;
 }
 
+TEST_F(DownloadArchivesTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+  DownloadArchivesTask task(store(), prefetch_downloader());
+  ExpectTaskCompletes(&task);
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(DownloadArchivesTaskTest, NoArchivesToDownload) {
   InsertDummyItemInState(PrefetchItemState::NEW_REQUEST);
   InsertDummyItemInState(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
@@ -84,6 +93,7 @@
   EXPECT_EQ(10U, store_util()->GetAllItems(&items_before_run));
 
   DownloadArchivesTask task(store(), prefetch_downloader());
+  base::HistogramTester histogram_tester;
   ExpectTaskCompletes(&task);
   task.Run();
   RunUntilIdle();
@@ -92,6 +102,9 @@
   EXPECT_EQ(10U, store_util()->GetAllItems(&items_after_run));
 
   EXPECT_EQ(items_before_run, items_after_run);
+
+  histogram_tester.ExpectTotalCount(
+      "OfflinePages.Prefetching.DownloadExpectedFileSize", 0);
 }
 
 TEST_F(DownloadArchivesTaskTest, SingleArchiveToDownload) {
@@ -102,6 +115,7 @@
   EXPECT_EQ(2U, store_util()->GetAllItems(&items_before_run));
 
   DownloadArchivesTask task(store(), prefetch_downloader());
+  base::HistogramTester histogram_tester;
   ExpectTaskCompletes(&task);
   task.Run();
   RunUntilIdle();
@@ -136,6 +150,10 @@
   auto it = requested_downloads.find(download_item->guid);
   ASSERT_TRUE(it != requested_downloads.end());
   EXPECT_EQ(it->second, download_item->archive_body_name);
+
+  histogram_tester.ExpectUniqueSample(
+      "OfflinePages.Prefetching.DownloadExpectedFileSize",
+      kLargeArchiveSize / 1024, 1);
 }
 
 TEST_F(DownloadArchivesTaskTest, MultipleArchivesToDownload) {
@@ -147,6 +165,7 @@
   EXPECT_EQ(3U, store_util()->GetAllItems(&items_before_run));
 
   DownloadArchivesTask task(store(), prefetch_downloader());
+  base::HistogramTester histogram_tester;
   ExpectTaskCompletes(&task);
   task.Run();
   RunUntilIdle();
@@ -183,6 +202,10 @@
   it = requested_downloads.find(download_item_2->guid);
   ASSERT_TRUE(it != requested_downloads.end());
   EXPECT_EQ(it->second, download_item_2->archive_body_name);
+
+  histogram_tester.ExpectUniqueSample(
+      "OfflinePages.Prefetching.DownloadExpectedFileSize",
+      kSmallArchiveSize / 1024, 2);
 }
 
 TEST_F(DownloadArchivesTaskTest, MultipleLargeArchivesToDownload) {
@@ -195,6 +218,7 @@
   EXPECT_EQ(3U, store_util()->GetAllItems(&items_before_run));
 
   DownloadArchivesTask task(store(), prefetch_downloader());
+  base::HistogramTester histogram_tester;
   ExpectTaskCompletes(&task);
   task.Run();
   RunUntilIdle();
@@ -227,6 +251,10 @@
   auto it = requested_downloads.find(download_item_1->guid);
   ASSERT_TRUE(it != requested_downloads.end());
   EXPECT_EQ(it->second, download_item_1->archive_body_name);
+
+  histogram_tester.ExpectUniqueSample(
+      "OfflinePages.Prefetching.DownloadExpectedFileSize",
+      kLargeArchiveSize / 1024, 1);
 }
 
 TEST_F(DownloadArchivesTaskTest, TooManyArchivesToDownload) {
@@ -243,6 +271,7 @@
             store_util()->GetAllItems(&items_before_run));
 
   DownloadArchivesTask task(store(), prefetch_downloader());
+  base::HistogramTester histogram_tester;
   ExpectTaskCompletes(&task);
   task.Run();
   RunUntilIdle();
@@ -280,6 +309,10 @@
     EXPECT_EQ(*download_item_before, *download_item_before);
     EXPECT_EQ(PrefetchItemState::RECEIVED_BUNDLE, download_item_after->state);
   }
+
+  histogram_tester.ExpectUniqueSample(
+      "OfflinePages.Prefetching.DownloadExpectedFileSize",
+      kSmallArchiveSize / 1024, 2);
 }
 
 TEST_F(DownloadArchivesTaskTest, SingleArchiveSecondAttempt) {
@@ -294,6 +327,7 @@
   EXPECT_EQ(1U, store_util()->GetAllItems(&items_before_run));
 
   DownloadArchivesTask task(store(), prefetch_downloader());
+  base::HistogramTester histogram_tester;
   ExpectTaskCompletes(&task);
   task.Run();
   RunUntilIdle();
@@ -317,6 +351,10 @@
   auto it = requested_downloads.find(download_item->guid);
   ASSERT_TRUE(it != requested_downloads.end());
   EXPECT_EQ(it->second, download_item->archive_body_name);
+
+  histogram_tester.ExpectUniqueSample(
+      "OfflinePages.Prefetching.DownloadExpectedFileSize",
+      item.archive_body_length / 1024, 1);
 }
 
 }  // namespace
diff --git a/components/offline_pages/core/prefetch/download_cleanup_task.cc b/components/offline_pages/core/prefetch/download_cleanup_task.cc
index 55a7656a..5ebb844 100644
--- a/components/offline_pages/core/prefetch/download_cleanup_task.cc
+++ b/components/offline_pages/core/prefetch/download_cleanup_task.cc
@@ -98,6 +98,7 @@
   if (!transaction.Begin())
     return false;
 
+  // TODO(carlosk): add UMA to track any extraordinary conditions detected here.
   std::vector<DownloadInfo> outstanding_prefetch_downloads =
       GetAllOutstandingDownloadsSync(db);
   if (outstanding_prefetch_downloads.empty())
diff --git a/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc b/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc
index bfb22d2..9b6127a7 100644
--- a/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/download_cleanup_task_unittest.cc
@@ -50,6 +50,12 @@
   TestPrefetchDispatcher dispatcher_;
 };
 
+TEST_F(DownloadCleanupTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  CreateAndRunDownloadCleanupTask(std::string(), std::string());
+}
+
 TEST_F(DownloadCleanupTaskTest, Retry) {
   PrefetchItem item =
       item_generator()->CreateItem(PrefetchItemState::DOWNLOADING);
diff --git a/components/offline_pages/core/prefetch/download_completed_task.cc b/components/offline_pages/core/prefetch/download_completed_task.cc
index 1c578e574..9def8f4 100644
--- a/components/offline_pages/core/prefetch/download_completed_task.cc
+++ b/components/offline_pages/core/prefetch/download_completed_task.cc
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
 #include "components/offline_pages/core/prefetch/prefetch_types.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store.h"
@@ -22,6 +23,9 @@
                                              const base::FilePath& file_path,
                                              int64_t file_size,
                                              sql::Connection* db) {
+  if (!db)
+    return false;
+
   static const char kSql[] =
       "UPDATE prefetch_items"
       " SET state = ?, file_path = ?, file_size = ?"
@@ -39,6 +43,9 @@
 
 bool UpdatePrefetchItemOnDownloadErrorSync(const std::string& guid,
                                            sql::Connection* db) {
+  if (!db)
+    return false;
+
   static const char kSql[] =
       "UPDATE prefetch_items"
       " SET state = ?, error_code = ?"
@@ -70,6 +77,9 @@
 
 void DownloadCompletedTask::Run() {
   if (download_result_.success) {
+    // Reports downloaded file size in KiB (accepting values up to 100 MiB).
+    UMA_HISTOGRAM_COUNTS_100000("OfflinePages.Prefetching.DownloadedFileSize",
+                                download_result_.file_size / 1024);
     prefetch_store_->Execute(
         base::BindOnce(&UpdatePrefetchItemOnDownloadSuccessSync,
                        download_result_.download_id, download_result_.file_path,
diff --git a/components/offline_pages/core/prefetch/download_completed_task.h b/components/offline_pages/core/prefetch/download_completed_task.h
index 118713c..b0973cd 100644
--- a/components/offline_pages/core/prefetch/download_completed_task.h
+++ b/components/offline_pages/core/prefetch/download_completed_task.h
@@ -25,7 +25,7 @@
   void Run() override;
 
  private:
-  void OnPrefetchItemUpdated(bool success);
+  void OnPrefetchItemUpdated(bool row_was_updated);
 
   PrefetchDispatcher* prefetch_dispatcher_;  // Outlives this class.
   PrefetchStore* prefetch_store_;  // Outlives this class.
diff --git a/components/offline_pages/core/prefetch/download_completed_task_unittest.cc b/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
index 06a94319..d2e415e 100644
--- a/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/download_completed_task_unittest.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "base/test/histogram_tester.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -31,6 +32,8 @@
 const int64_t kTestFileSize = 88888;
 }  // namespace
 
+// TODO(carlosk, jianli): Update this test to extend and use the functionality
+// provided by TaskTestBase.
 class DownloadCompletedTaskTest : public testing::Test {
  public:
   DownloadCompletedTaskTest();
@@ -44,12 +47,14 @@
   PrefetchStore* store() { return store_test_util_.store(); }
   TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
   PrefetchStoreTestUtil* store_util() { return &store_test_util_; }
+  base::HistogramTester* histogram_tester() { return histogram_tester_.get(); }
 
  private:
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   base::ThreadTaskRunnerHandle task_runner_handle_;
   TestPrefetchDispatcher dispatcher_;
   PrefetchStoreTestUtil store_test_util_;
+  std::unique_ptr<base::HistogramTester> histogram_tester_;
 };
 
 DownloadCompletedTaskTest::DownloadCompletedTaskTest()
@@ -75,6 +80,8 @@
   item2.creation_time = base::Time::Now();
   item2.freshness_time = item.creation_time;
   EXPECT_TRUE(store_test_util_.InsertPrefetchItem(item2));
+
+  histogram_tester_.reset(new base::HistogramTester());
 }
 
 void DownloadCompletedTaskTest::TearDown() {
@@ -86,6 +93,16 @@
   task_runner_->RunUntilIdle();
 }
 
+TEST_F(DownloadCompletedTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  PrefetchDownloadResult download_result(kTestGUID, kTestFilePath,
+                                         kTestFileSize);
+  DownloadCompletedTask task(dispatcher(), store(), download_result);
+  task.Run();
+  PumpLoop();
+}
+
 TEST_F(DownloadCompletedTaskTest, UpdateItemOnDownloadSuccess) {
   PrefetchDownloadResult download_result(kTestGUID, kTestFilePath,
                                          kTestFileSize);
@@ -99,6 +116,9 @@
   EXPECT_EQ(kTestGUID, item->guid);
   EXPECT_EQ(kTestFilePath, item->file_path);
   EXPECT_EQ(kTestFileSize, item->file_size);
+
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.Prefetching.DownloadedFileSize", kTestFileSize / 1024, 1);
 }
 
 TEST_F(DownloadCompletedTaskTest, UpdateItemOnDownloadError) {
@@ -116,6 +136,9 @@
   EXPECT_EQ(kTestGUID, item->guid);
   EXPECT_TRUE(item->file_path.empty());
   EXPECT_EQ(-1, item->file_size);
+
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.Prefetching.DownloadedFileSize", 0);
 }
 
 TEST_F(DownloadCompletedTaskTest, NoUpdateOnMismatchedDownloadSuccess) {
@@ -133,6 +156,9 @@
   std::unique_ptr<PrefetchItem> item2 =
       store_util()->GetPrefetchItem(kTestOfflineID2);
   EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
+
+  histogram_tester()->ExpectUniqueSample(
+      "OfflinePages.Prefetching.DownloadedFileSize", kTestFileSize / 1024, 1);
 }
 
 TEST_F(DownloadCompletedTaskTest, NoUpdateOnMismatchedDownloadError) {
@@ -151,6 +177,9 @@
   std::unique_ptr<PrefetchItem> item2 =
       store_util()->GetPrefetchItem(kTestOfflineID2);
   EXPECT_EQ(PrefetchItemState::NEW_REQUEST, item2->state);
+
+  histogram_tester()->ExpectTotalCount(
+      "OfflinePages.Prefetching.DownloadedFileSize", 0);
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc b/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc
index 2673302..1102924c 100644
--- a/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/generate_page_bundle_reconcile_task_unittest.cc
@@ -83,6 +83,15 @@
   return item;
 }
 
+TEST_F(GeneratePageBundleReconcileTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  GeneratePageBundleReconcileTask task(store(), request_factory());
+  ExpectTaskCompletes(&task);
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(GeneratePageBundleReconcileTaskTest, Retry) {
   PrefetchItem item = item_generator()->CreateItem(
       PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE);
@@ -185,4 +194,4 @@
   EXPECT_EQ(items, store_items);
 }
 
-}  // namespace offline_pages
\ No newline at end of file
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc b/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
index f2b8714..6240c4e 100644
--- a/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
@@ -37,6 +37,17 @@
   TestPrefetchGCMHandler gcm_handler_;
 };
 
+TEST_F(GeneratePageBundleTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  base::MockCallback<PrefetchRequestFinishedCallback> callback;
+  GeneratePageBundleTask task(store(), gcm_handler(),
+                              prefetch_request_factory(), callback.Get());
+  ExpectTaskCompletes(&task);
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(GeneratePageBundleTaskTest, EmptyTask) {
   base::MockCallback<PrefetchRequestFinishedCallback> callback;
   GeneratePageBundleTask task(store(), gcm_handler(),
diff --git a/components/offline_pages/core/prefetch/get_operation_task_unittest.cc b/components/offline_pages/core/prefetch/get_operation_task_unittest.cc
index 0e340a8..fbebad5 100644
--- a/components/offline_pages/core/prefetch/get_operation_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/get_operation_task_unittest.cc
@@ -34,6 +34,16 @@
   ~GetOperationTaskTest() override = default;
 };
 
+TEST_F(GetOperationTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+  base::MockCallback<PrefetchRequestFinishedCallback> callback;
+
+  GetOperationTask task(store(), prefetch_request_factory(), callback.Get());
+  ExpectTaskCompletes(&task);
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(GetOperationTaskTest, NormalOperationTask) {
   base::MockCallback<PrefetchRequestFinishedCallback> callback;
   int64_t id = InsertPrefetchItemInStateWithOperation(
diff --git a/components/offline_pages/core/prefetch/import_archives_task.cc b/components/offline_pages/core/prefetch/import_archives_task.cc
index 253c80e8..0f1f7bdc 100644
--- a/components/offline_pages/core/prefetch/import_archives_task.cc
+++ b/components/offline_pages/core/prefetch/import_archives_task.cc
@@ -64,6 +64,9 @@
 
 std::unique_ptr<std::vector<PrefetchArchiveInfo>>
 GetArchivesAndUpdateToImportingStateSync(sql::Connection* db) {
+  if (!db)
+    return nullptr;
+
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return nullptr;
diff --git a/components/offline_pages/core/prefetch/import_archives_task_unittest.cc b/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
index 960975ae..b9733c54 100644
--- a/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/import_archives_task_unittest.cc
@@ -132,6 +132,13 @@
   task_runner_->RunUntilIdle();
 }
 
+TEST_F(ImportArchivesTaskTest, NullConnection) {
+  store_util()->SimulateInitializationError();
+  ImportArchivesTask task(store(), importer());
+  task.Run();
+  PumpLoop();
+}
+
 TEST_F(ImportArchivesTaskTest, Importing) {
   ImportArchivesTask task(store(), importer());
   task.Run();
diff --git a/components/offline_pages/core/prefetch/import_completed_task.cc b/components/offline_pages/core/prefetch/import_completed_task.cc
index 1622b67..be86bc3 100644
--- a/components/offline_pages/core/prefetch/import_completed_task.cc
+++ b/components/offline_pages/core/prefetch/import_completed_task.cc
@@ -20,6 +20,9 @@
 bool UpdateToFinishedStateSync(int64_t offline_id,
                                bool success,
                                sql::Connection* db) {
+  if (!db)
+    return false;
+
   static const char kSql[] =
       "UPDATE prefetch_items"
       " SET state = ?, error_code = ?"
diff --git a/components/offline_pages/core/prefetch/import_completed_task_unittest.cc b/components/offline_pages/core/prefetch/import_completed_task_unittest.cc
index ee77855..4f90db0 100644
--- a/components/offline_pages/core/prefetch/import_completed_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/import_completed_task_unittest.cc
@@ -82,6 +82,14 @@
   task_runner_->RunUntilIdle();
 }
 
+TEST_F(ImportCompletedTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  ImportCompletedTask task(dispatcher(), store(), kTestOfflineID, true);
+  task.Run();
+  PumpLoop();
+}
+
 TEST_F(ImportCompletedTaskTest, ImportSuccess) {
   ImportCompletedTask task(dispatcher(), store(), kTestOfflineID, true);
   task.Run();
diff --git a/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc b/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc
index b32e524e..62ee3a9 100644
--- a/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/mark_operation_done_task_unittest.cc
@@ -58,6 +58,16 @@
   TestPrefetchDispatcher dispatcher_;
 };
 
+TEST_F(MarkOperationDoneTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  MarkOperationDoneTask task(dispatcher(), store(), kOperationName);
+  ExpectTaskCompletes(&task);
+
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(MarkOperationDoneTaskTest, NoOpTask) {
   MarkOperationDoneTask task(dispatcher(), store(), kOperationName);
   ExpectTaskCompletes(&task);
diff --git a/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc b/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc
index ecdf30f..685ea6d 100644
--- a/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/metrics_finalization_task_unittest.cc
@@ -40,6 +40,15 @@
   TaskTestBase::TearDown();
 }
 
+TEST_F(MetricsFinalizationTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  // Execute the metrics task.
+  ExpectTaskCompletes(metrics_finalization_task_.get());
+  metrics_finalization_task_->Run();
+  RunUntilIdle();
+}
+
 // Tests that the task works correctly with an empty database.
 TEST_F(MetricsFinalizationTaskTest, EmptyRun) {
   EXPECT_EQ(0, store_util()->CountPrefetchItems());
diff --git a/components/offline_pages/core/prefetch/page_bundle_update_task.cc b/components/offline_pages/core/prefetch/page_bundle_update_task.cc
index e80240a..d6149831 100644
--- a/components/offline_pages/core/prefetch/page_bundle_update_task.cc
+++ b/components/offline_pages/core/prefetch/page_bundle_update_task.cc
@@ -137,6 +137,9 @@
     const std::string operation_name,
     const std::vector<RenderPageInfo>& pages,
     sql::Connection* db) {
+  if (!db)
+    return false;
+
   sql::Transaction transaction(db);
   if (!transaction.Begin())
     return false;
diff --git a/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc b/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc
index 608ed57..03509354 100644
--- a/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/page_bundle_update_task_unittest.cc
@@ -60,6 +60,15 @@
   int body_name_count_ = 0;
 };
 
+TEST_F(PageBundleUpdateTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+  PageBundleUpdateTask task(store(), &dispatcher, "operation", {});
+  ExpectTaskCompletes(&task);
+
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(PageBundleUpdateTaskTest, EmptyTask) {
   PageBundleUpdateTask task(store(), &dispatcher, "operation", {});
   ExpectTaskCompletes(&task);
diff --git a/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc b/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
index e1495c1..403ce94c 100644
--- a/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
@@ -177,6 +177,10 @@
   prefetch_service_->GetLogger()->RecordActivity(
       "Downloader: Download started, download_id=" + download_id +
       ", result=" + std::to_string(static_cast<int>(result)));
+  // Treat the non-accepted request to start a download as an ordinary failure
+  // to simplify the control flow since this situation should rarely happen. The
+  // Download.Service.Request.StartResult.OfflinePage histogram tracks these
+  // cases and would signal the need to revisit this decision.
   if (result != download::DownloadParams::StartResult::ACCEPTED)
     OnDownloadFailed(download_id);
 }
diff --git a/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc b/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc
index 31f48fc..c1f6a4a 100644
--- a/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/sent_get_operation_cleanup_task_unittest.cc
@@ -64,6 +64,15 @@
   ~SentGetOperationCleanupTaskTest() override = default;
 };
 
+TEST_F(SentGetOperationCleanupTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  SentGetOperationCleanupTask task(store(), prefetch_request_factory());
+  ExpectTaskCompletes(&task);
+  task.Run();
+  RunUntilIdle();
+}
+
 TEST_F(SentGetOperationCleanupTaskTest, Retry) {
   PrefetchItem item =
       item_generator()->CreateItem(PrefetchItemState::SENT_GET_OPERATION);
diff --git a/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc b/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
index 762f76b3..67b4c2c 100644
--- a/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
@@ -77,6 +77,14 @@
   return item;
 }
 
+TEST_F(StaleEntryFinalizerTaskTest, StoreFailure) {
+  store_util()->SimulateInitializationError();
+
+  // Execute the expiration task.
+  ExpectTaskCompletes(stale_finalizer_task_.get());
+  stale_finalizer_task_->Run();
+  RunUntilIdle();
+}
 // Tests that the task works correctly with an empty database.
 TEST_F(StaleEntryFinalizerTaskTest, EmptyRun) {
   std::set<PrefetchItem> no_items;
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store.h b/components/offline_pages/core/prefetch/store/prefetch_store.h
index 713573f..d93a23f 100644
--- a/components/offline_pages/core/prefetch/store/prefetch_store.h
+++ b/components/offline_pages/core/prefetch/store/prefetch_store.h
@@ -95,6 +95,8 @@
   static const char* GetTableCreationSqlForTesting();
 
  private:
+  friend class PrefetchStoreTestUtil;
+
   // Used internally to initialize connection.
   void Initialize(base::OnceClosure pending_command);
 
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
index 8b3f1d2a..dd1fef8 100644
--- a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
+++ b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
@@ -297,4 +297,8 @@
   return result;
 }
 
+void PrefetchStoreTestUtil::SimulateInitializationError() {
+  store_->initialization_status_ = InitializationStatus::FAILURE;
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
index 1070e87..d0d137a 100644
--- a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
+++ b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
@@ -76,6 +76,9 @@
   // Will use |clock_| as time source when writing back quota.
   bool SetPrefetchQuota(int64_t available_quota);
 
+  // Causes the store to behave as if an initialization error occurred.
+  void SimulateInitializationError();
+
   PrefetchStore* store() { return store_.get(); }
 
   base::SimpleTestClock* clock() { return &clock_; }
diff --git a/components/password_manager/core/browser/password_store_consumer.cc b/components/password_manager/core/browser/password_store_consumer.cc
index 15451215..ad703c28 100644
--- a/components/password_manager/core/browser/password_store_consumer.cc
+++ b/components/password_manager/core/browser/password_store_consumer.cc
@@ -17,4 +17,9 @@
 void PasswordStoreConsumer::OnGetSiteStatistics(
     std::vector<InteractionsStats> stats) {}
 
+void PasswordStoreConsumer::CancelAllRequests() {
+  cancelable_task_tracker_.TryCancelAll();
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_consumer.h b/components/password_manager/core/browser/password_store_consumer.h
index 6800919b..19f942f9 100644
--- a/components/password_manager/core/browser/password_store_consumer.h
+++ b/components/password_manager/core/browser/password_store_consumer.h
@@ -48,6 +48,8 @@
 
   bool HasWeakPtrs() const { return weak_ptr_factory_.HasWeakPtrs(); }
 
+  void CancelAllRequests();
+
  protected:
   virtual ~PasswordStoreConsumer();
 
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn
index 0ab9b6a3..fac09fc 100644
--- a/components/payments/core/BUILD.gn
+++ b/components/payments/core/BUILD.gn
@@ -66,8 +66,9 @@
     "//components/link_header_util",
     "//components/pref_registry",
     "//components/strings:components_strings_grit",
-    "//components/ukm",
     "//net",
+    "//services/metrics/public/cpp:metrics_cpp",
+    "//services/metrics/public/cpp:ukm_builders",
     "//third_party/libphonenumber",
     "//third_party/re2",
     "//ui/base",
@@ -139,6 +140,7 @@
     "//components/ukm",
     "//components/ukm:test_support",
     "//net:test_support",
+    "//services/metrics/public/cpp:ukm_builders",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/libaddressinput:test_support",
diff --git a/components/payments/core/address_normalization_manager.cc b/components/payments/core/address_normalization_manager.cc
index 240846b..97f68f06 100644
--- a/components/payments/core/address_normalization_manager.cc
+++ b/components/payments/core/address_normalization_manager.cc
@@ -22,11 +22,6 @@
       address_normalizer_(address_normalizer) {
   DCHECK(autofill::data_util::IsValidCountryCode(default_country_code));
   DCHECK(address_normalizer_);
-
-  // Start loading rules for the default country code. This happens
-  // asynchronously, and will speed up normalization later if the rules for the
-  // address' region have already been loaded.
-  address_normalizer_->LoadRulesForRegion(default_country_code);
 }
 
 AddressNormalizationManager::~AddressNormalizationManager() {}
diff --git a/components/payments/core/journey_logger.cc b/components/payments/core/journey_logger.cc
index 85ed916d..819d36ea 100644
--- a/components/payments/core/journey_logger.cc
+++ b/components/payments/core/journey_logger.cc
@@ -8,18 +8,11 @@
 
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "services/metrics/public/cpp/ukm_entry_builder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 
 namespace payments {
 
-namespace internal {
-extern const char kUKMCheckoutEventsEntryName[] =
-    "PaymentRequest.CheckoutEvents";
-extern const char kUKMCompletionStatusMetricName[] = "CompletionStatus";
-extern const char kUKMEventsMetricName[] = "Events";
-}  // namespace internal
-
 namespace {
 
 // Returns the JourneyLogger histograms name suffix based on the |section| and
@@ -254,12 +247,10 @@
   // Record the Checkout Funnel UKM.
   ukm::SourceId source_id = ukm_recorder_->GetNewSourceID();
   ukm_recorder_->UpdateSourceURL(source_id, url_);
-  std::unique_ptr<ukm::UkmEntryBuilder> builder =
-      ukm_recorder_->GetEntryBuilder(source_id,
-                                     internal::kUKMCheckoutEventsEntryName);
-  builder->AddMetric(internal::kUKMCompletionStatusMetricName,
-                     completion_status);
-  builder->AddMetric(internal::kUKMEventsMetricName, events_);
+  ukm::builders::PaymentRequest_CheckoutEvents(source_id)
+      .SetCompletionStatus(completion_status)
+      .SetEvents(events_)
+      .Record(ukm_recorder_);
 }
 
 bool JourneyLogger::WasPaymentRequestTriggered() {
diff --git a/components/payments/core/journey_logger.h b/components/payments/core/journey_logger.h
index f79e088e32..a7f3b25d 100644
--- a/components/payments/core/journey_logger.h
+++ b/components/payments/core/journey_logger.h
@@ -16,13 +16,6 @@
 
 namespace payments {
 
-namespace internal {
-// Name constants are exposed here so they can be referenced from tests.
-extern const char kUKMCheckoutEventsEntryName[];
-extern const char kUKMCompletionStatusMetricName[];
-extern const char kUKMEventsMetricName[];
-}  // namespace internal
-
 // A class to keep track of different stats during a Payment Request journey. It
 // collects different metrics during the course of the checkout flow, like the
 // number of credit cards that the user added or edited. The metrics will be
diff --git a/components/payments/core/journey_logger_unittest.cc b/components/payments/core/journey_logger_unittest.cc
index 389a2bf7..b8e406e 100644
--- a/components/payments/core/journey_logger_unittest.cc
+++ b/components/payments/core/journey_logger_unittest.cc
@@ -10,6 +10,7 @@
 #include "components/metrics/proto/ukm/entry.pb.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "components/ukm/ukm_source.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -926,6 +927,7 @@
 // the Payment Request.
 TEST(JourneyLoggerTest,
      RecordJourneyStatsHistograms_CheckoutFunnelUkm_UserAborted) {
+  using UkmEntry = ukm::builders::PaymentRequest_CheckoutEvents;
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   char test_url[] = "http://www.google.com/";
 
@@ -953,17 +955,16 @@
   ASSERT_EQ(1U, ukm_recorder.entries_count());
   const ukm::mojom::UkmEntry* entry = ukm_recorder.GetEntry(0);
   EXPECT_EQ(source->id(), entry->source_id);
-  EXPECT_EQ(base::HashMetricName(internal::kUKMCheckoutEventsEntryName),
-            entry->event_hash);
+  EXPECT_EQ(base::HashMetricName(UkmEntry::kEntryName), entry->event_hash);
 
-  const ukm::mojom::UkmMetric* status_metric = ukm::TestUkmRecorder::FindMetric(
-      entry, internal::kUKMCompletionStatusMetricName);
+  const ukm::mojom::UkmMetric* status_metric =
+      ukm::TestUkmRecorder::FindMetric(entry, UkmEntry::kCompletionStatusName);
   ASSERT_NE(nullptr, status_metric);
   EXPECT_EQ(JourneyLogger::COMPLETION_STATUS_USER_ABORTED,
             status_metric->value);
 
   const ukm::mojom::UkmMetric* step_metric =
-      ukm::TestUkmRecorder::FindMetric(entry, internal::kUKMEventsMetricName);
+      ukm::TestUkmRecorder::FindMetric(entry, UkmEntry::kEventsName);
   ASSERT_NE(nullptr, step_metric);
   EXPECT_EQ(JourneyLogger::EVENT_SHOWN | JourneyLogger::EVENT_PAY_CLICKED |
                 JourneyLogger::EVENT_REQUEST_SHIPPING |
@@ -976,6 +977,7 @@
 // completes the Payment Request.
 TEST(JourneyLoggerTest,
      RecordJourneyStatsHistograms_CheckoutFunnelUkm_Completed) {
+  using UkmEntry = ukm::builders::PaymentRequest_CheckoutEvents;
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   char test_url[] = "http://www.google.com/";
 
@@ -1001,16 +1003,15 @@
   ASSERT_EQ(1U, ukm_recorder.entries_count());
   const ukm::mojom::UkmEntry* entry = ukm_recorder.GetEntry(0);
   EXPECT_EQ(source->id(), entry->source_id);
-  EXPECT_EQ(base::HashMetricName(internal::kUKMCheckoutEventsEntryName),
-            entry->event_hash);
+  EXPECT_EQ(base::HashMetricName(UkmEntry::kEntryName), entry->event_hash);
 
-  const ukm::mojom::UkmMetric* status_metric = ukm::TestUkmRecorder::FindMetric(
-      entry, internal::kUKMCompletionStatusMetricName);
+  const ukm::mojom::UkmMetric* status_metric =
+      ukm::TestUkmRecorder::FindMetric(entry, UkmEntry::kCompletionStatusName);
   ASSERT_NE(nullptr, status_metric);
   EXPECT_EQ(JourneyLogger::COMPLETION_STATUS_COMPLETED, status_metric->value);
 
   const ukm::mojom::UkmMetric* step_metric =
-      ukm::TestUkmRecorder::FindMetric(entry, internal::kUKMEventsMetricName);
+      ukm::TestUkmRecorder::FindMetric(entry, UkmEntry::kEventsName);
   ASSERT_NE(nullptr, step_metric);
   EXPECT_EQ(JourneyLogger::EVENT_SHOWN | JourneyLogger::EVENT_REQUEST_SHIPPING |
                 JourneyLogger::EVENT_REQUEST_PAYER_EMAIL |
diff --git a/components/payments/core/payment_manifest_downloader.cc b/components/payments/core/payment_manifest_downloader.cc
index 8d3990f..0a7d6c5 100644
--- a/components/payments/core/payment_manifest_downloader.cc
+++ b/components/payments/core/payment_manifest_downloader.cc
@@ -29,17 +29,25 @@
 GURL ParseResponseHeader(const net::URLFetcher* source) {
   if (source->GetResponseCode() != net::HTTP_OK &&
       source->GetResponseCode() != net::HTTP_NO_CONTENT) {
+    LOG(ERROR) << "Unable to make a HEAD request to " << source->GetURL()
+               << " for payment method manifest.";
     return GURL();
   }
 
   net::HttpResponseHeaders* headers = source->GetResponseHeaders();
-  if (!headers)
+  if (!headers) {
+    LOG(ERROR) << "No HTTP headers found on " << source->GetURL()
+               << " for payment method manifest.";
     return GURL();
+  }
 
   std::string link_header;
   headers->GetNormalizedHeader("link", &link_header);
-  if (link_header.empty())
+  if (link_header.empty()) {
+    LOG(ERROR) << "No HTTP Link headers found on " << source->GetURL()
+               << " for payment method manifest.";
     return GURL();
+  }
 
   std::string payment_method_manifest_url;
   std::unordered_map<std::string, base::Optional<std::string>> params;
@@ -60,13 +68,18 @@
       return source->GetOriginalURL().Resolve(payment_method_manifest_url);
   }
 
+  LOG(ERROR) << "No rel=\"payment-method-manifest\" HTTP Link headers found on "
+             << source->GetURL() << " for payment method manifest.";
   return GURL();
 }
 
 std::string ParseResponseContent(const net::URLFetcher* source) {
   std::string content;
-  if (source->GetResponseCode() != net::HTTP_OK)
+  if (source->GetResponseCode() != net::HTTP_OK) {
+    LOG(ERROR) << "Unable to download " << source->GetURL()
+               << " for payment manifests.";
     return content;
+  }
 
   bool success = source->GetResponseAsString(&content);
   DCHECK(success);  // Whether the fetcher was set to store result as string.
@@ -118,6 +131,7 @@
       InitiateDownload(url, net::URLFetcher::GET,
                        std::move(download->callback));
     } else {
+      LOG(ERROR) << url << " is not a valid payment method manifest URL.";
       std::move(download->callback).Run(std::string());
     }
   } else {
diff --git a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc
index bf1ac856..ecae8236c 100644
--- a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc
+++ b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc
@@ -190,7 +190,7 @@
   // according to delay based on system time. If we have no information about
   // the last refresh based on system time, there's nothing we can do in
   // applying the above logic.
-  if (last_refresh_.is_null())
+  if (last_refresh_.is_null() || !client_->is_registered())
     return;
 
   const base::TimeDelta refresh_delay =
@@ -204,6 +204,11 @@
     RefreshAfter(system_delta.InMilliseconds());
 }
 
+void CloudPolicyRefreshScheduler::set_last_refresh_for_testing(
+    base::Time last_refresh) {
+  last_refresh_ = last_refresh;
+}
+
 void CloudPolicyRefreshScheduler::UpdateLastRefreshFromPolicy() {
   if (!last_refresh_.is_null())
     return;
diff --git a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h
index 7110c94a..90fc956 100644
--- a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h
+++ b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h
@@ -86,6 +86,8 @@
   // Triggered also when the device wakes up.
   void OnIPAddressChanged() override;
 
+  void set_last_refresh_for_testing(base::Time last_refresh);
+
  private:
   // Initializes |last_refresh_| to the policy timestamp from |store_| in case
   // there is policy present that indicates this client is not managed. This
@@ -124,8 +126,7 @@
   // |RefreshNow|).
   bool is_scheduled_for_soon_ = false;
 
-  // The last time a refresh callback completed. Is null in case the client is
-  // not registered.
+  // The last time a policy fetch was attempted or completed.
   base::Time last_refresh_;
 
   // The same |last_refresh_|, but based on TimeTicks. This allows to schedule
diff --git a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc
index 28610833..df47ed0 100644
--- a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc
@@ -70,6 +70,16 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  void EmulateSleepThroughLastRefreshTime(
+      CloudPolicyRefreshScheduler* const scheduler) {
+    // Simulate a sleep of the device by decreasing the wall clock based refresh
+    // timestamp, so that the next refresh time point, calculated from it, turns
+    // out to be earlier than the next refresh time point, calculated from the
+    // ticks count clock.
+    scheduler->set_last_refresh_for_testing(base::Time::NowFromSystemTime() -
+                                            base::TimeDelta::FromDays(1));
+  }
+
   base::TimeDelta GetLastDelay() const {
     if (!task_runner_->HasPendingTask())
       return base::TimeDelta();
@@ -364,6 +374,37 @@
   CheckTiming(kPolicyRefreshRate);
 }
 
+TEST_F(CloudPolicyRefreshSchedulerTest, OnIPAddressChangedUnregistered) {
+  client_.SetDMToken(std::string());
+  std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
+      CreateRefreshScheduler());
+
+  client_.NotifyClientError();
+  EXPECT_FALSE(task_runner_->HasPendingTask());
+
+  EmulateSleepThroughLastRefreshTime(scheduler.get());
+  scheduler->OnIPAddressChanged();
+  EXPECT_FALSE(task_runner_->HasPendingTask());
+}
+// TODO(igorcov): Before sleep in normal flow there's a task pending. When the
+// device wakes up, OnIPAddressChanged is called which should cancel the
+// pending task and queue a new task to run earlier. It is desirable to
+// simulate that flow here.
+TEST_F(CloudPolicyRefreshSchedulerTest, OnIPAddressChangedAfterSleep) {
+  std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
+      CreateRefreshScheduler());
+
+  client_.SetPolicy(dm_protocol::kChromeUserPolicyType, std::string(),
+                    em::PolicyFetchResponse());
+  task_runner_->RunPendingTasks();
+  EXPECT_FALSE(task_runner_->HasPendingTask());
+
+  EmulateSleepThroughLastRefreshTime(scheduler.get());
+  scheduler->OnIPAddressChanged();
+  EXPECT_TRUE(task_runner_->HasPendingTask());
+  task_runner_->ClearPendingTasks();
+}
+
 class CloudPolicyRefreshSchedulerSteadyStateTest
     : public CloudPolicyRefreshSchedulerTest {
  protected:
diff --git a/components/policy/tools/grd_helper.py b/components/policy/tools/grd_helper.py
index 1cc1d8be..3702eb93 100755
--- a/components/policy/tools/grd_helper.py
+++ b/components/policy/tools/grd_helper.py
@@ -24,6 +24,7 @@
   The following options are optional:
     -D <define1> ... -D <defineN>: List of grit defines.
     -E <env1> ... -D <envN>:       List of grit build environment variables.
+    -t <platfrom>:                 Target OS.
 
   Args:
     parser: Option parser (from optparse.OptionParser()).
@@ -33,6 +34,7 @@
   parser.add_option("--grd_strip_path_prefix", dest="grd_strip_path_prefix")
   parser.add_option("-D", action="append", dest="grit_defines", default=[])
   parser.add_option("-E", action="append", dest="grit_build_env", default=[])
+  parser.add_option("-t", dest="target_platform", default=None)
 
 
 def get_grd_outputs(options):
@@ -52,7 +54,8 @@
   sys.path.insert(1, grit_path)
   import grit_info
   outputs = grit_info.Outputs(options.grd_input, grit_defines,
-                              'GRIT_DIR/../gritsettings/resource_ids')
+                              'GRIT_DIR/../gritsettings/resource_ids',
+                              options.target_platform)
 
   # Strip the path prefix from the filenames.
   result = []
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index 2d0599b..ed5681d8 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -315,6 +315,9 @@
   <message name="IDS_POLICY_HIDE_EXPANDED_VALUE" desc="Text for the link that hides the policy value. Used when the policy value is too long to be always visible.">
     Hide value
   </message>
+  <message name="IDS_POLICY_LEARN_MORE" desc="Help text for learn-more link for known chrome policies.">
+    Learn more about <ph name="POLICY_NAME">$1<ex>AllowDinosaurEasterEgg</ex></ph> policy
+  </message>
   <message name="IDS_POLICY_SCOPE_USER" desc="Text displayed in the Applies to column when a policy applies to the current user only.">
     Current user
   </message>
diff --git a/components/prefs/persistent_pref_store.cc b/components/prefs/persistent_pref_store.cc
index 2f933659..9d3a42af 100644
--- a/components/prefs/persistent_pref_store.cc
+++ b/components/prefs/persistent_pref_store.cc
@@ -8,10 +8,6 @@
 
 #include "base/threading/sequenced_task_runner_handle.h"
 
-void PersistentPrefStore::CommitPendingWrite() {
-  CommitPendingWrite(base::OnceClosure());
-}
-
 void PersistentPrefStore::CommitPendingWrite(base::OnceClosure done_callback) {
   // Default behavior for PersistentPrefStore implementation that don't issue
   // disk operations: schedule the callback immediately.
diff --git a/components/prefs/persistent_pref_store.h b/components/prefs/persistent_pref_store.h
index 3be5816..803f50af 100644
--- a/components/prefs/persistent_pref_store.h
+++ b/components/prefs/persistent_pref_store.h
@@ -62,9 +62,6 @@
   // Owns |error_delegate|.
   virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) = 0;
 
-  // Starts an asynchronous attempt to commit pending writes to disk.
-  void CommitPendingWrite();
-
   // Starts an asynchronous attempt to commit pending writes to disk. Posts a
   // task to run |done_callback| on the current sequence when disk operations,
   // if any, are complete (even if they are unsuccessful).
diff --git a/components/prefs/pref_service.cc b/components/prefs/pref_service.cc
index a03daa04..fd1dea3b 100644
--- a/components/prefs/pref_service.cc
+++ b/components/prefs/pref_service.cc
@@ -104,8 +104,12 @@
 }
 
 void PrefService::CommitPendingWrite() {
+  CommitPendingWrite(base::OnceClosure());
+}
+
+void PrefService::CommitPendingWrite(base::OnceClosure done_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  user_pref_store_->CommitPendingWrite();
+  user_pref_store_->CommitPendingWrite(std::move(done_callback));
 }
 
 void PrefService::SchedulePendingLossyWrites() {
diff --git a/components/prefs/pref_service.h b/components/prefs/pref_service.h
index b38cb97cb..5d3b101b 100644
--- a/components/prefs/pref_service.h
+++ b/components/prefs/pref_service.h
@@ -177,6 +177,11 @@
   // immediately (basically, during shutdown).
   void CommitPendingWrite();
 
+  // Lands pending writes to disk. This should only be used if we need to save
+  // immediately. |done_callback| will be invoked when changes have been
+  // written.
+  void CommitPendingWrite(base::OnceClosure done_callback);
+
   // Schedule a write if there is any lossy data pending. Unlike
   // CommitPendingWrite() this does not immediately sync to disk, instead it
   // triggers an eventual write if there is lossy data pending and if there
diff --git a/components/printing/service/pdf_compositor_manifest.json b/components/printing/service/pdf_compositor_manifest.json
index d7914f4..bf095c2 100644
--- a/components/printing/service/pdf_compositor_manifest.json
+++ b/components/printing/service/pdf_compositor_manifest.json
@@ -4,7 +4,7 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
-        "composite": [ "printing::mojom::PdfCompositor" ]
+        "compositor": [ "printing::mojom::PdfCompositor" ]
        },
        "requires": {
          "*": [ "app" ],
diff --git a/components/printing/service/pdf_compositor_service_unittest_manifest.json b/components/printing/service/pdf_compositor_service_unittest_manifest.json
index 262a00fe..02be317 100644
--- a/components/printing/service/pdf_compositor_service_unittest_manifest.json
+++ b/components/printing/service/pdf_compositor_service_unittest_manifest.json
@@ -9,7 +9,7 @@
         ]
       },
       "requires": {
-        "pdf_compositor": [ "composite" ],
+        "pdf_compositor": [ "compositor" ],
         "service_manager": [ "service_manager:service_manager" ]
       }
     }
diff --git a/components/safe_browsing/base_blocking_page.cc b/components/safe_browsing/base_blocking_page.cc
index 6c16975..78de24b 100644
--- a/components/safe_browsing/base_blocking_page.cc
+++ b/components/safe_browsing/base_blocking_page.cc
@@ -291,8 +291,7 @@
       harmful = true;
     } else {
       DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
-             threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING ||
-             threat_type == SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING);
+             threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING);
     }
   }
 
@@ -370,8 +369,7 @@
          threat_type == SB_THREAT_TYPE_URL_MALWARE ||
          threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
          threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING ||
-         threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE ||
-         threat_type == SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING;
+         threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE;
 }
 
 }  // namespace safe_browsing
diff --git a/components/safe_browsing/base_ping_manager.cc b/components/safe_browsing/base_ping_manager.cc
index bb37fcd7..2bff3f32 100644
--- a/components/safe_browsing/base_ping_manager.cc
+++ b/components/safe_browsing/base_ping_manager.cc
@@ -202,9 +202,7 @@
          hit_report.threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
          hit_report.threat_type == SB_THREAT_TYPE_URL_BINARY_MALWARE ||
          hit_report.threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING ||
-         hit_report.threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE ||
-         hit_report.threat_type ==
-             SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING);
+         hit_report.threat_type == SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE);
   std::string url = ProtocolManagerHelper::ComposeUrl(
       url_prefix_, "report", client_name_, version_, std::string(),
       hit_report.extended_reporting_level);
@@ -229,9 +227,6 @@
     case SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE:
       threat_list = "malcsdhit";
       break;
-    case SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING:
-      threat_list = "phishpphit";
-      break;
     default:
       NOTREACHED();
   }
diff --git a/components/safe_browsing/browser/threat_details.cc b/components/safe_browsing/browser/threat_details.cc
index 7f12584..6a977c1 100644
--- a/components/safe_browsing/browser/threat_details.cc
+++ b/components/safe_browsing/browser/threat_details.cc
@@ -83,8 +83,6 @@
       return ClientSafeBrowsingReportRequest::URL_CLIENT_SIDE_PHISHING;
     case SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE:
       return ClientSafeBrowsingReportRequest::URL_CLIENT_SIDE_MALWARE;
-    case SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING:
-      return ClientSafeBrowsingReportRequest::URL_PASSWORD_PROTECTION_PHISHING;
     case SB_THREAT_TYPE_AD_SAMPLE:
       return ClientSafeBrowsingReportRequest::AD_SAMPLE;
     default:  // Gated by SafeBrowsingBlockingPage::ShouldReportThreatDetails.
@@ -507,9 +505,6 @@
     report_->set_type(GetReportTypeFromSBThreatType(resource_.threat_type));
   }
 
-  if (resource_.threat_type == SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING)
-    report_->set_token(resource_.token);
-
   GURL referrer_url;
   NavigationEntry* nav_entry = resource_.GetNavigationEntryForResource();
   if (nav_entry) {
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc
index f929d01..f6675a8 100644
--- a/components/safe_browsing/features.cc
+++ b/components/safe_browsing/features.cc
@@ -45,9 +45,6 @@
 const base::Feature kPasswordFieldOnFocusPinging{
     "PasswordFieldOnFocusPinging", base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kPasswordProtectionInterstitial{
-    "PasswordProtectionInterstitial", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kProtectedPasswordEntryPinging{
     "ProtectedPasswordEntryPinging", base::FEATURE_ENABLED_BY_DEFAULT};
 
@@ -76,7 +73,6 @@
     {&kLocalDatabaseManagerEnabled, true},
     {&kParallelUrlCheck, true},
     {&kPasswordFieldOnFocusPinging, true},
-    {&kPasswordProtectionInterstitial, false},
     {&kProtectedPasswordEntryPinging, true},
     {&kThreatDomDetailsTagAndAttributeFeature, false},
     {&kTriggerThrottlerDailyQuotaFeature, false},
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h
index f4c0bbc..f28407d 100644
--- a/components/safe_browsing/features.h
+++ b/components/safe_browsing/features.h
@@ -26,7 +26,6 @@
 extern const base::Feature kLocalDatabaseManagerEnabled;
 extern const base::Feature kParallelUrlCheck;
 extern const base::Feature kPasswordFieldOnFocusPinging;
-extern const base::Feature kPasswordProtectionInterstitial;
 extern const base::Feature kProtectedPasswordEntryPinging;
 
 // Specifies which non-resource HTML Elements to collect based on their tag and
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index 91b10551..4bb3d303 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -23,7 +23,6 @@
 #include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/safe_browsing_db/database_manager.h"
-#include "components/safe_browsing_db/v4_protocol_manager_util.h"
 #include "components/safe_browsing_db/whitelist_checker_client.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
@@ -149,10 +148,9 @@
   }
 }
 
-void PasswordProtectionService::OnWarningDone(
-    content::WebContents* web_contents,
-    WarningUIType ui_type,
-    WarningAction action) {
+void PasswordProtectionService::OnWarningDone(WebContents* web_contents,
+                                              WarningUIType ui_type,
+                                              WarningAction action) {
   RecordWarningAction(ui_type, action);
   // TODO(jialiul): Need to send post-warning report, trigger event logger and
   // other tasks.
@@ -166,9 +164,8 @@
   }
 }
 
-void PasswordProtectionService::OnWarningShown(
-    content::WebContents* web_contents,
-    WarningUIType ui_type) {
+void PasswordProtectionService::OnWarningShown(WebContents* web_contents,
+                                               WarningUIType ui_type) {
   RecordWarningAction(ui_type, SHOWN);
   // TODO(jialiul): Trigger event logger here.
 }
@@ -434,20 +431,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(request);
 
-  if (response) {
-    if (!already_cached) {
-      CacheVerdict(request->main_frame_url(), request->trigger_type(),
-                   response.get(), base::Time::Now());
-    }
-
-    if (request->trigger_type() ==
-            LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE &&
-        response->verdict_type() == LoginReputationClientResponse::PHISHING &&
-        base::FeatureList::IsEnabled(kPasswordProtectionInterstitial)) {
-      ShowPhishingInterstitial(request->main_frame_url(),
-                               response->verdict_token(),
-                               request->web_contents());
-    }
+  if (response && !already_cached) {
+    CacheVerdict(request->main_frame_url(), request->trigger_type(),
+                 response.get(), base::Time::Now());
   }
 
   // Finished processing this request. Remove it from pending list.
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h
index 2b99a48..b8e0703 100644
--- a/components/safe_browsing/password_protection/password_protection_service.h
+++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -269,10 +269,6 @@
 
   virtual bool IsHistorySyncEnabled() = 0;
 
-  virtual void ShowPhishingInterstitial(const GURL& phishing_url,
-                                        const std::string& token,
-                                        content::WebContents* web_contents) = 0;
-
   // Gets the type of sync account associated with current profile or
   // |NOT_SIGNED_IN|.
   virtual SyncAccountType GetSyncAccountType() = 0;
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index c1e80ae0..81707af 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -121,10 +121,6 @@
       PasswordProtectionService::RequestOutcome,
       const LoginReputationClientResponse*) override {}
 
-  void ShowPhishingInterstitial(const GURL& phishing_url,
-                                const std::string& token,
-                                content::WebContents* web_contents) override {}
-
   bool IsHistorySyncEnabled() override { return false; }
 
   LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.h b/components/safe_browsing_db/v4_protocol_manager_util.h
index 3192e14..03b94ed 100644
--- a/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -123,8 +123,8 @@
   // CSD Phishing whitelist.  This "threat" means a URL matched the whitelist.
   SB_THREAT_TYPE_CSD_WHITELIST,
 
-  // Url detected by password protection service.
-  SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING,
+  // DEPRECATED. Url detected by password protection service.
+  DEPRECATED_SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING,
 
   // Password reuse detected on low reputation page,
   SB_THREAT_TYPE_PASSWORD_REUSE,
diff --git a/components/search_provider_logos/features.cc b/components/search_provider_logos/features.cc
index a5529ba..dc044a8 100644
--- a/components/search_provider_logos/features.cc
+++ b/components/search_provider_logos/features.cc
@@ -13,7 +13,7 @@
 const char kDdljsonOverrideUrlParam[] = "ddljson-override-url";
 
 const base::Feature kThirdPartyDoodles{"ThirdPartyDoodles",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
 const char kThirdPartyDoodlesOverrideUrlParam[] =
     "third-party-doodles-override-url";
diff --git a/components/search_provider_logos/logo_common.h b/components/search_provider_logos/logo_common.h
index 1e368041..a1c050f 100644
--- a/components/search_provider_logos/logo_common.h
+++ b/components/search_provider_logos/logo_common.h
@@ -13,6 +13,7 @@
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/optional.h"
 #include "base/time/time.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
@@ -65,6 +66,8 @@
   // Metadata about the logo.
   LogoMetadata metadata;
 };
+using EncodedLogoCallback =
+    base::OnceCallback<void(const base::Optional<EncodedLogo> logo)>;
 
 struct Logo {
   Logo();
@@ -75,6 +78,7 @@
   // Metadata about the logo.
   LogoMetadata metadata;
 };
+using LogoCallback = base::OnceCallback<void(const base::Optional<Logo> logo)>;
 
 // Parses the response from the server and returns it as an EncodedLogo. Returns
 // null if the response is invalid.
diff --git a/components/search_provider_logos/logo_service.cc b/components/search_provider_logos/logo_service.cc
index 05d3c054..c9711d3 100644
--- a/components/search_provider_logos/logo_service.cc
+++ b/components/search_provider_logos/logo_service.cc
@@ -96,6 +96,59 @@
   DISALLOW_COPY_AND_ASSIGN(LogoDelegateImpl);
 };
 
+class CallbackLogoObserver : public LogoObserver {
+ public:
+  CallbackLogoObserver(LogoCallback on_cached_logo_available,
+                       EncodedLogoCallback on_cached_encoded_logo_available,
+                       LogoCallback on_fresh_logo_available,
+                       EncodedLogoCallback on_fresh_encoded_logo_available)
+      : on_cached_logo_available_(std::move(on_cached_logo_available)),
+        on_cached_encoded_logo_available_(
+            std::move(on_cached_encoded_logo_available)),
+        on_fresh_logo_available_(std::move(on_fresh_logo_available)),
+        on_fresh_encoded_logo_available_(
+            std::move(on_fresh_encoded_logo_available)) {}
+
+  void OnLogoAvailable(const Logo* logo, bool from_cache) override {
+    if (from_cache) {
+      if (on_cached_logo_available_) {
+        std::move(on_cached_logo_available_)
+            .Run(logo ? base::make_optional(*logo) : base::nullopt);
+      }
+    } else {
+      if (on_fresh_logo_available_) {
+        std::move(on_fresh_logo_available_)
+            .Run(logo ? base::make_optional(*logo) : base::nullopt);
+      }
+    }
+  }
+
+  void OnEncodedLogoAvailable(const EncodedLogo* logo,
+                              bool from_cache) override {
+    if (from_cache) {
+      if (on_cached_encoded_logo_available_) {
+        std::move(on_cached_encoded_logo_available_)
+            .Run(logo ? base::make_optional(*logo) : base::nullopt);
+      }
+    } else {
+      if (on_fresh_encoded_logo_available_) {
+        std::move(on_fresh_encoded_logo_available_)
+            .Run(logo ? base::make_optional(*logo) : base::nullopt);
+      }
+    }
+  }
+
+  void OnObserverRemoved() override { delete this; }
+
+ private:
+  LogoCallback on_cached_logo_available_;
+  EncodedLogoCallback on_cached_encoded_logo_available_;
+  LogoCallback on_fresh_logo_available_;
+  EncodedLogoCallback on_fresh_encoded_logo_available_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallbackLogoObserver);
+};
+
 }  // namespace
 
 LogoService::LogoService(
@@ -217,6 +270,22 @@
   logo_tracker_->GetLogo(observer);
 }
 
+void LogoService::GetLogo(LogoCallback on_cached_logo_available,
+                          LogoCallback on_fresh_logo_available) {
+  // CallbackLogoObserver is self-deleting.
+  GetLogo(new CallbackLogoObserver(
+      std::move(on_cached_logo_available), EncodedLogoCallback(),
+      std::move(on_fresh_logo_available), EncodedLogoCallback()));
+}
+
+void LogoService::GetEncodedLogo(EncodedLogoCallback on_cached_logo_available,
+                                 EncodedLogoCallback on_fresh_logo_available) {
+  // CallbackLogoObserver is self-deleting.
+  GetLogo(new CallbackLogoObserver(
+      LogoCallback(), std::move(on_cached_logo_available), LogoCallback(),
+      std::move(on_fresh_logo_available)));
+}
+
 void LogoService::SetLogoCacheForTests(std::unique_ptr<LogoCache> cache) {
   logo_cache_for_test_ = std::move(cache);
 }
diff --git a/components/search_provider_logos/logo_service.h b/components/search_provider_logos/logo_service.h
index 78ea7b5b..7ff73fe 100644
--- a/components/search_provider_logos/logo_service.h
+++ b/components/search_provider_logos/logo_service.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/search_provider_logos/logo_common.h"
 
 class TemplateURLService;
 
@@ -49,20 +50,46 @@
 
   ~LogoService() override;
 
+  // Gets the logo for the default search provider and calls the provided
+  // callbacks with the encoded or decoded logos (for GetEncodedLogo() or
+  // GetLogo(), respectively) The service will:
+  //
+  // 1.  Load a cached logo,
+  //     *   and call on_cached_logo_available with a cached logo, if
+  //         available and still up-to-date.
+  //     *   and call on_cached_logo_available with a null logo, if there is no
+  //         cached logo or it is out-of-date.
+  //     *   and do nothing, if the current default search engine does not
+  //         support logos.
+  //
+  // 2.  Fetch a fresh logo for the default search engine,
+  //     *   and call on_fresh_logo_available with a fresh logo, if the service
+  //         fetched a new logo (and didn't just revalidate the cached logo)
+  //     *   and call on_fresh_logo_available with a null logo, if both:
+  //         *   the server responded, but its response was invalid or did not
+  //             contain a fresh logo, and
+  //         *   the service previously called on_cached_logo_available with a
+  //             non-null logo, so it is necessary to invalidate it.
+  //     *   and do nothing, if either:
+  //         *   the default search engine does not have a logo, or
+  //         *   the the server did not respond, or
+  //         *   the server reported that the cached logo was up-to-date, or
+  //         *   the logo data could be parsed, but not the logo image itself.
+  //
+  // TODO(sfiera): simplify the interface to the point that it does not require
+  // three nested lists to explain.
+  void GetLogo(LogoCallback on_cached_logo_available,
+               LogoCallback on_fresh_logo_available);
+  void GetEncodedLogo(EncodedLogoCallback on_cached_logo_available,
+                      EncodedLogoCallback on_fresh_logo_available);
+
   // Gets the logo for the default search provider and notifies |observer|
   // 0-2 times with the results. The service will:
   //
-  // 1.  Load a cached logo,
-  //     *   and call observer->OnLogoAvailable() with a cached logo, if
-  //         available and still up-to-date.
-  //     *   and do nothing, if there is no cached logo or it is out-of-date.
-  // 2.  Fetch a fresh logo for the default search engine,
-  //     *   and call OnLogoAvailable() with a fresh logo, if the service
-  //         fetched a fresh logo
-  //     *   and call OnLogoAvailable() with a null logo, if the fetched logo
-  //         was null and the cached logo was non-null
-  //     *   and do nothing, if the default search engine does not have a logo,
-  //         or both the fresh and cached logos were null.
+  // 1.  Call observer->OnLogoAvailable() with |from_cache=true| when
+  //     |on_cached_logo_available| would be called in the callback interface.
+  // 2.  Call observer->OnLogoAvailable() with |from_cache=false| when
+  //     |on_fresh_logo_available| would be called in the callback interface.
   // 3.  Call observer->OnObserverRemoved().
   void GetLogo(search_provider_logos::LogoObserver* observer);
 
diff --git a/components/search_provider_logos/logo_service_unittest.cc b/components/search_provider_logos/logo_service_unittest.cc
index d75ebeba..6f8f1883 100644
--- a/components/search_provider_logos/logo_service_unittest.cc
+++ b/components/search_provider_logos/logo_service_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_clock.h"
@@ -50,20 +51,24 @@
 using ::testing::_;
 using ::testing::AnyNumber;
 using ::testing::AtMost;
+using ::testing::Eq;
 using ::testing::InSequence;
 using ::testing::Invoke;
 using ::testing::Mock;
+using ::testing::Ne;
 using ::testing::NiceMock;
+using ::testing::Not;
+using ::testing::NotNull;
+using ::testing::Pointee;
+using ::testing::StrictMock;
 using ::testing::Return;
 
 namespace search_provider_logos {
 
 namespace {
 
-bool AreImagesSameSize(const SkBitmap& bitmap1, const SkBitmap& bitmap2) {
-  return bitmap1.width() == bitmap2.width() &&
-         bitmap1.height() == bitmap2.height();
-}
+using MockLogoCallback = base::MockCallback<LogoCallback>;
+using MockEncodedLogoCallback = base::MockCallback<EncodedLogoCallback>;
 
 scoped_refptr<base::RefCountedString> EncodeBitmapAsPNG(
     const SkBitmap& bitmap) {
@@ -177,37 +182,15 @@
       logo.metadata.fingerprint, time_to_live);
 }
 
-void ExpectLogosEqual(const Logo* expected_logo, const Logo* actual_logo) {
-  if (!expected_logo) {
-    ASSERT_FALSE(actual_logo);
-    return;
-  }
-  ASSERT_TRUE(actual_logo);
-  EXPECT_TRUE(AreImagesSameSize(expected_logo->image, actual_logo->image));
-  EXPECT_EQ(expected_logo->metadata.on_click_url,
-            actual_logo->metadata.on_click_url);
-  EXPECT_EQ(expected_logo->metadata.source_url,
-            actual_logo->metadata.source_url);
-  EXPECT_EQ(expected_logo->metadata.animated_url,
-            actual_logo->metadata.animated_url);
-  EXPECT_EQ(expected_logo->metadata.alt_text, actual_logo->metadata.alt_text);
-  EXPECT_EQ(expected_logo->metadata.mime_type, actual_logo->metadata.mime_type);
-  EXPECT_EQ(expected_logo->metadata.fingerprint,
-            actual_logo->metadata.fingerprint);
-  EXPECT_EQ(expected_logo->metadata.can_show_after_expiration,
-            actual_logo->metadata.can_show_after_expiration);
+template <typename Arg, typename Matcher>
+bool Match(const Arg& arg,
+           const Matcher& matcher,
+           ::testing::MatchResultListener* result_listener) {
+  return ::testing::Matcher<Arg>(matcher).MatchAndExplain(arg, result_listener);
 }
 
-void ExpectLogosEqual(const Logo* expected_logo,
-                      const EncodedLogo* actual_encoded_logo) {
-  Logo actual_logo;
-  if (actual_encoded_logo)
-    actual_logo = DecodeLogo(*actual_encoded_logo);
-  ExpectLogosEqual(expected_logo, actual_encoded_logo ? &actual_logo : nullptr);
-}
-
-ACTION_P(ExpectLogosEqualAction, expected_logo) {
-  ExpectLogosEqual(expected_logo, arg0);
+MATCHER_P(DecodesTo, decoded_logo, "") {
+  return Match(DecodeLogo(arg), Eq(decoded_logo), result_listener);
 }
 
 class MockLogoCache : public LogoCache {
@@ -239,8 +222,11 @@
 
   void ExpectSetCachedLogo(const Logo* expected_logo) {
     Mock::VerifyAndClearExpectations(this);
-    EXPECT_CALL(*this, SetCachedLogo(_))
-        .WillOnce(ExpectLogosEqualAction(expected_logo));
+    if (expected_logo) {
+      EXPECT_CALL(*this, SetCachedLogo(Pointee(DecodesTo(*expected_logo))));
+    } else {
+      EXPECT_CALL(*this, SetCachedLogo(nullptr));
+    }
   }
 
   void UpdateCachedLogoMetadataInternal(const LogoMetadata& metadata) {
@@ -256,13 +242,13 @@
   }
 
   void SetCachedLogoInternal(const EncodedLogo* logo) {
-    logo_ = logo ? base::MakeUnique<EncodedLogo>(*logo) : nullptr;
-    metadata_ = logo ? base::MakeUnique<LogoMetadata>(logo->metadata) : nullptr;
+    logo_ = logo ? std::make_unique<EncodedLogo>(*logo) : nullptr;
+    metadata_ = logo ? std::make_unique<LogoMetadata>(logo->metadata) : nullptr;
   }
 
   std::unique_ptr<EncodedLogo> GetCachedLogo() override {
     OnGetCachedLogo();
-    return logo_ ? base::MakeUnique<EncodedLogo>(*logo_) : nullptr;
+    return logo_ ? std::make_unique<EncodedLogo>(*logo_) : nullptr;
   }
 
  private:
@@ -270,48 +256,6 @@
   std::unique_ptr<EncodedLogo> logo_;
 };
 
-class MockLogoObserver : public LogoObserver {
- public:
-  virtual ~MockLogoObserver() {}
-
-  void ExpectNoLogo() {
-    Mock::VerifyAndClearExpectations(this);
-    EXPECT_CALL(*this, OnLogoAvailable(_, _)).Times(0);
-    EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
-  }
-
-  void ExpectCachedLogo(const Logo* expected_cached_logo) {
-    Mock::VerifyAndClearExpectations(this);
-    EXPECT_CALL(*this, OnLogoAvailable(_, true))
-        .WillOnce(ExpectLogosEqualAction(expected_cached_logo));
-    EXPECT_CALL(*this, OnLogoAvailable(_, false)).Times(0);
-    EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
-  }
-
-  void ExpectFreshLogo(const Logo* expected_fresh_logo) {
-    Mock::VerifyAndClearExpectations(this);
-    EXPECT_CALL(*this, OnLogoAvailable(_, true)).Times(0);
-    EXPECT_CALL(*this, OnLogoAvailable(nullptr, true));
-    EXPECT_CALL(*this, OnLogoAvailable(_, false))
-        .WillOnce(ExpectLogosEqualAction(expected_fresh_logo));
-    EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
-  }
-
-  void ExpectCachedAndFreshLogos(const Logo* expected_cached_logo,
-                                 const Logo* expected_fresh_logo) {
-    Mock::VerifyAndClearExpectations(this);
-    InSequence dummy;
-    EXPECT_CALL(*this, OnLogoAvailable(_, true))
-        .WillOnce(ExpectLogosEqualAction(expected_cached_logo));
-    EXPECT_CALL(*this, OnLogoAvailable(_, false))
-        .WillOnce(ExpectLogosEqualAction(expected_fresh_logo));
-    EXPECT_CALL(*this, OnObserverRemoved()).Times(1);
-  }
-
-  MOCK_METHOD2(OnLogoAvailable, void(const Logo*, bool));
-  MOCK_METHOD0(OnObserverRemoved, void());
-};
-
 class FakeImageDecoder : public image_fetcher::ImageDecoder {
  public:
   void DecodeImage(
@@ -342,8 +286,8 @@
 
     test_clock_->SetNow(base::Time::FromJsTime(INT64_C(1388686828000)));
     logo_service_ =
-        base::MakeUnique<LogoService>(base::FilePath(), &template_url_service_,
-                                      base::MakeUnique<FakeImageDecoder>(),
+        std::make_unique<LogoService>(base::FilePath(), &template_url_service_,
+                                      std::make_unique<FakeImageDecoder>(),
                                       new net::TestURLRequestContextGetter(
                                           base::ThreadTaskRunnerHandle::Get()),
                                       /*use_gray_background=*/false);
@@ -382,7 +326,10 @@
 
   // Calls logo_service_->GetLogo() with |observer_| and waits for the
   // asynchronous response(s).
-  void GetLogo();
+  void GetLogo(LogoCallback on_cached_logo_available,
+               LogoCallback on_fresh_logo_available);
+  void GetEncodedLogo(EncodedLogoCallback on_cached_logo_available,
+                      EncodedLogoCallback on_fresh_logo_available);
 
   void AddSearchEngine(base::StringPiece keyword,
                        base::StringPiece short_name,
@@ -397,7 +344,6 @@
   NiceMock<MockLogoCache>* logo_cache_;
   net::FakeURLFetcherFactory fake_url_fetcher_factory_;
   std::unique_ptr<LogoService> logo_service_;
-  NiceMock<MockLogoObserver> observer_;
 };
 
 std::string LogoServiceTest::ServerResponse(const Logo& logo) const {
@@ -430,8 +376,18 @@
   return template_url_service_.GetDefaultSearchProvider()->doodle_url();
 }
 
-void LogoServiceTest::GetLogo() {
-  logo_service_->GetLogo(&observer_);
+void LogoServiceTest::GetLogo(LogoCallback on_cached_logo_available,
+                              LogoCallback on_fresh_logo_available) {
+  logo_service_->GetLogo(std::move(on_cached_logo_available),
+                         std::move(on_fresh_logo_available));
+  task_environment_.RunUntilIdle();
+}
+
+void LogoServiceTest::GetEncodedLogo(
+    EncodedLogoCallback on_cached_logo_available,
+    EncodedLogoCallback on_fresh_logo_available) {
+  logo_service_->GetEncodedLogo(std::move(on_cached_logo_available),
+                                std::move(on_fresh_logo_available));
   task_environment_.RunUntilIdle();
 }
 
@@ -447,7 +403,7 @@
   search_url.doodle_url = doodle_url;
 
   TemplateURL* template_url =
-      template_url_service_.Add(base::MakeUnique<TemplateURL>(search_url));
+      template_url_service_.Add(std::make_unique<TemplateURL>(search_url));
   if (make_default) {
     template_url_service_.SetUserSelectedDefaultSearchProvider(template_url);
   }
@@ -480,11 +436,26 @@
 }
 
 TEST_F(LogoServiceTest, DownloadAndCacheLogo) {
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
   Logo logo = GetSampleLogo(DoodleURL(), test_clock_->Now());
   SetServerResponse(ServerResponse(logo));
   logo_cache_->ExpectSetCachedLogo(&logo);
-  observer_.ExpectFreshLogo(&logo);
-  GetLogo();
+  EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+  EXPECT_CALL(fresh, Run(Eq(logo)));
+  GetLogo(cached.Get(), fresh.Get());
+}
+
+TEST_F(LogoServiceTest, DownloadAndCacheEncodedLogo) {
+  StrictMock<MockEncodedLogoCallback> cached;
+  StrictMock<MockEncodedLogoCallback> fresh;
+  Logo logo = GetSampleLogo(DoodleURL(), test_clock_->Now());
+  EncodedLogo encoded_logo = EncodeLogo(logo);
+  SetServerResponse(ServerResponse(logo));
+  logo_cache_->ExpectSetCachedLogo(&logo);
+  EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+  EXPECT_CALL(fresh, Run(Eq(encoded_logo)));
+  GetEncodedLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, EmptyCacheAndFailedDownload) {
@@ -492,17 +463,33 @@
   EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
   EXPECT_CALL(*logo_cache_, SetCachedLogo(nullptr)).Times(AnyNumber());
 
-  SetServerResponse("server is borked");
-  observer_.ExpectCachedLogo(nullptr);
-  GetLogo();
+  {
+    StrictMock<MockLogoCallback> cached;
+    StrictMock<MockLogoCallback> fresh;
+    SetServerResponse("server is borked");
+    EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+    EXPECT_CALL(fresh, Run(_)).Times(0);
+    GetLogo(cached.Get(), fresh.Get());
+  }
 
-  SetServerResponse("", net::URLRequestStatus::FAILED, net::HTTP_OK);
-  observer_.ExpectCachedLogo(nullptr);
-  GetLogo();
+  {
+    StrictMock<MockLogoCallback> cached;
+    StrictMock<MockLogoCallback> fresh;
+    SetServerResponse("", net::URLRequestStatus::FAILED, net::HTTP_OK);
+    EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+    EXPECT_CALL(fresh, Run(_)).Times(0);
+    GetLogo(cached.Get(), fresh.Get());
+  }
 
-  SetServerResponse("", net::URLRequestStatus::SUCCESS, net::HTTP_BAD_GATEWAY);
-  observer_.ExpectCachedLogo(nullptr);
-  GetLogo();
+  {
+    StrictMock<MockLogoCallback> cached;
+    StrictMock<MockLogoCallback> fresh;
+    SetServerResponse("", net::URLRequestStatus::SUCCESS,
+                      net::HTTP_BAD_GATEWAY);
+    EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+    EXPECT_CALL(fresh, Run(_)).Times(0);
+    GetLogo(cached.Get(), fresh.Get());
+  }
 }
 
 TEST_F(LogoServiceTest, AcceptMinimalLogoResponse) {
@@ -517,8 +504,13 @@
       EncodeBitmapAsPNGBase64(logo.image) + "\"}}";
 
   SetServerResponse(response);
-  observer_.ExpectFreshLogo(&logo);
-  GetLogo();
+
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+  EXPECT_CALL(fresh, Run(Eq(logo)));
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, ReturnCachedLogo) {
@@ -530,8 +522,13 @@
   EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
   EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedLogo(&cached_logo);
-  GetLogo();
+
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(cached_logo)));
+  EXPECT_CALL(fresh, Run(_)).Times(0);
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, ValidateCachedLogo) {
@@ -547,23 +544,36 @@
   SetServerResponseWhenFingerprint(fresh_logo.metadata.fingerprint,
                                    ServerResponse(fresh_logo));
 
-  EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(1);
-  EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
-  EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedLogo(&cached_logo);
-  GetLogo();
+  {
+    EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(1);
+    EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
+    EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
+
+    StrictMock<MockLogoCallback> cached;
+    StrictMock<MockLogoCallback> fresh;
+    EXPECT_CALL(cached, Run(Eq(cached_logo)));
+    EXPECT_CALL(fresh, Run(_)).Times(0);
+    GetLogo(cached.Get(), fresh.Get());
+  }
 
   ASSERT_TRUE(logo_cache_->GetCachedLogoMetadata());
   EXPECT_EQ(fresh_logo.metadata.expiration_time,
             logo_cache_->GetCachedLogoMetadata()->expiration_time);
 
-  // Ensure that cached logo is still returned correctly on subsequent requests.
-  // In particular, the metadata should stay valid. http://crbug.com/480090
-  EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(1);
-  EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
-  EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedLogo(&cached_logo);
-  GetLogo();
+  {
+    // Ensure that cached logo is still returned correctly on subsequent
+    // requests. In particular, the metadata should stay valid.
+    // http://crbug.com/480090
+    EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(1);
+    EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
+    EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
+
+    StrictMock<MockLogoCallback> cached;
+    StrictMock<MockLogoCallback> fresh;
+    EXPECT_CALL(cached, Run(Eq(cached_logo)));
+    EXPECT_CALL(fresh, Run(_)).Times(0);
+    GetLogo(cached.Get(), fresh.Get());
+  }
 }
 
 TEST_F(LogoServiceTest, UpdateCachedLogoMetadata) {
@@ -582,16 +592,28 @@
                                    ServerResponse(fresh_logo));
 
   // On the first request, the cached logo should be used.
-  observer_.ExpectCachedLogo(&cached_logo);
-  GetLogo();
+  {
+    StrictMock<MockLogoCallback> cached;
+    StrictMock<MockLogoCallback> fresh;
+    EXPECT_CALL(cached, Run(Eq(cached_logo)));
+    // TODO(sfiera): double-check whether we should inform the observer of the
+    // fresh metadata.
+    EXPECT_CALL(fresh, Run(_)).Times(0);
+    GetLogo(cached.Get(), fresh.Get());
+  }
 
   // Subsequently, the cached image should be returned along with the updated
   // metadata.
-  Logo expected_logo = fresh_logo;
-  expected_logo.image = cached_logo.image;
-  expected_logo.metadata.mime_type = cached_logo.metadata.mime_type;
-  observer_.ExpectCachedLogo(&expected_logo);
-  GetLogo();
+  {
+    Logo expected_logo = fresh_logo;
+    expected_logo.image = cached_logo.image;
+    expected_logo.metadata.mime_type = cached_logo.metadata.mime_type;
+    StrictMock<MockLogoCallback> cached;
+    StrictMock<MockLogoCallback> fresh;
+    EXPECT_CALL(cached, Run(Eq(expected_logo)));
+    EXPECT_CALL(fresh, Run(_)).Times(0);
+    GetLogo(cached.Get(), fresh.Get());
+  }
 }
 
 TEST_F(LogoServiceTest, UpdateCachedLogo) {
@@ -605,9 +627,12 @@
   logo_cache_->ExpectSetCachedLogo(&fresh_logo);
   EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedAndFreshLogos(&cached_logo, &fresh_logo);
 
-  GetLogo();
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(cached_logo)));
+  EXPECT_CALL(fresh, Run(Eq(fresh_logo)));
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, InvalidateCachedLogo) {
@@ -621,9 +646,13 @@
   logo_cache_->ExpectSetCachedLogo(nullptr);
   EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedAndFreshLogos(&cached_logo, nullptr);
 
-  GetLogo();
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(cached_logo)));
+  EXPECT_CALL(fresh, Run(Eq(base::nullopt)));
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, DeleteCachedLogoFromOldUrl) {
@@ -636,8 +665,13 @@
   EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
   EXPECT_CALL(*logo_cache_, SetCachedLogo(nullptr)).Times(AnyNumber());
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedLogo(nullptr);
-  GetLogo();
+
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+  EXPECT_CALL(fresh, Run(_)).Times(0);
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, LogoWithTTLCannotBeShownAfterExpiration) {
@@ -645,7 +679,7 @@
   base::TimeDelta time_to_live = base::TimeDelta::FromDays(3);
   logo.metadata.expiration_time = test_clock_->Now() + time_to_live;
   SetServerResponse(ServerResponse(logo));
-  GetLogo();
+  GetLogo(LogoCallback(), LogoCallback());
 
   const LogoMetadata* cached_metadata = logo_cache_->GetCachedLogoMetadata();
   ASSERT_TRUE(cached_metadata);
@@ -658,7 +692,7 @@
   Logo logo = GetSampleLogo(DoodleURL(), test_clock_->Now());
   base::TimeDelta time_to_live = base::TimeDelta();
   SetServerResponse(MakeServerResponse(logo, time_to_live));
-  GetLogo();
+  GetLogo(LogoCallback(), LogoCallback());
 
   const LogoMetadata* cached_metadata = logo_cache_->GetCachedLogoMetadata();
   ASSERT_TRUE(cached_metadata);
@@ -678,8 +712,13 @@
   EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
   EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedLogo(&cached_logo);
-  GetLogo();
+
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(cached_logo)));
+  EXPECT_CALL(fresh, Run(_)).Times(0);
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, RerequestSoftExpiredCachedLogo) {
@@ -695,9 +734,13 @@
   logo_cache_->ExpectSetCachedLogo(&fresh_logo);
   EXPECT_CALL(*logo_cache_, UpdateCachedLogoMetadata(_)).Times(0);
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedAndFreshLogos(&cached_logo, &fresh_logo);
 
-  GetLogo();
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(cached_logo)));
+  EXPECT_CALL(fresh, Run(Eq(fresh_logo)));
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, DeleteAncientCachedLogo) {
@@ -712,8 +755,13 @@
   EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
   EXPECT_CALL(*logo_cache_, SetCachedLogo(nullptr)).Times(AnyNumber());
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedLogo(nullptr);
-  GetLogo();
+
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+  EXPECT_CALL(fresh, Run(_)).Times(0);
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 TEST_F(LogoServiceTest, DeleteExpiredCachedLogo) {
@@ -728,23 +776,30 @@
   EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(0);
   EXPECT_CALL(*logo_cache_, SetCachedLogo(nullptr)).Times(AnyNumber());
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(1));
-  observer_.ExpectCachedLogo(nullptr);
-  GetLogo();
+
+  StrictMock<MockLogoCallback> cached;
+  StrictMock<MockLogoCallback> fresh;
+  EXPECT_CALL(cached, Run(Eq(base::nullopt)));
+  EXPECT_CALL(fresh, Run(_)).Times(0);
+
+  GetLogo(cached.Get(), fresh.Get());
 }
 
 // Tests that deal with multiple listeners.
 
-void EnqueueObservers(
-    LogoService* logo_service,
-    const std::vector<std::unique_ptr<MockLogoObserver>>& observers,
-    size_t start_index) {
-  if (start_index >= observers.size())
+void EnqueueObservers(LogoService* logo_service,
+                      std::vector<LogoCallback>* cached_callbacks,
+                      std::vector<LogoCallback>* fresh_callbacks,
+                      size_t start_index) {
+  DCHECK_EQ(cached_callbacks->size(), fresh_callbacks->size());
+  if (start_index >= cached_callbacks->size())
     return;
 
-  logo_service->GetLogo(observers[start_index].get());
+  logo_service->GetLogo(std::move((*cached_callbacks)[start_index]),
+                        std::move((*fresh_callbacks)[start_index]));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&EnqueueObservers, logo_service,
-                            base::ConstRef(observers), start_index + 1));
+      FROM_HERE, base::Bind(&EnqueueObservers, logo_service, cached_callbacks,
+                            fresh_callbacks, start_index + 1));
 }
 
 #if defined(THREAD_SANITIZER)
@@ -765,13 +820,19 @@
   SetServerResponseWhenFingerprint(cached_logo.metadata.fingerprint, response);
 
   const int kNumListeners = 10;
-  std::vector<std::unique_ptr<MockLogoObserver>> listeners;
+  std::vector<std::unique_ptr<MockLogoCallback>> mocks;
+  std::vector<LogoCallback> cached_callbacks;
+  std::vector<LogoCallback> fresh_callbacks;
   for (int i = 0; i < kNumListeners; ++i) {
-    auto listener = base::MakeUnique<MockLogoObserver>();
-    listener->ExpectCachedAndFreshLogos(&cached_logo, &fresh_logo);
-    listeners.push_back(std::move(listener));
+    mocks.push_back(std::make_unique<MockLogoCallback>());
+    EXPECT_CALL(*mocks.back(), Run(Eq(cached_logo)));
+    cached_callbacks.push_back(mocks.back()->Get());
+
+    mocks.push_back(std::make_unique<MockLogoCallback>());
+    EXPECT_CALL(*mocks.back(), Run(Eq(fresh_logo)));
+    fresh_callbacks.push_back(mocks.back()->Get());
   }
-  EnqueueObservers(logo_service_.get(), listeners, 0);
+  EnqueueObservers(logo_service_.get(), &cached_callbacks, &fresh_callbacks, 0);
 
   EXPECT_CALL(*logo_cache_, SetCachedLogo(_)).Times(AtMost(3));
   EXPECT_CALL(*logo_cache_, OnGetCachedLogo()).Times(AtMost(3));
@@ -780,9 +841,11 @@
 }
 
 TEST_F(LogoServiceTest, DeleteObserversWhenLogoURLChanged) {
-  MockLogoObserver listener1;
-  listener1.ExpectNoLogo();
-  logo_service_->GetLogo(&listener1);
+  StrictMock<MockLogoCallback> first_cached;
+  StrictMock<MockLogoCallback> first_fresh;
+  EXPECT_CALL(first_cached, Run(_)).Times(0);
+  EXPECT_CALL(first_fresh, Run(_)).Times(0);
+  logo_service_->GetLogo(first_cached.Get(), first_fresh.Get());
 
   // Change default search engine; new DSE has a doodle URL.
   AddSearchEngine("cr", "Chromium", "https://www.chromium.org/?q={searchTerms}",
@@ -792,13 +855,48 @@
   Logo logo = GetSampleLogo(DoodleURL(), test_clock_->Now());
   SetServerResponse(ServerResponse(logo));
 
-  MockLogoObserver listener2;
-  listener2.ExpectFreshLogo(&logo);
-  logo_service_->GetLogo(&listener2);
+  StrictMock<MockLogoCallback> second_cached;
+  StrictMock<MockLogoCallback> second_fresh;
+  EXPECT_CALL(second_cached, Run(Eq(base::nullopt)));
+  EXPECT_CALL(second_fresh, Run(Eq(logo)));
+  logo_service_->GetLogo(second_cached.Get(), second_fresh.Get());
 
   task_environment_.RunUntilIdle();
 }
 
 }  // namespace
 
+bool operator==(const Logo& a, const Logo& b) {
+  return (a.image.width() == b.image.width()) &&
+         (a.image.height() == b.image.height()) &&
+         (a.metadata.on_click_url == b.metadata.on_click_url) &&
+         (a.metadata.source_url == b.metadata.source_url) &&
+         (a.metadata.animated_url == b.metadata.animated_url) &&
+         (a.metadata.alt_text == b.metadata.alt_text) &&
+         (a.metadata.mime_type == b.metadata.mime_type) &&
+         (a.metadata.fingerprint == b.metadata.fingerprint) &&
+         (a.metadata.can_show_after_expiration ==
+          b.metadata.can_show_after_expiration);
+}
+
+bool operator==(const EncodedLogo& a, const EncodedLogo& b) {
+  return DecodeLogo(a) == DecodeLogo(b);
+}
+
+void PrintTo(const Logo& logo, std::ostream* ostr) {
+  *ostr << "image size: " << logo.image.width() << "x" << logo.image.height()
+        << "\non_click_url: " << logo.metadata.on_click_url
+        << "\nsource_url: " << logo.metadata.source_url
+        << "\nanimated_url: " << logo.metadata.animated_url
+        << "\nalt_text: " << logo.metadata.alt_text
+        << "\nmime_type: " << logo.metadata.mime_type
+        << "\nfingerprint: " << logo.metadata.fingerprint
+        << "\ncan_show_after_expiration: "
+        << logo.metadata.can_show_after_expiration;
+}
+
+void PrintTo(const EncodedLogo& logo, std::ostream* ostr) {
+  PrintTo(DecodeLogo(logo), ostr);
+}
+
 }  // namespace search_provider_logos
diff --git a/components/search_provider_logos/logo_tracker.cc b/components/search_provider_logos/logo_tracker.cc
index 3891cc31..1af279da 100644
--- a/components/search_provider_logos/logo_tracker.cc
+++ b/components/search_provider_logos/logo_tracker.cc
@@ -144,6 +144,7 @@
 void LogoTracker::OnCachedLogoRead(std::unique_ptr<EncodedLogo> cached_logo) {
   DCHECK(!is_idle_);
 
+  NotifyEncodedLogoObservers(cached_logo.get(), /*from_cache=*/true);
   if (cached_logo) {
     logo_delegate_->DecodeUntrustedImage(
         cached_logo->encoded_image,
@@ -166,8 +167,7 @@
   }
   is_cached_logo_valid_ = true;
   Logo* logo = cached_logo_.get();
-  for (auto& observer : logo_observers_)
-    observer.OnLogoAvailable(logo, true);
+  NotifyDecodedLogoObservers(logo, /*from_cache=*/true);
   FetchLogo();
 }
 
@@ -243,8 +243,8 @@
     logo->metadata.source_url = logo_url_;
 
   if (!logo || !logo->encoded_image.get()) {
-    OnFreshLogoAvailable(std::move(logo), *parsing_failed, from_http_cache,
-                         SkBitmap());
+    OnFreshLogoAvailable(std::move(logo), /*download_failed=*/false,
+                         *parsing_failed, from_http_cache, SkBitmap());
   } else {
     // Store the value of logo->encoded_image for use below. This ensures that
     // logo->encoded_image is evaulated before base::Passed(&logo), which sets
@@ -254,23 +254,28 @@
         encoded_image,
         base::Bind(&LogoTracker::OnFreshLogoAvailable,
                    weak_ptr_factory_.GetWeakPtr(), base::Passed(&logo),
-                   *parsing_failed, from_http_cache));
+                   /*download_failed=*/false, *parsing_failed,
+                   from_http_cache));
   }
 }
 
 void LogoTracker::OnFreshLogoAvailable(
     std::unique_ptr<EncodedLogo> encoded_logo,
+    bool download_failed,
     bool parsing_failed,
     bool from_http_cache,
     const SkBitmap& image) {
   DCHECK(!is_idle_);
 
-  int download_outcome = kDownloadOutcomeNotTracked;
+  LogoDownloadOutcome download_outcome = DOWNLOAD_OUTCOME_COUNT;
+  std::unique_ptr<Logo> logo;
 
-  if (encoded_logo && !encoded_logo->encoded_image.get() && cached_logo_ &&
-      !encoded_logo->metadata.fingerprint.empty() &&
-      encoded_logo->metadata.fingerprint ==
-          cached_logo_->metadata.fingerprint) {
+  if (download_failed) {
+    download_outcome = DOWNLOAD_OUTCOME_DOWNLOAD_FAILED;
+  } else if (encoded_logo && !encoded_logo->encoded_image.get() &&
+             cached_logo_ && !encoded_logo->metadata.fingerprint.empty() &&
+             encoded_logo->metadata.fingerprint ==
+                 cached_logo_->metadata.fingerprint) {
     // The cached logo was revalidated, i.e. its fingerprint was verified.
     // mime_type isn't sent when revalidating, so copy it from the cached logo.
     encoded_logo->metadata.mime_type = cached_logo_->metadata.mime_type;
@@ -280,7 +285,6 @@
     // Image decoding failed. Do nothing.
     download_outcome = DOWNLOAD_OUTCOME_DECODING_FAILED;
   } else {
-    std::unique_ptr<Logo> logo;
     // Check if the server returned a valid, non-empty response.
     if (encoded_logo) {
       UMA_HISTOGRAM_BOOLEAN("NewTabPage.LogoImageDownloaded", from_http_cache);
@@ -299,26 +303,73 @@
       else
         download_outcome = DOWNLOAD_OUTCOME_NO_LOGO_TODAY;
     }
-
-    // Notify observers if a new logo was fetched, or if the new logo is NULL
-    // but the cached logo was non-NULL.
-    if (logo || cached_logo_) {
-      for (auto& observer : logo_observers_)
-        observer.OnLogoAvailable(logo.get(), false);
-      SetCachedLogo(std::move(encoded_logo));
-    }
   }
 
-  DCHECK_NE(kDownloadOutcomeNotTracked, download_outcome);
+  switch (download_outcome) {
+    case DOWNLOAD_OUTCOME_NEW_LOGO_SUCCESS:
+      DCHECK(encoded_logo.get());
+      DCHECK(logo.get());
+      NotifyEncodedLogoObservers(encoded_logo.get(), /*from_cache=*/false);
+      NotifyDecodedLogoObservers(logo.get(), /*from_cache=*/false);
+      SetCachedLogo(std::move(encoded_logo));
+      break;
+
+    case DOWNLOAD_OUTCOME_PARSING_FAILED:
+    case DOWNLOAD_OUTCOME_NO_LOGO_TODAY:
+      // Invalidate the cached logo if it was non-null. Otherwise, do nothing.
+      DCHECK(!encoded_logo.get());
+      DCHECK(!logo.get());
+      if (cached_logo_) {
+        NotifyEncodedLogoObservers(nullptr, /*from_cache=*/false);
+        NotifyDecodedLogoObservers(nullptr, /*from_cache=*/false);
+        SetCachedLogo(std::move(encoded_logo));
+      }
+      break;
+
+    case DOWNLOAD_OUTCOME_DECODING_FAILED:
+    case DOWNLOAD_OUTCOME_LOGO_REVALIDATED:
+      // In the server reported that the cached logo is still current, don't
+      // notify the observer at all, since the observer should continue to use
+      // the cached logo.
+      DCHECK(encoded_logo.get());
+      DCHECK(!logo.get());
+      break;
+
+    case DOWNLOAD_OUTCOME_DOWNLOAD_FAILED:
+      // In the download failed, don't notify the observer at all, since the
+      // observer should continue to use the cached logo.
+      DCHECK(!encoded_logo.get());
+      DCHECK(!logo.get());
+      break;
+
+    case DOWNLOAD_OUTCOME_COUNT:
+      NOTREACHED();
+  }
+
   ReturnToIdle(download_outcome);
 }
 
+void LogoTracker::NotifyDecodedLogoObservers(const Logo* logo,
+                                             bool from_cache) const {
+  for (auto& observer : logo_observers_) {
+    observer.OnLogoAvailable(logo, from_cache);
+  }
+}
+
+void LogoTracker::NotifyEncodedLogoObservers(const EncodedLogo* logo,
+                                             bool from_cache) const {
+  for (auto& observer : logo_observers_) {
+    observer.OnEncodedLogoAvailable(logo, from_cache);
+  }
+}
+
 void LogoTracker::OnURLFetchComplete(const net::URLFetcher* source) {
   DCHECK(!is_idle_);
   std::unique_ptr<net::URLFetcher> cleanup_fetcher(fetcher_.release());
 
   if (!source->GetStatus().is_success()) {
-    ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
+    OnFreshLogoAvailable({}, /*download_failed=*/true, false, false,
+                         SkBitmap());
     return;
   }
 
@@ -327,7 +378,8 @@
       response_code != net::URLFetcher::RESPONSE_CODE_INVALID) {
     // RESPONSE_CODE_INVALID is returned when fetching from a file: URL
     // (for testing). In all other cases we would have had a non-success status.
-    ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
+    OnFreshLogoAvailable({}, /*download_failed=*/true, false, false,
+                         SkBitmap());
     return;
   }
 
@@ -358,7 +410,8 @@
                                              int64_t current_network_bytes) {
   if (total > kMaxDownloadBytes || current > kMaxDownloadBytes) {
     LOG(WARNING) << "Search provider logo exceeded download size limit";
-    ReturnToIdle(DOWNLOAD_OUTCOME_DOWNLOAD_FAILED);
+    OnFreshLogoAvailable({}, /*download_failed=*/true, false, false,
+                         SkBitmap());
   }
 }
 
diff --git a/components/search_provider_logos/logo_tracker.h b/components/search_provider_logos/logo_tracker.h
index bef268a..0cf83a4 100644
--- a/components/search_provider_logos/logo_tracker.h
+++ b/components/search_provider_logos/logo_tracker.h
@@ -43,6 +43,8 @@
   // If the fresh logo is the same as the cached logo, this will not be called
   // again.
   virtual void OnLogoAvailable(const Logo* logo, bool from_cache) = 0;
+  virtual void OnEncodedLogoAvailable(const EncodedLogo* logo,
+                                      bool from_cache) {}
 
   // Called when the LogoTracker will no longer send updates to this
   // LogoObserver. For example: after the cached logo is validated, after
@@ -166,10 +168,16 @@
   // Called when the fresh logo has been decoded into an SkBitmap. |image| will
   // be NULL if decoding failed.
   void OnFreshLogoAvailable(std::unique_ptr<EncodedLogo> logo,
+                            bool download_failed,
                             bool parsing_failed,
                             bool from_http_cache,
                             const SkBitmap& image);
 
+  void NotifyDecodedLogoObservers(const Logo* logo, bool from_cache) const;
+  void NotifyEncodedLogoObservers(const EncodedLogo* logo,
+                                  bool from_cache) const;
+  bool HaveDecodedLogoObservers() const;
+
   // net::URLFetcherDelegate:
   void OnURLFetchComplete(const net::URLFetcher* source) override;
   void OnURLFetchDownloadProgress(const net::URLFetcher* source,
diff --git a/components/security_interstitials/content/unsafe_resource.cc b/components/security_interstitials/content/unsafe_resource.cc
index 2b77bd6..aa24632 100644
--- a/components/security_interstitials/content/unsafe_resource.cc
+++ b/components/security_interstitials/content/unsafe_resource.cc
@@ -41,12 +41,10 @@
     return false;
 
   switch (threat_type) {
-    // Client-side phishing/malware detection and password protection phishing
-    // interstitials never block the main frame load, since they happen after
-    // the page is finished loading.
+    // Client-side phishing/malware detection interstitials never block the main
+    // frame load, since they happen after the page is finished loading.
     case safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_PHISHING:
     case safe_browsing::SB_THREAT_TYPE_URL_CLIENT_SIDE_MALWARE:
-    case safe_browsing::SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING:
     // Ad sampling happens in the background.
     case safe_browsing::SB_THREAT_TYPE_AD_SAMPLE:
       return false;
diff --git a/components/security_interstitials/content/unsafe_resource.h b/components/security_interstitials/content/unsafe_resource.h
index fdb31b4..1df982f 100644
--- a/components/security_interstitials/content/unsafe_resource.h
+++ b/components/security_interstitials/content/unsafe_resource.h
@@ -68,7 +68,7 @@
   base::Callback<content::WebContents*(void)> web_contents_getter;
   safe_browsing::ThreatSource threat_source;
   // |token| field is only set if |threat_type| is
-  // SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING
+  // SB_THREAT_TYPE_PASSWORD_REUSE.
   std::string token;
 };
 
diff --git a/components/signin/core/browser/fake_signin_manager.cc b/components/signin/core/browser/fake_signin_manager.cc
index 104d8ea..1b2ac44 100644
--- a/components/signin/core/browser/fake_signin_manager.cc
+++ b/components/signin/core/browser/fake_signin_manager.cc
@@ -83,9 +83,10 @@
     observer.GoogleSigninFailed(error);
 }
 
-void FakeSigninManager::SignOut(
+void FakeSigninManager::DoSignOut(
     signin_metrics::ProfileSignout signout_source_metric,
-    signin_metrics::SignoutDelete signout_delete_metric) {
+    signin_metrics::SignoutDelete signout_delete_metric,
+    bool remove_all_accounts) {
   if (IsSignoutProhibited())
     return;
   set_auth_in_progress(std::string());
@@ -93,7 +94,7 @@
   const std::string account_id = GetAuthenticatedAccountId();
   const std::string username = GetAuthenticatedAccountInfo().email;
   authenticated_account_id_.clear();
-  if (token_service_)
+  if (token_service_ && remove_all_accounts)
     token_service_->RevokeAllCredentials();
 
   for (auto& observer : observer_list_)
diff --git a/components/signin/core/browser/fake_signin_manager.h b/components/signin/core/browser/fake_signin_manager.h
index b3943e0..b6ede8c58 100644
--- a/components/signin/core/browser/fake_signin_manager.h
+++ b/components/signin/core/browser/fake_signin_manager.h
@@ -57,11 +57,13 @@
       const std::string& password,
       const OAuthTokenFetchedCallback& oauth_fetched_callback) override;
 
-  void SignOut(signin_metrics::ProfileSignout signout_source_metric,
-               signin_metrics::SignoutDelete signout_delete_metric) override;
-
   void CompletePendingSignin() override;
 
+ protected:
+  void DoSignOut(signin_metrics::ProfileSignout signout_source_metric,
+                 signin_metrics::SignoutDelete signout_delete_metric,
+                 bool remove_all_accounts) override;
+
   // Username specified in StartSignInWithRefreshToken() call.
   std::string username_;
 
diff --git a/components/signin/core/browser/resources/signin_internals.js b/components/signin/core/browser/resources/signin_internals.js
index fb0f47c..38b02a3 100644
--- a/components/signin/core/browser/resources/signin_internals.js
+++ b/components/signin/core/browser/resources/signin_internals.js
@@ -168,6 +168,9 @@
     $('enableSyncButton').addEventListener('click', function(e) {
         chrome.send("enableSync");
     });
+    $('disableSyncButton').addEventListener('click', function(e) {
+        chrome.send("disableSync");
+    });
   }
 
   function refreshUI(signinInfo) {
diff --git a/components/signin/core/browser/signin_manager.cc b/components/signin/core/browser/signin_manager.cc
index 60f309fc..78d8148fc 100644
--- a/components/signin/core/browser/signin_manager.cc
+++ b/components/signin/core/browser/signin_manager.cc
@@ -18,6 +18,7 @@
 #include "components/signin/core/browser/signin_client.h"
 #include "components/signin/core/browser/signin_internals_util.h"
 #include "components/signin/core/browser/signin_metrics.h"
+#include "components/signin/core/common/profile_management_switches.h"
 #include "components/signin/core/common/signin_pref_names.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -153,15 +154,31 @@
 void SigninManager::SignOut(
     signin_metrics::ProfileSignout signout_source_metric,
     signin_metrics::SignoutDelete signout_delete_metric) {
-  client_->PreSignOut(
-      base::Bind(&SigninManager::DoSignOut, base::Unretained(this),
-                 signout_source_metric, signout_delete_metric),
-      signout_source_metric);
+  StartSignOut(signout_source_metric, signout_delete_metric,
+               !signin::IsAccountConsistencyDiceEnabled());
+}
+
+void SigninManager::SignOutAndRemoveAllAccounts(
+    signin_metrics::ProfileSignout signout_source_metric,
+    signin_metrics::SignoutDelete signout_delete_metric) {
+  StartSignOut(signout_source_metric, signout_delete_metric,
+               true /* remove_all_tokens */);
+}
+
+void SigninManager::StartSignOut(
+    signin_metrics::ProfileSignout signout_source_metric,
+    signin_metrics::SignoutDelete signout_delete_metric,
+    bool remove_all_accounts) {
+  client_->PreSignOut(base::Bind(&SigninManager::DoSignOut,
+                                 base::Unretained(this), signout_source_metric,
+                                 signout_delete_metric, remove_all_accounts),
+                      signout_source_metric);
 }
 
 void SigninManager::DoSignOut(
     signin_metrics::ProfileSignout signout_source_metric,
-    signin_metrics::SignoutDelete signout_delete_metric) {
+    signin_metrics::SignoutDelete signout_delete_metric,
+    bool remove_all_accounts) {
   DCHECK(IsInitialized());
 
   signin_metrics::LogSignout(signout_source_metric, signout_delete_metric);
@@ -210,9 +227,11 @@
   // Revoke all tokens before sending signed_out notification, because there
   // may be components that don't listen for token service events when the
   // profile is not connected to an account.
-  LOG(WARNING) << "Revoking refresh token on server. Reason: sign out, "
-               << "IsSigninAllowed: " << IsSigninAllowed();
-  token_service_->RevokeAllCredentials();
+  if (remove_all_accounts) {
+    LOG(WARNING) << "Revoking all refresh tokens on server. Reason: sign out, "
+                 << "IsSigninAllowed: " << IsSigninAllowed();
+    token_service_->RevokeAllCredentials();
+  }
 
   for (auto& observer : observer_list_)
     observer.GoogleSignedOut(account_id, username);
diff --git a/components/signin/core/browser/signin_manager.h b/components/signin/core/browser/signin_manager.h
index 7ec3c3f6..1bd3fa1 100644
--- a/components/signin/core/browser/signin_manager.h
+++ b/components/signin/core/browser/signin_manager.h
@@ -92,10 +92,22 @@
   // in-progress credentials to the new profile.
   virtual void CopyCredentialsFrom(const SigninManager& source);
 
-  // Sign a user out, removing the preference, erasing all keys
-  // associated with the user, and canceling all auth in progress.
-  virtual void SignOut(signin_metrics::ProfileSignout signout_source_metric,
-                       signin_metrics::SignoutDelete signout_delete_metric);
+  // Signs a user out, removing the preference, erasing all keys
+  // associated with the authenticated user, and canceling all auth in progress.
+  // On mobile and on desktop pre-DICE, this also removes all accounts from
+  // Chrome by revoking all refresh tokens.
+  // On desktop with DICE enabled, this will not remove all accounts from
+  // Chrome.
+  void SignOut(signin_metrics::ProfileSignout signout_source_metric,
+               signin_metrics::SignoutDelete signout_delete_metric);
+
+  // Signs a user out, removing the preference, erasing all keys
+  // associated with the authenticated user, and canceling all auth in progress.
+  // It removes removes all accounts from Chrome by revoking all refresh
+  // tokens.
+  void SignOutAndRemoveAllAccounts(
+      signin_metrics::ProfileSignout signout_source_metric,
+      signin_metrics::SignoutDelete signout_delete_metric);
 
   // On platforms where SigninManager is responsible for dealing with
   // invalid username policy updates, we need to check this during
@@ -151,7 +163,8 @@
 
   // The sign out process which is started by SigninClient::PreSignOut()
   virtual void DoSignOut(signin_metrics::ProfileSignout signout_source_metric,
-                         signin_metrics::SignoutDelete signout_delete_metric);
+                         signin_metrics::SignoutDelete signout_delete_metric,
+                         bool remove_all_accounts);
 
  private:
   enum SigninType {
@@ -208,6 +221,11 @@
   // transient signin data.
   void HandleAuthError(const GoogleServiceAuthError& error);
 
+  // Starts the sign out process.
+  void StartSignOut(signin_metrics::ProfileSignout signout_source_metric,
+                    signin_metrics::SignoutDelete signout_delete_metric,
+                    bool remove_all_accounts);
+
   void OnSigninAllowedPrefChanged();
   void OnGoogleServicesUsernamePatternChanged();
 
diff --git a/components/signin/core/browser/signin_metrics.h b/components/signin/core/browser/signin_metrics.h
index bcaa972..eb89d0868 100644
--- a/components/signin/core/browser/signin_metrics.h
+++ b/components/signin/core/browser/signin_metrics.h
@@ -48,6 +48,8 @@
   TRANSFER_CREDENTIALS,
   // Signed out because credentials are invalid and force-sign-in is enabled.
   AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN,
+  // The user disables sync from the DICE UI.
+  USER_TUNED_OFF_SYNC_FROM_DICE_UI,
   // Keep this as the last enum.
   NUM_PROFILE_SIGNOUT_METRICS,
 };
diff --git a/components/sync/user_events/user_event_sync_bridge.cc b/components/sync/user_events/user_event_sync_bridge.cc
index 4e97274..0039464 100644
--- a/components/sync/user_events/user_event_sync_bridge.cc
+++ b/components/sync/user_events/user_event_sync_bridge.cc
@@ -155,6 +155,14 @@
   if (!store_) {
     return;
   }
+  // TODO(skym): Remove this when the processor can handle Put() calls before
+  // being given metadata, see crbug.com/761485. Dropping data on the floor here
+  // is better than just writing to the store, because it will be lost if sent
+  // to just the store, and bloat persistent storage indefinitely.
+  if (!change_processor()->IsTrackingMetadata()) {
+    return;
+  }
+
   std::string storage_key = GetStorageKeyFromSpecifics(*specifics);
 
   // There are two scenarios we need to guard against here. First, the given
diff --git a/components/sync/user_events/user_event_sync_bridge_unittest.cc b/components/sync/user_events/user_event_sync_bridge_unittest.cc
index b5961464..47862ec 100644
--- a/components/sync/user_events/user_event_sync_bridge_unittest.cc
+++ b/components/sync/user_events/user_event_sync_bridge_unittest.cc
@@ -106,6 +106,12 @@
         &test_global_id_mapper_);
   }
 
+  ~UserEventSyncBridgeTest() override {
+    // Get[All]Data() calls are async, so this will run the verification they
+    // call in their callbacks.
+    base::RunLoop().RunUntilIdle();
+  }
+
   std::string GetStorageKey(const UserEventSpecifics& specifics) {
     EntityData entity_data;
     *entity_data.specifics.mutable_user_event() = specifics;
@@ -113,7 +119,7 @@
   }
 
   UserEventSyncBridge* bridge() { return bridge_.get(); }
-  const RecordingModelTypeChangeProcessor& processor() { return *processor_; }
+  RecordingModelTypeChangeProcessor* processor() { return processor_; }
   TestGlobalIdMapper* mapper() { return &test_global_id_mapper_; }
 
  private:
@@ -125,22 +131,27 @@
 
 TEST_F(UserEventSyncBridgeTest, MetadataIsInitialized) {
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(processor().metadata()->GetModelTypeState().initial_sync_done());
+  EXPECT_TRUE(processor()->metadata()->GetModelTypeState().initial_sync_done());
 }
 
 TEST_F(UserEventSyncBridgeTest, SingleRecord) {
   const UserEventSpecifics specifics(CreateSpecifics(1u, 2u, 3u));
   bridge()->RecordUserEvent(std::make_unique<UserEventSpecifics>(specifics));
-  EXPECT_EQ(1u, processor().put_multimap().size());
+  EXPECT_EQ(1u, processor()->put_multimap().size());
 
-  const std::string storage_key = processor().put_multimap().begin()->first;
+  const std::string storage_key = processor()->put_multimap().begin()->first;
   bridge()->GetData({storage_key}, VerifyCallback({{storage_key, specifics}}));
   bridge()->GetData({"bogus"}, base::Bind(&VerifyDataBatchCount, 0));
   bridge()->GetAllData(VerifyCallback({{storage_key, specifics}}));
 
   bridge()->DisableSync();
+
+  // Disabling deletes records through multiple round trips, if we quickly call
+  // GetAllData() we're going to beat the deletions to the storage task.
+  base::RunLoop().RunUntilIdle();
+
   bridge()->GetAllData(base::Bind(&VerifyDataBatchCount, 0));
-  EXPECT_EQ(0u, processor().delete_set().size());
+  EXPECT_EQ(0u, processor()->delete_set().size());
 }
 
 TEST_F(UserEventSyncBridgeTest, MultipleRecords) {
@@ -149,13 +160,13 @@
   bridge()->RecordUserEvent(SpecificsUniquePtr(1u, 2u, 2u));
   bridge()->RecordUserEvent(SpecificsUniquePtr(2u, 2u, 2u));
 
-  EXPECT_EQ(4u, processor().put_multimap().size());
+  EXPECT_EQ(4u, processor()->put_multimap().size());
   std::set<std::string> unique_storage_keys;
-  for (const auto& kv : processor().put_multimap()) {
+  for (const auto& kv : processor()->put_multimap()) {
     unique_storage_keys.insert(kv.first);
   }
   EXPECT_EQ(2u, unique_storage_keys.size());
-  bridge()->GetAllData(base::Bind(&VerifyDataBatchCount, 4));
+  bridge()->GetAllData(base::Bind(&VerifyDataBatchCount, 2));
 }
 
 TEST_F(UserEventSyncBridgeTest, ApplySyncChanges) {
@@ -163,7 +174,7 @@
   bridge()->RecordUserEvent(SpecificsUniquePtr(2u, 2u, 2u));
   bridge()->GetAllData(base::Bind(&VerifyDataBatchCount, 2));
 
-  const std::string storage_key = processor().put_multimap().begin()->first;
+  const std::string storage_key = processor()->put_multimap().begin()->first;
   auto error_on_delete =
       bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
                                  {EntityChange::CreateDelete(storage_key)});
@@ -179,17 +190,16 @@
 
   // This id update should be applied to the event as it is initially recorded.
   mapper()->ChangeId(first_id, second_id);
-  bridge()->RecordUserEvent(
-      std::make_unique<UserEventSpecifics>(CreateSpecifics(1u, first_id, 2u)));
-  const std::string storage_key = processor().put_multimap().begin()->first;
-  EXPECT_EQ(1u, processor().put_multimap().size());
+  bridge()->RecordUserEvent(SpecificsUniquePtr(1u, first_id, 2u));
+  const std::string storage_key = processor()->put_multimap().begin()->first;
+  EXPECT_EQ(1u, processor()->put_multimap().size());
   bridge()->GetAllData(
       VerifyCallback({{storage_key, CreateSpecifics(1u, second_id, 2u)}}));
 
   // This id update is done while the event is "in flight", and should result in
   // it being updated and re-sent to sync.
   mapper()->ChangeId(second_id, third_id);
-  EXPECT_EQ(2u, processor().put_multimap().size());
+  EXPECT_EQ(2u, processor()->put_multimap().size());
   bridge()->GetAllData(
       VerifyCallback({{storage_key, CreateSpecifics(1u, third_id, 2u)}}));
   auto error_on_delete =
@@ -201,7 +211,7 @@
   // This id update should be ignored, since we received commit confirmation
   // above.
   mapper()->ChangeId(third_id, fourth_id);
-  EXPECT_EQ(2u, processor().put_multimap().size());
+  EXPECT_EQ(2u, processor()->put_multimap().size());
   bridge()->GetAllData(base::Bind(&VerifyDataBatchCount, 0));
 }
 
@@ -237,6 +247,12 @@
                       {key3, CreateSpecifics(5u, fourth_id, 6u)}}));
 }
 
+TEST_F(UserEventSyncBridgeTest, RecordBeforeMetadataLoads) {
+  processor()->SetIsTrackingMetadata(false);
+  bridge()->RecordUserEvent(SpecificsUniquePtr(1u, 2u, 3u));
+  bridge()->GetAllData(VerifyCallback({}));
+}
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/ui_devtools/views/ui_devtools_dom_agent.cc b/components/ui_devtools/views/ui_devtools_dom_agent.cc
index 57a87ee9..ec162cd 100644
--- a/components/ui_devtools/views/ui_devtools_dom_agent.cc
+++ b/components/ui_devtools/views/ui_devtools_dom_agent.cc
@@ -236,6 +236,21 @@
                         render_text);
 }
 
+void DrawR1HorizontalFullLeftR2(const gfx::RectF& pinned_rect_f,
+                                const gfx::RectF& hovered_rect_f,
+                                const cc::PaintFlags& flags,
+                                gfx::Canvas* canvas,
+                                gfx::RenderText* render_text) {
+  // Horizontal left distance line.
+  float x1 = hovered_rect_f.right();
+  float y1 = hovered_rect_f.y() + hovered_rect_f.height() / 2;
+  float x2 = pinned_rect_f.x();
+  float y2 = y1;
+  canvas->DrawLine(gfx::PointF(x1, y1), gfx::PointF(x2, y2), flags);
+  DrawTextWithAnyBounds(x1, y1, x2, y2, RectSide::BOTTOM_SIDE, canvas,
+                        render_text);
+}
+
 }  // namespace
 
 UIDevToolsDOMAgent::UIDevToolsDOMAgent()
@@ -483,8 +498,12 @@
   flags.setPathEffect(0);
   flags.setColor(SK_ColorRED);
 
-  if (pinned_rect_f.Contains(hovered_rect_f))
+  // Make sure |pinned_rect_f| stays on the right or below of |hovered_rect_f|.
+  if (pinned_rect_.x() < hovered_rect_.x() ||
+      (pinned_rect_.x() == hovered_rect_.x() &&
+       pinned_rect_.y() < hovered_rect_.y())) {
     std::swap(pinned_rect_f, hovered_rect_f);
+  }
 
   switch (highlight_rect_config_) {
     case HighlightRectsConfiguration::R1_CONTAINS_R2:
@@ -492,7 +511,8 @@
                        render_text_.get());
       return;
     case HighlightRectsConfiguration::R1_HORIZONTAL_FULL_LEFT_R2:
-      NOTIMPLEMENTED();
+      DrawR1HorizontalFullLeftR2(pinned_rect_f, hovered_rect_f, flags, canvas,
+                                 render_text_.get());
       return;
     case HighlightRectsConfiguration::R1_TOP_FULL_LEFT_R2:
       NOTIMPLEMENTED();
diff --git a/components/ui_devtools/views/ui_devtools_unittest.cc b/components/ui_devtools/views/ui_devtools_unittest.cc
index 6dfd26455..f4213cf3 100644
--- a/components/ui_devtools/views/ui_devtools_unittest.cc
+++ b/components/ui_devtools/views/ui_devtools_unittest.cc
@@ -434,6 +434,46 @@
             HighlightRectsConfiguration::R1_CONTAINS_R2);
 }
 
+// Test case R1_HORIZONTAL_FULL_LEFT_R2.
+TEST_F(UIDevToolsTest, OneUIElementStaysHorizontalAndLeftOfAnother) {
+  const gfx::Rect outside_rect(1, 1, 50, 50);
+  std::unique_ptr<views::Widget> widget_outside(CreateTestWidget(outside_rect));
+
+  const gfx::Rect inside_rect(60, 1, 60, 60);
+  std::unique_ptr<views::Widget> widget_inside(CreateTestWidget(inside_rect));
+
+  std::unique_ptr<ui_devtools::protocol::DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int outside_rect_id = dom_agent()->FindElementIdTargetedByPoint(
+      outside_rect.origin(), GetPrimaryRootWindow());
+  int inside_rect_id = dom_agent()->FindElementIdTargetedByPoint(
+      inside_rect.origin(), GetPrimaryRootWindow());
+  dom_agent()->ShowDistancesInHighlightOverlay(outside_rect_id, inside_rect_id);
+
+  HighlightRectsConfiguration highlight_rect_config =
+      dom_agent()->highlight_rect_config();
+
+  // Swapping R1 and R2 shouldn't change |highlight_rect_config|.
+  dom_agent()->ShowDistancesInHighlightOverlay(inside_rect_id, outside_rect_id);
+  DCHECK_EQ(highlight_rect_config, dom_agent()->highlight_rect_config());
+
+  const std::pair<aura::Window*, gfx::Rect> element_outside(
+      dom_agent()
+          ->GetElementFromNodeId(outside_rect_id)
+          ->GetNodeWindowAndBounds());
+
+  const std::pair<aura::Window*, gfx::Rect> element_inside(
+      dom_agent()
+          ->GetElementFromNodeId(inside_rect_id)
+          ->GetNodeWindowAndBounds());
+
+  EXPECT_TRUE(element_outside.second == outside_rect);
+  EXPECT_TRUE(element_inside.second == inside_rect);
+  DCHECK_EQ(dom_agent()->highlight_rect_config(),
+            HighlightRectsConfiguration::R1_HORIZONTAL_FULL_LEFT_R2);
+}
+
 // Tests that the correct Overlay events are dispatched to the frontend when
 // hovering and clicking over a UI element in inspect mode.
 TEST_F(UIDevToolsTest, MouseEventsGenerateFEEventsInInspectMode) {
diff --git a/components/ukm/test_ukm_recorder.cc b/components/ukm/test_ukm_recorder.cc
index faab026..0a3fcd16a 100644
--- a/components/ukm/test_ukm_recorder.cc
+++ b/components/ukm/test_ukm_recorder.cc
@@ -58,6 +58,17 @@
 TestUkmRecorder::~TestUkmRecorder() {
 };
 
+std::set<ukm::SourceId> TestUkmRecorder::GetSourceIds() const {
+  std::set<ukm::SourceId> result;
+  for (const auto& kv : sources()) {
+    result.insert(kv.first);
+  }
+  for (const auto& it : entries()) {
+    result.insert(it->source_id);
+  }
+  return result;
+}
+
 const UkmSource* TestUkmRecorder::GetSourceForUrl(const char* url) const {
   const UkmSource* source = nullptr;
   for (const auto& kv : sources()) {
@@ -238,12 +249,19 @@
       << "Failed to find expected_values for metric: " << metric_name;
 }
 
+std::vector<int64_t> TestUkmRecorder::GetMetricValues(
+    ukm::SourceId source_id,
+    const char* event_name,
+    const char* metric_name) const {
+  mojom::UkmEntryPtr entry = GetMergedEntryForSourceID(source_id, event_name);
+  return GetValuesForMetric(entry.get(), metric_name);
+}
+
 std::vector<int64_t> TestUkmRecorder::GetMetrics(
     const UkmSource& source,
     const char* event_name,
     const char* metric_name) const {
-  mojom::UkmEntryPtr entry = GetMergedEntryForSourceID(source.id(), event_name);
-  return GetValuesForMetric(entry.get(), metric_name);
+  return GetMetricValues(source.id(), event_name, metric_name);
 }
 
 TestAutoSetUkmRecorder::TestAutoSetUkmRecorder() {
diff --git a/components/ukm/test_ukm_recorder.h b/components/ukm/test_ukm_recorder.h
index 1d9a506..26ed127f 100644
--- a/components/ukm/test_ukm_recorder.h
+++ b/components/ukm/test_ukm_recorder.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -26,10 +27,15 @@
   ~TestUkmRecorder() override;
 
   size_t sources_count() const { return sources().size(); }
+
+  // Get all SourceIds with any data associated with them.
+  std::set<ukm::SourceId> GetSourceIds() const;
+
   const std::map<ukm::SourceId, std::unique_ptr<UkmSource>>& GetSources()
       const {
     return sources();
   }
+
   const UkmSource* GetSourceForUrl(const char* url) const;
   std::vector<const ukm::UkmSource*> GetSourcesForUrl(const char* url) const;
   const UkmSource* GetSourceForSourceId(ukm::SourceId source_id) const;
@@ -74,6 +80,13 @@
                      const char* metric_name,
                      const std::vector<int64_t>& expected_values) const;
 
+  // Returns all recorded values of a metric for the given |source|,
+  // |event_name| and |metric_name|. The order of values is not specified.
+  std::vector<int64_t> GetMetricValues(ukm::SourceId source_id,
+                                       const char* event_name,
+                                       const char* metric_name) const;
+
+  // Deprecated.
   // Returns all collected metrics for the given |source|, |event_name| and
   // |metric_name|. The order of values is not specified.
   std::vector<int64_t> GetMetrics(const UkmSource& source,
diff --git a/components/viz/common/quads/shared_quad_state.cc b/components/viz/common/quads/shared_quad_state.cc
index 71eed58..9572ec4d 100644
--- a/components/viz/common/quads/shared_quad_state.cc
+++ b/components/viz/common/quads/shared_quad_state.cc
@@ -32,6 +32,7 @@
                              const gfx::Rect& visible_quad_layer_rect,
                              const gfx::Rect& clip_rect,
                              bool is_clipped,
+                             bool are_contents_opaque,
                              float opacity,
                              SkBlendMode blend_mode,
                              int sorting_context_id) {
@@ -40,6 +41,7 @@
   this->visible_quad_layer_rect = visible_quad_layer_rect;
   this->clip_rect = clip_rect;
   this->is_clipped = is_clipped;
+  this->are_contents_opaque = are_contents_opaque;
   this->opacity = opacity;
   this->blend_mode = blend_mode;
   this->sorting_context_id = sorting_context_id;
@@ -52,9 +54,9 @@
                                  visible_quad_layer_rect, value);
 
   value->SetBoolean("is_clipped", is_clipped);
-
   cc::MathUtil::AddToTracedValue("clip_rect", clip_rect, value);
 
+  value->SetBoolean("are_contents_opaque", are_contents_opaque);
   value->SetDouble("opacity", opacity);
   value->SetString("blend_mode", SkBlendMode_Name(blend_mode));
   TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
diff --git a/components/viz/common/quads/shared_quad_state.h b/components/viz/common/quads/shared_quad_state.h
index d1b0a97..9390b24 100644
--- a/components/viz/common/quads/shared_quad_state.h
+++ b/components/viz/common/quads/shared_quad_state.h
@@ -36,6 +36,7 @@
               const gfx::Rect& visible_layer_rect,
               const gfx::Rect& clip_rect,
               bool is_clipped,
+              bool are_contents_opaque,
               float opacity,
               SkBlendMode blend_mode,
               int sorting_context_id);
@@ -51,6 +52,8 @@
   // This rect lives in the target content space.
   gfx::Rect clip_rect;
   bool is_clipped;
+  // Indicates whether the quads share this sqs contains opaque content.
+  bool are_contents_opaque;
   float opacity;
   SkBlendMode blend_mode;
   int sorting_context_id;
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 7596843..ebbf55bd 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -2138,7 +2138,7 @@
   SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
                        gfx::Rect(viewport_size), gfx::Rect(viewport_size),
-                       false, 1, SkBlendMode::kSrcOver, 0);
+                       false, false, 1, SkBlendMode::kSrcOver, 0);
   overlay_quad->SetNew(shared_state, gfx::Rect(viewport_size),
                        gfx::Rect(viewport_size), needs_blending, resource_id,
                        premultiplied_alpha, uv_top_left, uv_bottom_right,
@@ -2339,7 +2339,7 @@
       gfx::RectF tex_coord_rect(0, 0, 1, 1);
       SharedQuadState* shared_state =
           root_pass->CreateAndAppendSharedQuadState();
-      shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1,
+      shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, false, 1,
                            SkBlendMode::kSrcOver, 0);
       cc::YUVVideoDrawQuad* quad =
           root_pass->CreateAndAppendDrawQuad<cc::YUVVideoDrawQuad>();
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 41604d70..746bd99 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -386,7 +386,7 @@
       /*quad_layer_rect=*/output_rect,
       /*visible_quad_layer_rect=*/output_rect,
       /*clip_rect=*/gfx::Rect(),
-      /*is_clipped=*/false, /*opacity=*/1.f,
+      /*is_clipped=*/false, /*are_contents_opaque=*/false, /*opacity=*/1.f,
       /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
 
   auto* quad =
@@ -418,6 +418,7 @@
   copy_shared_quad_state->SetAll(new_transform, source_sqs->quad_layer_rect,
                                  source_sqs->visible_quad_layer_rect,
                                  new_clip_rect.rect, new_clip_rect.is_clipped,
+                                 source_sqs->are_contents_opaque,
                                  source_sqs->opacity, source_sqs->blend_mode,
                                  source_sqs->sorting_context_id);
 
diff --git a/components/viz/service/display/surface_aggregator_pixeltest.cc b/components/viz/service/display/surface_aggregator_pixeltest.cc
index d6a54fd..03d1a9392 100644
--- a/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -55,11 +55,12 @@
   const gfx::Rect visible_layer_rect = gfx::Rect(size);
   const gfx::Rect clip_rect = gfx::Rect(size);
   bool is_clipped = false;
+  bool are_contents_opaque = false;
   float opacity = 1.f;
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   auto* shared_state = render_pass->CreateAndAppendSharedQuadState();
   shared_state->SetAll(transform, layer_rect, visible_layer_rect, clip_rect,
-                       is_clipped, opacity, blend_mode, 0);
+                       is_clipped, are_contents_opaque, opacity, blend_mode, 0);
   return shared_state;
 }
 
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 63bb8275..1f2bd50 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -228,12 +228,13 @@
     gfx::Rect visible_layer_rect = gfx::Rect(surface_size);
     gfx::Rect clip_rect = gfx::Rect(surface_size);
     bool is_clipped = false;
+    bool are_contents_opaque = false;
     SkBlendMode blend_mode = SkBlendMode::kSrcOver;
 
     auto* shared_quad_state = pass->CreateAndAppendSharedQuadState();
-    shared_quad_state->SetAll(layer_to_target_transform,
-                              gfx::Rect(layer_bounds), visible_layer_rect,
-                              clip_rect, is_clipped, opacity, blend_mode, 0);
+    shared_quad_state->SetAll(
+        layer_to_target_transform, gfx::Rect(layer_bounds), visible_layer_rect,
+        clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode, 0);
 
     cc::SurfaceDrawQuad* surface_quad =
         pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
@@ -260,7 +261,8 @@
     gfx::Rect output_rect = gfx::Rect(0, 0, 5, 5);
     auto* shared_state = pass->CreateAndAppendSharedQuadState();
     shared_state->SetAll(gfx::Transform(), output_rect, output_rect,
-                         output_rect, false, 1, SkBlendMode::kSrcOver, 0);
+                         output_rect, false, false, 1, SkBlendMode::kSrcOver,
+                         0);
     auto* quad = pass->CreateAndAppendDrawQuad<cc::RenderPassDrawQuad>();
     quad->SetNew(shared_state, output_rect, output_rect, render_pass_id, 0,
                  gfx::RectF(), gfx::Size(), gfx::Vector2dF(), gfx::PointF(),
@@ -1210,17 +1212,19 @@
   const gfx::Rect clip_rect(size);
 
   bool is_clipped = false;
+  SkColor color = SK_ColorGREEN;
+  bool are_contents_opaque = SkColorGetA(color) == 0xFF;
   float opacity = 1.f;
 
   bool force_anti_aliasing_off = false;
   auto* sqs = pass->CreateAndAppendSharedQuadState();
   sqs->SetAll(layer_to_target_transform, layer_rect, visible_layer_rect,
-              clip_rect, is_clipped, opacity, blend_mode, 0);
+              clip_rect, is_clipped, are_contents_opaque, opacity, blend_mode,
+              0);
 
   auto* color_quad = pass->CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>();
   color_quad->SetNew(pass->shared_quad_state_list.back(), visible_layer_rect,
-                     visible_layer_rect, SK_ColorGREEN,
-                     force_anti_aliasing_off);
+                     visible_layer_rect, color, force_anti_aliasing_off);
 }
 
 // This tests that we update shared quad state pointers correctly within
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
index 830ca2c..5bf5e79 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -39,8 +39,8 @@
     cc::CompositorFrame frame,
     mojom::HitTestRegionListPtr hit_test_region_list,
     uint64_t submit_time) {
-  // TODO(gklassen): Route hit-test data to the appropriate HitTestAggregator.
-  if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) {
+  if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame),
+                                       std::move(hit_test_region_list))) {
     compositor_frame_sink_binding_.CloseWithReason(
         1, "Surface invariants violation");
     OnClientConnectionLost();
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 48f767d..75079b9 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -134,7 +134,8 @@
 
 bool CompositorFrameSinkSupport::SubmitCompositorFrame(
     const LocalSurfaceId& local_surface_id,
-    cc::CompositorFrame frame) {
+    cc::CompositorFrame frame,
+    mojom::HitTestRegionListPtr hit_test_region_list) {
   TRACE_EVENT0("cc", "CompositorFrameSinkSupport::SubmitCompositorFrame");
   DCHECK(local_surface_id.is_valid());
   DCHECK(!frame.render_pass_list.empty());
@@ -158,6 +159,9 @@
     }
   }
 
+  frame_sink_manager()->SubmitHitTestRegionList(
+      current_surface_id_, frame_index, std::move(hit_test_region_list));
+
   Surface* prev_surface =
       surface_manager_->GetSurfaceForId(current_surface_id_);
   Surface* current_surface = nullptr;
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index 70d13c4..a6e01a1e 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -21,6 +21,7 @@
 #include "components/viz/service/frame_sinks/surface_resource_holder_client.h"
 #include "components/viz/service/surfaces/surface_client.h"
 #include "components/viz/service/viz_service_export.h"
+#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
 
 namespace {
 // The frame index starts at 2 so that empty frames will be treated as
@@ -72,8 +73,10 @@
   void EvictCurrentSurface();
   void SetNeedsBeginFrame(bool needs_begin_frame);
   void DidNotProduceFrame(const BeginFrameAck& ack);
-  bool SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
-                             cc::CompositorFrame frame);
+  bool SubmitCompositorFrame(
+      const LocalSurfaceId& local_surface_id,
+      cc::CompositorFrame frame,
+      mojom::HitTestRegionListPtr hit_test_region_list = nullptr);
   void RequestCopyOfSurface(std::unique_ptr<CopyOutputRequest> request);
 
   Surface* GetCurrentSurfaceForTesting();
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 111b3a70..6cc5b399 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -358,6 +358,14 @@
     client_->OnClientConnectionClosed(frame_sink_id);
 }
 
+void FrameSinkManagerImpl::SubmitHitTestRegionList(
+    const SurfaceId& surface_id,
+    uint64_t frame_index,
+    mojom::HitTestRegionListPtr hit_test_region_list) {
+  // TODO(gklassen): Route hit_test_region_list to appropriate
+  // matching RootCompositorFrameSink
+}
+
 void FrameSinkManagerImpl::OnAggregatedHitTestRegionListUpdated(
     const FrameSinkId& frame_sink_id,
     mojo::ScopedSharedBufferHandle active_handle,
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index a9d2364..eac01a7 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -139,6 +139,11 @@
   // by value avoids this.
   void DestroyCompositorFrameSink(FrameSinkId frame_sink_id);
 
+  void SubmitHitTestRegionList(
+      const SurfaceId& surface_id,
+      uint64_t frame_index,
+      mojom::HitTestRegionListPtr hit_test_region_list);
+
  private:
   friend class cc::test::SurfaceSynchronizationTest;
 
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index eb03cb1..fb780b9 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -83,8 +83,8 @@
     cc::CompositorFrame frame,
     mojom::HitTestRegionListPtr hit_test_region_list,
     uint64_t submit_time) {
-  // TODO(gklassen): send |hit_test_region_list| to |support_|.
-  if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) {
+  if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame),
+                                       std::move(hit_test_region_list))) {
     compositor_frame_sink_binding_.Close();
     OnClientConnectionLost();
   }
diff --git a/components/viz/test/surface_hittest_test_helpers.cc b/components/viz/test/surface_hittest_test_helpers.cc
index 6c9f69b..24df42cb 100644
--- a/components/viz/test/surface_hittest_test_helpers.cc
+++ b/components/viz/test/surface_hittest_test_helpers.cc
@@ -19,7 +19,7 @@
                            const gfx::Rect& root_rect) {
   SharedQuadState* child_shared_state = pass->CreateAndAppendSharedQuadState();
   child_shared_state->SetAll(transform, root_rect, root_rect, root_rect, false,
-                             1.0f, SkBlendMode::kSrcOver, 0);
+                             false, 1.0f, SkBlendMode::kSrcOver, 0);
 }
 
 void CreateSolidColorDrawQuad(cc::RenderPass* pass,
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 9776f7cf..0d32a38f 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -752,6 +752,8 @@
     "frame_host/interstitial_page_impl.h",
     "frame_host/interstitial_page_navigator_impl.cc",
     "frame_host/interstitial_page_navigator_impl.h",
+    "frame_host/keep_alive_handle_factory.cc",
+    "frame_host/keep_alive_handle_factory.h",
     "frame_host/mixed_content_navigation_throttle.cc",
     "frame_host/mixed_content_navigation_throttle.h",
     "frame_host/navigation_controller_android.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 8feb727..670e7255 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -14,7 +14,6 @@
   "+components/payments",
   "+components/profile_service",
   "+components/rappor/public",
-  "+components/scheduler/common",
   "+components/tracing",
   "+components/ukm",
   "+components/url_formatter",
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc
index 846ad2b6..fc0d733 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -70,6 +70,7 @@
     "maximumValue",
     "description",
     "default_action",
+    "action_name",
     "keyboard_shortcut",
     "location",
     "size",
@@ -271,6 +272,7 @@
   }
   temp_bstr.Reset();
 
+  // |get_accDefaultAction| returns a localized string.
   if (SUCCEEDED(ax_object->GetCOM()->get_accDefaultAction(
           variant_self, temp_bstr.Receive()))) {
     dict->SetString("default_action", base::string16(temp_bstr,
@@ -278,6 +280,14 @@
   }
   temp_bstr.Reset();
 
+  // |IAccessibleAction::get_name| returns a localized string.
+  if (SUCCEEDED(ax_object->GetCOM()->get_name(0 /* action_index */,
+                                              temp_bstr.Receive()))) {
+    dict->SetString("action_name",
+                    base::string16(temp_bstr, temp_bstr.Length()));
+  }
+  temp_bstr.Reset();
+
   if (SUCCEEDED(ax_object->GetCOM()->get_accKeyboardShortcut(
           variant_self, temp_bstr.Receive()))) {
     dict->SetString("keyboard_shortcut", base::string16(temp_bstr,
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index ec281af..ac0ffff 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -992,6 +992,28 @@
     return true;
   }
 
+  if (data.action == ui::AX_ACTION_SCROLL_TO_POINT) {
+    // target_point is in screen coordinates.  We need to convert this to frame
+    // coordinates because that's what BrowserAccessiblity cares about.
+    gfx::Point target =
+        data.target_point -
+        manager_->GetRootManager()->GetViewBounds().OffsetFromOrigin();
+
+    manager_->ScrollToPoint(*this, target);
+    return true;
+  }
+
+  if (data.action == ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE) {
+    // target_rect is in screen coordinates.  We need to convert this to frame
+    // coordinates because that's what BrowserAccessiblity cares about.
+    gfx::Rect target =
+        data.target_rect -
+        manager_->GetRootManager()->GetViewBounds().OffsetFromOrigin();
+
+    manager_->ScrollToMakeVisible(*this, target);
+    return true;
+  }
+
   return false;
 }
 
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index 5509626..556bed4 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -224,7 +224,11 @@
 }
 
 bool BrowserAccessibilityAndroid::IsEditableText() const {
-  return GetRole() == ui::AX_ROLE_TEXT_FIELD;
+  // TODO(dmazzoni): Use utility function in ax_role_properties, and
+  // handle different types of combo boxes correctly.
+  return GetRole() == ui::AX_ROLE_TEXT_FIELD ||
+         GetRole() == ui::AX_ROLE_SEARCH_BOX ||
+         GetRole() == ui::AX_ROLE_COMBO_BOX;
 }
 
 bool BrowserAccessibilityAndroid::IsEnabled() const {
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc
index 3a7d8db33..ca9b6138 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.cc
+++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -94,77 +94,7 @@
 }
 
 STDMETHODIMP BrowserAccessibilityComWin::scrollTo(IA2ScrollType scroll_type) {
-  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IA2_SCROLL_TO);
-  if (!owner())
-    return E_FAIL;
-
-  auto* manager = Manager();
-
-  if (!manager)
-    return E_FAIL;
-
-  gfx::Rect r = owner()->GetFrameBoundsRect();
-  switch (scroll_type) {
-    case IA2_SCROLL_TYPE_TOP_LEFT:
-      manager->ScrollToMakeVisible(*owner(), gfx::Rect(r.x(), r.y(), 0, 0));
-      break;
-    case IA2_SCROLL_TYPE_BOTTOM_RIGHT:
-      manager->ScrollToMakeVisible(*owner(),
-                                   gfx::Rect(r.right(), r.bottom(), 0, 0));
-      break;
-    case IA2_SCROLL_TYPE_TOP_EDGE:
-      manager->ScrollToMakeVisible(*owner(),
-                                   gfx::Rect(r.x(), r.y(), r.width(), 0));
-      break;
-    case IA2_SCROLL_TYPE_BOTTOM_EDGE:
-      manager->ScrollToMakeVisible(*owner(),
-                                   gfx::Rect(r.x(), r.bottom(), r.width(), 0));
-      break;
-    case IA2_SCROLL_TYPE_LEFT_EDGE:
-      manager->ScrollToMakeVisible(*owner(),
-                                   gfx::Rect(r.x(), r.y(), 0, r.height()));
-      break;
-    case IA2_SCROLL_TYPE_RIGHT_EDGE:
-      manager->ScrollToMakeVisible(*owner(),
-                                   gfx::Rect(r.right(), r.y(), 0, r.height()));
-      break;
-    case IA2_SCROLL_TYPE_ANYWHERE:
-    default:
-      manager->ScrollToMakeVisible(*owner(), r);
-      break;
-  }
-
-  return S_OK;
-}
-
-STDMETHODIMP BrowserAccessibilityComWin::scrollToPoint(
-    IA2CoordinateType coordinate_type,
-    LONG x,
-    LONG y) {
-  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SCROLL_TO_POINT);
-  if (!owner())
-    return E_FAIL;
-
-  auto* manager = Manager();
-  if (!manager)
-    return E_FAIL;
-
-  gfx::Point scroll_to(x, y);
-
-  if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
-    scroll_to -= manager->GetViewBounds().OffsetFromOrigin();
-  } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
-    if (owner()->PlatformGetParent()) {
-      scroll_to +=
-          owner()->PlatformGetParent()->GetFrameBoundsRect().OffsetFromOrigin();
-    }
-  } else {
-    return E_INVALIDARG;
-  }
-
-  manager->ScrollToPoint(*owner(), scroll_to);
-
-  return S_OK;
+  return AXPlatformNodeWin::scrollTo(scroll_type);
 }
 
 //
@@ -314,7 +244,7 @@
   if (!n_characters)
     return E_INVALIDARG;
 
-  *n_characters = static_cast<LONG>(owner()->GetText().size());
+  *n_characters = static_cast<LONG>(GetText().size());
   return S_OK;
 }
 
@@ -356,7 +286,7 @@
   if (!out_x || !out_y || !out_width || !out_height)
     return E_INVALIDARG;
 
-  const base::string16& text_str = owner()->GetText();
+  const base::string16& text_str = GetText();
   HandleSpecialTextOffset(&offset);
   if (offset < 0 || offset > static_cast<LONG>(text_str.size()))
     return E_INVALIDARG;
@@ -445,7 +375,7 @@
   if (!text)
     return E_INVALIDARG;
 
-  const base::string16& text_str = owner()->GetText();
+  const base::string16& text_str = GetText();
   HandleSpecialTextOffset(&start_offset);
   HandleSpecialTextOffset(&end_offset);
 
@@ -498,7 +428,7 @@
   if (offset < 0)
     return E_INVALIDARG;
 
-  const base::string16& text_str = owner()->GetText();
+  const base::string16& text_str = GetText();
   LONG text_len = text_str.length();
   if (offset > text_len)
     return E_INVALIDARG;
@@ -542,7 +472,7 @@
   *end_offset = 0;
   *text = NULL;
 
-  const base::string16& text_str = owner()->GetText();
+  const base::string16& text_str = GetText();
   LONG text_len = text_str.length();
   if (offset > text_len)
     return E_INVALIDARG;
@@ -576,7 +506,7 @@
   *end_offset = 0;
   *text = NULL;
 
-  const base::string16& text_str = owner()->GetText();
+  const base::string16& text_str = GetText();
   LONG text_len = text_str.length();
   if (offset > text_len)
     return E_INVALIDARG;
@@ -608,7 +538,7 @@
   if (new_len == 0)
     return E_FAIL;
 
-  base::string16 substr = owner()->GetText().substr(start, new_len);
+  base::string16 substr = GetText().substr(start, new_len);
   new_text->text = SysAllocString(substr.c_str());
   new_text->start = static_cast<long>(start);
   new_text->end = static_cast<long>(start + new_len);
@@ -632,7 +562,7 @@
   if (old_len == 0)
     return E_FAIL;
 
-  base::string16 old_hypertext = old_win_attributes_->hypertext;
+  base::string16 old_hypertext = old_hypertext_;
   base::string16 substr = old_hypertext.substr(start, old_len);
   old_text->text = SysAllocString(substr.c_str());
   old_text->start = static_cast<long>(start);
@@ -765,7 +695,7 @@
   if (!owner())
     return E_FAIL;
 
-  const base::string16 text = owner()->GetText();
+  const base::string16 text = GetText();
   HandleSpecialTextOffset(&offset);
   if (offset < 0 || offset > static_cast<LONG>(text.size()))
     return E_INVALIDARG;
@@ -803,7 +733,7 @@
   if (!hyperlink_count)
     return E_INVALIDARG;
 
-  *hyperlink_count = hyperlink_offset_to_index().size();
+  *hyperlink_count = hyperlink_offset_to_index_.size();
   return S_OK;
 }
 
@@ -816,11 +746,11 @@
     return E_FAIL;
 
   if (!hyperlink || index < 0 ||
-      index >= static_cast<long>(hyperlinks().size())) {
+      index >= static_cast<long>(hyperlinks_.size())) {
     return E_INVALIDARG;
   }
 
-  int32_t id = hyperlinks()[index];
+  int32_t id = hyperlinks_[index];
   auto* link = static_cast<BrowserAccessibilityComWin*>(
       AXPlatformNodeWin::GetFromUniqueId(id));
   if (!link)
@@ -841,14 +771,13 @@
   if (!hyperlink_index)
     return E_INVALIDARG;
 
-  if (char_index < 0 ||
-      char_index >= static_cast<long>(owner()->GetText().size())) {
+  if (char_index < 0 || char_index >= static_cast<long>(GetText().size())) {
     return E_INVALIDARG;
   }
 
   std::map<int32_t, int32_t>::iterator it =
-      hyperlink_offset_to_index().find(char_index);
-  if (it == hyperlink_offset_to_index().end()) {
+      hyperlink_offset_to_index_.find(char_index);
+  if (it == hyperlink_offset_to_index_.end()) {
     *hyperlink_index = -1;
     return S_FALSE;
   }
@@ -873,7 +802,7 @@
   if (index != 0 || !anchor)
     return E_INVALIDARG;
 
-  BSTR ia2_hypertext = SysAllocString(owner()->GetText().c_str());
+  BSTR ia2_hypertext = SysAllocString(GetText().c_str());
   DCHECK(ia2_hypertext);
   anchor->vt = VT_BSTR;
   anchor->bstrVal = ia2_hypertext;
@@ -1627,8 +1556,7 @@
   if (!out_x || !out_y || !out_width || !out_height)
     return E_INVALIDARG;
 
-  unsigned int text_length =
-      static_cast<unsigned int>(owner()->GetText().size());
+  unsigned int text_length = static_cast<unsigned int>(GetText().size());
   if (start_index > text_length || end_index > text_length ||
       start_index > end_index) {
     return E_INVALIDARG;
@@ -1656,8 +1584,7 @@
   if (!manager)
     return E_FAIL;
 
-  unsigned int text_length =
-      static_cast<unsigned int>(owner()->GetText().size());
+  unsigned int text_length = static_cast<unsigned int>(GetText().size());
   if (start_index > text_length || end_index > text_length ||
       start_index > end_index) {
     return E_INVALIDARG;
@@ -1932,7 +1859,7 @@
     }
 
     if (child->owner()->IsTextOnlyObject())
-      start_offset += child->owner()->GetText().length();
+      start_offset += child->GetText().length();
     else
       start_offset += 1;
   }
@@ -1966,6 +1893,16 @@
   // exactly what changed and fire appropriate events. Note that
   // old_win_attributes_ is cleared at the end of UpdateStep3FireEvents.
   old_win_attributes_.swap(win_attributes_);
+
+  old_hyperlinks_.swap(hyperlinks_);
+  hyperlinks_.clear();
+
+  old_hyperlink_offset_to_index_.swap(hyperlink_offset_to_index_);
+  hyperlink_offset_to_index_.clear();
+
+  old_hypertext_.swap(hypertext_);
+  hypertext_.clear();
+
   win_attributes_.reset(new WinAttributes());
 
   win_attributes_->ia_role = MSAARole();
@@ -2008,7 +1945,7 @@
 
 void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() {
   if (owner()->IsSimpleTextControl()) {
-    win_attributes_->hypertext = value();
+    hypertext_ = value();
     return;
   }
 
@@ -2017,7 +1954,7 @@
       // We don't want to expose any associated label in IA2 Hypertext.
       return;
     }
-    win_attributes_->hypertext = name();
+    hypertext_ = name();
     return;
   }
 
@@ -2031,14 +1968,14 @@
     DCHECK(child);
     // Similar to Firefox, we don't expose text-only objects in IA2 hypertext.
     if (child->owner()->IsTextOnlyObject()) {
-      win_attributes_->hypertext += child->name();
+      hypertext_ += child->name();
     } else {
-      int32_t char_offset = static_cast<int32_t>(owner()->GetText().size());
+      int32_t char_offset = static_cast<int32_t>(GetText().size());
       int32_t child_unique_id = child->unique_id();
-      int32_t index = hyperlinks().size();
-      win_attributes_->hyperlink_offset_to_index[char_offset] = index;
-      win_attributes_->hyperlinks.push_back(child_unique_id);
-      win_attributes_->hypertext += kEmbeddedCharacter;
+      int32_t index = hyperlinks_.size();
+      hyperlink_offset_to_index_[char_offset] = index;
+      hyperlinks_.push_back(child_unique_id);
+      hypertext_ += kEmbeddedCharacter;
     }
   }
 }
@@ -2125,6 +2062,9 @@
   }
 
   old_win_attributes_.reset(nullptr);
+  old_hyperlinks_.clear();
+  old_hyperlink_offset_to_index_.clear();
+  old_hypertext_.clear();
 }
 
 BrowserAccessibilityManager* BrowserAccessibilityComWin::Manager() const {
@@ -2373,7 +2313,7 @@
           spelling_attributes[start_offset + attribute.first] =
               std::move(attribute.second);
         }
-        start_offset += static_cast<int>(text_win->owner()->GetText().length());
+        start_offset += static_cast<int>(text_win->GetText().length());
       }
     }
   }
@@ -2462,16 +2402,16 @@
 }
 
 BrowserAccessibilityComWin*
-BrowserAccessibilityComWin::GetHyperlinkFromHypertextOffset(int offset) const {
+BrowserAccessibilityComWin::GetHyperlinkFromHypertextOffset(int offset) {
   std::map<int32_t, int32_t>::iterator iterator =
-      hyperlink_offset_to_index().find(offset);
-  if (iterator == hyperlink_offset_to_index().end())
+      hyperlink_offset_to_index_.find(offset);
+  if (iterator == hyperlink_offset_to_index_.end())
     return nullptr;
 
   int32_t index = iterator->second;
   DCHECK_GE(index, 0);
-  DCHECK_LT(index, static_cast<int32_t>(hyperlinks().size()));
-  int32_t id = hyperlinks()[index];
+  DCHECK_LT(index, static_cast<int32_t>(hyperlinks_.size()));
+  int32_t id = hyperlinks_[index];
   auto* hyperlink = static_cast<BrowserAccessibilityComWin*>(
       AXPlatformNodeWin::GetFromUniqueId(id));
   if (!hyperlink)
@@ -2481,20 +2421,20 @@
 
 int32_t BrowserAccessibilityComWin::GetHyperlinkIndexFromChild(
     const BrowserAccessibilityComWin& child) const {
-  if (hyperlinks().empty())
+  if (hyperlinks_.empty())
     return -1;
 
   auto iterator =
-      std::find(hyperlinks().begin(), hyperlinks().end(), child.unique_id());
-  if (iterator == hyperlinks().end())
+      std::find(hyperlinks_.begin(), hyperlinks_.end(), child.unique_id());
+  if (iterator == hyperlinks_.end())
     return -1;
 
-  return static_cast<int32_t>(iterator - hyperlinks().begin());
+  return static_cast<int32_t>(iterator - hyperlinks_.begin());
 }
 
 int32_t BrowserAccessibilityComWin::GetHypertextOffsetFromHyperlinkIndex(
     int32_t hyperlink_index) const {
-  for (auto& offset_index : hyperlink_offset_to_index()) {
+  for (auto& offset_index : hyperlink_offset_to_index_) {
     if (offset_index.second == hyperlink_index)
       return offset_index.first;
   }
@@ -2518,11 +2458,11 @@
     DCHECK_LT(index_in_parent,
               static_cast<int32_t>(owner()->InternalChildCount()));
     for (uint32_t i = 0; i < static_cast<uint32_t>(index_in_parent); ++i) {
-      const BrowserAccessibilityComWin* sibling =
+      BrowserAccessibilityComWin* sibling =
           ToBrowserAccessibilityComWin(owner()->InternalGetChild(i));
       DCHECK(sibling);
       if (sibling->owner()->IsTextOnlyObject())
-        hypertextOffset += sibling->owner()->GetText().size();
+        hypertextOffset += sibling->GetText().size();
       else
         ++hypertextOffset;
     }
@@ -2537,7 +2477,7 @@
 }
 
 int32_t BrowserAccessibilityComWin::GetHypertextOffsetFromDescendant(
-    const BrowserAccessibilityComWin& descendant) const {
+    const BrowserAccessibilityComWin& descendant) {
   auto* parent_object =
       ToBrowserAccessibilityComWin(descendant.owner()->PlatformGetParent());
   auto* current_object = const_cast<BrowserAccessibilityComWin*>(&descendant);
@@ -2554,7 +2494,7 @@
 
 int BrowserAccessibilityComWin::GetHypertextOffsetFromEndpoint(
     const BrowserAccessibilityComWin& endpoint_object,
-    int endpoint_offset) const {
+    int endpoint_offset) {
   // There are three cases:
   // 1. Either the selection endpoint is inside this object or is an ancestor of
   // of this object. endpoint_offset should be returned.
@@ -2618,15 +2558,15 @@
   if (endpoint_index_in_common_parent < index_in_common_parent)
     return 0;
   if (endpoint_index_in_common_parent > index_in_common_parent)
-    return owner()->GetText().size();
+    return GetText().size();
 
   NOTREACHED();
   return -1;
 }
 
-int BrowserAccessibilityComWin::GetSelectionAnchor() const {
+int BrowserAccessibilityComWin::GetSelectionAnchor() {
   int32_t anchor_id = Manager()->GetTreeData().sel_anchor_object_id;
-  const BrowserAccessibilityComWin* anchor_object = GetFromID(anchor_id);
+  BrowserAccessibilityComWin* anchor_object = GetFromID(anchor_id);
   if (!anchor_object)
     return -1;
 
@@ -2634,9 +2574,9 @@
   return GetHypertextOffsetFromEndpoint(*anchor_object, anchor_offset);
 }
 
-int BrowserAccessibilityComWin::GetSelectionFocus() const {
+int BrowserAccessibilityComWin::GetSelectionFocus() {
   int32_t focus_id = Manager()->GetTreeData().sel_focus_object_id;
-  const BrowserAccessibilityComWin* focus_object = GetFromID(focus_id);
+  BrowserAccessibilityComWin* focus_object = GetFromID(focus_id);
   if (!focus_object)
     return -1;
 
@@ -2645,7 +2585,7 @@
 }
 
 void BrowserAccessibilityComWin::GetSelectionOffsets(int* selection_start,
-                                                     int* selection_end) const {
+                                                     int* selection_end) {
   DCHECK(selection_start && selection_end);
 
   if (owner()->IsSimpleTextControl() &&
@@ -2704,8 +2644,8 @@
 
   // For anything other than the "embedded character", we just compare the
   // characters directly.
-  base::char16 old_ch = old_win_attributes_->hypertext[old_char_index];
-  base::char16 new_ch = win_attributes_->hypertext[new_char_index];
+  base::char16 old_ch = old_hypertext_[old_char_index];
+  base::char16 new_ch = hypertext_[new_char_index];
   if (old_ch != new_ch)
     return false;
   if (old_ch == new_ch && new_ch != kEmbeddedCharacter)
@@ -2714,21 +2654,20 @@
   // If it's an embedded character, they're only identical if the child id
   // the hyperlink points to is the same.
   std::map<int32_t, int32_t>& old_offset_to_index =
-      old_win_attributes_->hyperlink_offset_to_index;
-  std::vector<int32_t>& old_hyperlinks = old_win_attributes_->hyperlinks;
+      old_hyperlink_offset_to_index_;
+  std::vector<int32_t>& old_hyperlinks = old_hyperlinks_;
   int32_t old_hyperlinks_count = static_cast<int32_t>(old_hyperlinks.size());
   std::map<int32_t, int32_t>::iterator iter;
-  iter = old_offset_to_index.find(old_char_index);
+  iter = old_offset_to_index.find((int32_t)old_char_index);
   int old_index = (iter != old_offset_to_index.end()) ? iter->second : -1;
   int old_child_id = (old_index >= 0 && old_index < old_hyperlinks_count)
                          ? old_hyperlinks[old_index]
                          : -1;
 
-  std::map<int32_t, int32_t>& new_offset_to_index =
-      win_attributes_->hyperlink_offset_to_index;
-  std::vector<int32_t>& new_hyperlinks = win_attributes_->hyperlinks;
+  std::map<int32_t, int32_t>& new_offset_to_index = hyperlink_offset_to_index_;
+  std::vector<int32_t>& new_hyperlinks = hyperlinks_;
   int32_t new_hyperlinks_count = static_cast<int32_t>(new_hyperlinks.size());
-  iter = new_offset_to_index.find(new_char_index);
+  iter = new_offset_to_index.find((int32_t)new_char_index);
   int new_index = (iter != new_offset_to_index.end()) ? iter->second : -1;
   int new_child_id = (new_index >= 0 && new_index < new_hyperlinks_count)
                          ? new_hyperlinks[new_index]
@@ -2747,8 +2686,8 @@
   *old_len = 0;
   *new_len = 0;
 
-  const base::string16& old_text = old_win_attributes_->hypertext;
-  const base::string16& new_text = owner()->GetText();
+  const base::string16& old_text = old_hypertext_;
+  const base::string16& new_text = GetText();
 
   size_t common_prefix = 0;
   while (common_prefix < old_text.size() && common_prefix < new_text.size() &&
@@ -2771,7 +2710,7 @@
 
 void BrowserAccessibilityComWin::HandleSpecialTextOffset(LONG* offset) {
   if (*offset == IA2_TEXT_OFFSET_LENGTH) {
-    *offset = static_cast<LONG>(owner()->GetText().length());
+    *offset = static_cast<LONG>(GetText().length());
   } else if (*offset == IA2_TEXT_OFFSET_CARET) {
     // We shouldn't call |get_caretOffset| here as it affects UMA counts.
     int selection_start, selection_end;
@@ -2857,14 +2796,14 @@
   // TODO(nektar): |AXPosition| can handle other types of boundaries as well.
   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
   return ui::FindAccessibleTextBoundary(
-      owner()->GetText(), owner()->GetLineStartOffsets(), boundary,
-      start_offset, direction, affinity);
+      GetText(), owner()->GetLineStartOffsets(), boundary, start_offset,
+      direction, affinity);
 }
 
 LONG BrowserAccessibilityComWin::FindStartOfStyle(
     LONG start_offset,
-    ui::TextBoundaryDirection direction) const {
-  LONG text_length = static_cast<LONG>(owner()->GetText().length());
+    ui::TextBoundaryDirection direction) {
+  LONG text_length = static_cast<LONG>(GetText().length());
   DCHECK_GE(start_offset, 0);
   DCHECK_LE(start_offset, text_length);
 
diff --git a/content/browser/accessibility/browser_accessibility_com_win.h b/content/browser/accessibility/browser_accessibility_com_win.h
index 585da1d9..920cd630 100644
--- a/content/browser/accessibility/browser_accessibility_com_win.h
+++ b/content/browser/accessibility/browser_accessibility_com_win.h
@@ -102,11 +102,6 @@
 
   CONTENT_EXPORT STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type) override;
 
-  CONTENT_EXPORT STDMETHODIMP
-  scrollToPoint(enum IA2CoordinateType coordinate_type,
-                LONG x,
-                LONG y) override;
-
   //
   // IAccessibleApplication methods.
   //
@@ -442,13 +437,6 @@
   base::string16 description() const { return win_attributes_->description; }
   base::string16 value() const { return win_attributes_->value; }
 
-  std::map<int32_t, int32_t>& hyperlink_offset_to_index() const {
-    return win_attributes_->hyperlink_offset_to_index;
-  }
-  std::vector<int32_t>& hyperlinks() const {
-    return win_attributes_->hyperlinks;
-  }
-
   // Setter and getter for the browser accessibility owner
   BrowserAccessibilityWin* owner() const { return owner_; }
   void SetOwner(BrowserAccessibilityWin* owner) { owner_ = owner; }
@@ -509,7 +497,7 @@
   bool IsHyperlink() const;
   // Returns the hyperlink at the given text position, or nullptr if no
   // hyperlink can be found.
-  BrowserAccessibilityComWin* GetHyperlinkFromHypertextOffset(int offset) const;
+  BrowserAccessibilityComWin* GetHyperlinkFromHypertextOffset(int offset);
 
   // Functions for retrieving offsets for hyperlinks and hypertext.
   // Return -1 in case of failure.
@@ -518,7 +506,7 @@
   int32_t GetHypertextOffsetFromHyperlinkIndex(int32_t hyperlink_index) const;
   int32_t GetHypertextOffsetFromChild(BrowserAccessibilityComWin& child);
   int32_t GetHypertextOffsetFromDescendant(
-      const BrowserAccessibilityComWin& descendant) const;
+      const BrowserAccessibilityComWin& descendant);
 
   // If the selection endpoint is either equal to or an ancestor of this object,
   // returns endpoint_offset.
@@ -529,7 +517,7 @@
   // cannot be found in the accessibility tree.
   int GetHypertextOffsetFromEndpoint(
       const BrowserAccessibilityComWin& endpoint_object,
-      int endpoint_offset) const;
+      int endpoint_offset);
 
   //
   // Selection helper functions.
@@ -538,15 +526,14 @@
   // First they check for a local selection found on the current control, e.g.
   // when querying the selection on a textarea.
   // If not found they retrieve the global selection found on the current frame.
-  int GetSelectionAnchor() const;
-  int GetSelectionFocus() const;
+  int GetSelectionAnchor();
+  int GetSelectionFocus();
   // Retrieves the selection offsets in the way required by the IA2 APIs.
   // selection_start and selection_end are -1 when there is no selection active
   // on this object.
   // The greatest of the two offsets is one past the last character of the
   // selection.)
-  void GetSelectionOffsets(int* selection_start, int* selection_end) const;
-
+  void GetSelectionOffsets(int* selection_start, int* selection_end);
 
   bool IsSameHypertextCharacter(size_t old_char_index, size_t new_char_index);
   void ComputeHypertextRemovedAndInserted(int* start,
@@ -570,8 +557,7 @@
   // Searches forward from the given offset until the start of the next style
   // is found, or searches backward from the given offset until the start of the
   // current style is found.
-  LONG FindStartOfStyle(LONG start_offset,
-                        ui::TextBoundaryDirection direction) const;
+  LONG FindStartOfStyle(LONG start_offset, ui::TextBoundaryDirection direction);
 
   // ID refers to the node ID in the current tree, not the globally unique ID.
   // TODO(nektar): Could we use globally unique IDs everywhere?
@@ -605,21 +591,8 @@
     // IAccessible2 attributes.
     std::vector<base::string16> ia2_attributes;
 
-    // Hypertext.
-    base::string16 hypertext;
-
     // Maps each style span to its start offset in hypertext.
     std::map<int, std::vector<base::string16>> offset_to_text_attributes;
-
-    // Maps an embedded character offset in |hypertext_| to an index in
-    // |hyperlinks_|.
-    std::map<int32_t, int32_t> hyperlink_offset_to_index;
-
-    // The unique id of a BrowserAccessibilityComWin for each hyperlink.
-    // TODO(nektar): Replace object IDs with child indices if we decide that
-    // we are not implementing IA2 hyperlinks for anything other than IA2
-    // Hypertext.
-    std::vector<int32_t> hyperlinks;
   };
 
   BrowserAccessibilityWin* owner_;
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index 7bbc722e..284c4019 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -65,7 +65,14 @@
 
 BrowserAccessibility* BrowserAccessibilityManagerAndroid::GetFocus() {
   BrowserAccessibility* focus = BrowserAccessibilityManager::GetFocus();
-  return GetActiveDescendant(focus);
+  BrowserAccessibilityAndroid* android_focus =
+      static_cast<BrowserAccessibilityAndroid*>(focus);
+  // This is a temporary workaround because we're not distinguishing
+  // between text fields with a role of combobox, and pop-up menu buttons.
+  // TODO(dmazzoni): Handle different types of combo boxes correctly.
+  if (!android_focus->IsEditableText())
+    return GetActiveDescendant(focus);
+  return focus;
 }
 
 void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index 604c4f9..5b1585a 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -53,9 +53,7 @@
 }
 
 base::string16 BrowserAccessibilityWin::GetText() const {
-  if (PlatformIsChildOfLeaf())
-    return BrowserAccessibility::GetText();
-  return GetCOM()->win_attributes_->hypertext;
+  return GetCOM()->AXPlatformNodeWin::GetText();
 }
 
 gfx::NativeViewAccessible BrowserAccessibilityWin::GetNativeViewAccessible() {
diff --git a/content/browser/android/overscroll_controller_android.cc b/content/browser/android/overscroll_controller_android.cc
index a0885e4..2a3201d 100644
--- a/content/browser/android/overscroll_controller_android.cc
+++ b/content/browser/android/overscroll_controller_android.cc
@@ -214,8 +214,9 @@
       refresh_effect_) {
     // The effect should only be allowed if both the causal touch events go
     // unconsumed and the generated scroll events go unconsumed.
-    if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED ||
-        event.data.scroll_update.previous_update_in_sequence_prevented) {
+    if (refresh_effect_->IsAwaitingScrollUpdateAck() &&
+        (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED ||
+         event.data.scroll_update.previous_update_in_sequence_prevented)) {
       refresh_effect_->Reset();
     }
   }
diff --git a/content/browser/android/overscroll_controller_android_unittest.cc b/content/browser/android/overscroll_controller_android_unittest.cc
index a48d6e4..7db0123 100644
--- a/content/browser/android/overscroll_controller_android_unittest.cc
+++ b/content/browser/android/overscroll_controller_android_unittest.cc
@@ -9,10 +9,13 @@
 #include "cc/layers/layer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebGestureEvent.h"
+#include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "ui/android/overscroll_glow.h"
 #include "ui/android/overscroll_refresh.h"
 #include "ui/android/resources/resource_manager_impl.h"
 #include "ui/android/window_android_compositor.h"
+#include "ui/events/base_event_utils.h"
 #include "ui/events/blink/did_overscroll_params.h"
 
 using ui::EdgeEffectBase;
@@ -178,6 +181,30 @@
   testing::Mock::VerifyAndClearExpectations(glow_);
 }
 
+TEST_F(OverscrollControllerAndroidUnitTest,
+       ConsumedUpdateDoesNotResetEnabledRefresh) {
+  ui::DidOverscrollParams params = CreateVerticalOverscrollParams();
+  params.scroll_boundary_behavior.y = cc::ScrollBoundaryBehavior::
+      ScrollBoundaryBehaviorType::kScrollBoundaryBehaviorTypeAuto;
+
+  EXPECT_CALL(*refresh_, OnOverscrolled());
+  EXPECT_CALL(*refresh_, IsActive()).WillOnce(Return(true));
+  EXPECT_CALL(*refresh_, IsAwaitingScrollUpdateAck()).WillOnce(Return(false));
+  EXPECT_CALL(*refresh_, Reset()).Times(0);
+
+  // Enable the refresh effect.
+  controller_->OnOverscrolled(params);
+
+  // Generate a consumed scroll update.
+  blink::WebGestureEvent event(
+      blink::WebInputEvent::kGestureScrollUpdate,
+      blink::WebInputEvent::kNoModifiers,
+      ui::EventTimeStampToSeconds(ui::EventTimeForNow()));
+  controller_->OnGestureEventAck(event, INPUT_EVENT_ACK_STATE_CONSUMED);
+
+  testing::Mock::VerifyAndClearExpectations(&refresh_);
+}
+
 }  // namespace
 
 }  // namespace content
\ No newline at end of file
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index 45c16feb..f8c39ae 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -201,6 +201,7 @@
   SWDH_PROVIDER_CREATED_ILLEGAL_TYPE_CONTROLLER = 175,
   SWDH_PROVIDER_CREATED_DUPLICATE_ID = 176,
   SWDH_PROVIDER_CREATED_BAD_ID = 177,
+  RFH_KEEP_ALIVE_HANDLE_REQUESTED_INCORRECTLY = 178,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/blob_storage/blob_internals_url_loader.cc b/content/browser/blob_storage/blob_internals_url_loader.cc
index 910b356b..688e1e40 100644
--- a/content/browser/blob_storage/blob_internals_url_loader.cc
+++ b/content/browser/blob_storage/blob_internals_url_loader.cc
@@ -40,7 +40,10 @@
   CHECK_EQ(result, MOJO_RESULT_OK);
 
   client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
-  client->OnComplete(ResourceRequestCompletionStatus(output.size()));
+  ResourceRequestCompletionStatus status(net::OK);
+  status.encoded_data_length = output.size();
+  status.encoded_body_length = output.size();
+  client->OnComplete(status);
 }
 
 }  // namespace content
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index ed53e2f..1ff54def 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -43,9 +43,11 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/render_widget_host_iterator.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/content_features.h"
 
 #if defined(OS_ANDROID)
 #include "content/public/browser/render_widget_host_view.h"
@@ -771,8 +773,11 @@
 void RenderFrameDevToolsAgentHost::GrantPolicy(RenderFrameHostImpl* host) {
   if (!host)
     return;
+  uint32_t process_id = host->GetProcess()->GetID();
+  if (base::FeatureList::IsEnabled(features::kNetworkService))
+    GetNetworkService()->SetRawHeadersAccess(process_id, true);
   ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
-      host->GetProcess()->GetID());
+      process_id);
 }
 
 void RenderFrameDevToolsAgentHost::RevokePolicy(RenderFrameHostImpl* host) {
@@ -803,6 +808,8 @@
 
   // We are the last to disconnect from the renderer -> revoke permissions.
   if (!process_has_agents) {
+    if (base::FeatureList::IsEnabled(features::kNetworkService))
+      GetNetworkService()->SetRawHeadersAccess(process_host->GetID(), false);
     ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
         process_host->GetID());
   }
@@ -1260,7 +1267,7 @@
 }
 
 base::TimeTicks RenderFrameDevToolsAgentHost::GetLastActivityTime() {
-  if (content::WebContents* contents = web_contents())
+  if (WebContents* contents = web_contents())
     return contents->GetLastActiveTime();
   return base::TimeTicks();
 }
diff --git a/content/browser/dom_storage/dom_storage_area.cc b/content/browser/dom_storage/dom_storage_area.cc
index 9dcc3d0..10a1c2df 100644
--- a/content/browser/dom_storage/dom_storage_area.cc
+++ b/content/browser/dom_storage/dom_storage_area.cc
@@ -19,6 +19,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "build/build_config.h"
 #include "content/browser/dom_storage/dom_storage_namespace.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
 #include "content/browser/dom_storage/local_storage_database_adapter.h"
@@ -69,14 +70,21 @@
   return base::TimeDelta();
 }
 
-DOMStorageArea::CommitBatch::CommitBatch() : clear_all_first(false) {
-}
+DOMStorageArea::CommitBatch::CommitBatch() : clear_all_first(false) {}
 DOMStorageArea::CommitBatch::~CommitBatch() {}
 
 size_t DOMStorageArea::CommitBatch::GetDataSize() const {
   return DOMStorageMap::CountBytes(changed_values);
 }
 
+DOMStorageArea::CommitBatchHolder::CommitBatchHolder(
+    Type type,
+    scoped_refptr<CommitBatch> batch)
+    : type(type), batch(batch) {}
+DOMStorageArea::CommitBatchHolder::CommitBatchHolder(
+    const DOMStorageArea::CommitBatchHolder& other) = default;
+DOMStorageArea::CommitBatchHolder::~CommitBatchHolder() {}
+
 // static
 const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] =
     FILE_PATH_LITERAL(".localstorage");
@@ -111,44 +119,63 @@
       origin_(origin),
       directory_(directory),
       task_runner_(task_runner),
-      map_(new DOMStorageMap(kPerStorageAreaQuota +
-                             kPerStorageAreaOverQuotaAllowance)),
-      is_initial_import_done_(true),
+#if defined(OS_ANDROID)
+      desired_load_state_(directory.empty() ? LOAD_STATE_KEYS_AND_VALUES
+                                            : LOAD_STATE_KEYS_ONLY),
+#else
+      desired_load_state_(LOAD_STATE_KEYS_AND_VALUES),
+#endif
+      load_state_(directory.empty() ? LOAD_STATE_KEYS_AND_VALUES
+                                    : LOAD_STATE_UNLOADED),
+      map_(new DOMStorageMap(
+          kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+          desired_load_state_ == LOAD_STATE_KEYS_ONLY)),
       is_shutdown_(false),
-      commit_batches_in_flight_(0),
       start_time_(base::TimeTicks::Now()),
       data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)),
       commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
   if (!directory.empty()) {
     base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
     backing_.reset(new LocalStorageDatabaseAdapter(path));
-    is_initial_import_done_ = false;
   }
 }
 
-DOMStorageArea::DOMStorageArea(int64_t namespace_id,
-                               const std::string& persistent_namespace_id,
-                               const GURL& origin,
-                               SessionStorageDatabase* session_storage_backing,
-                               DOMStorageTaskRunner* task_runner)
+DOMStorageArea::DOMStorageArea(
+    int64_t namespace_id,
+    const std::string& persistent_namespace_id,
+    std::unique_ptr<std::vector<std::string>> original_persistent_namespace_ids,
+    const GURL& origin,
+    SessionStorageDatabase* session_storage_backing,
+    DOMStorageTaskRunner* task_runner)
     : namespace_id_(namespace_id),
       persistent_namespace_id_(persistent_namespace_id),
+      original_persistent_namespace_ids_(
+          std::move(original_persistent_namespace_ids)),
       origin_(origin),
       task_runner_(task_runner),
-      map_(new DOMStorageMap(kPerStorageAreaQuota +
-                             kPerStorageAreaOverQuotaAllowance)),
+#if defined(OS_ANDROID)
+      desired_load_state_(session_storage_backing ? LOAD_STATE_KEYS_ONLY
+                                                  : LOAD_STATE_KEYS_AND_VALUES),
+#else
+      desired_load_state_(LOAD_STATE_KEYS_AND_VALUES),
+#endif
+      load_state_(session_storage_backing ? LOAD_STATE_UNLOADED
+                                          : LOAD_STATE_KEYS_AND_VALUES),
+      map_(new DOMStorageMap(
+          kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+          desired_load_state_ == LOAD_STATE_KEYS_ONLY)),
       session_storage_backing_(session_storage_backing),
-      is_initial_import_done_(true),
       is_shutdown_(false),
-      commit_batches_in_flight_(0),
       start_time_(base::TimeTicks::Now()),
       data_rate_limiter_(kMaxBytesPerHour, base::TimeDelta::FromHours(1)),
       commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
   DCHECK(namespace_id != kLocalStorageNamespaceId);
   if (session_storage_backing) {
     backing_.reset(new SessionStorageDatabaseAdapter(
-        session_storage_backing, persistent_namespace_id, origin));
-    is_initial_import_done_ = false;
+        session_storage_backing, persistent_namespace_id,
+        original_persistent_namespace_ids_ ? *original_persistent_namespace_ids_
+                                           : std::vector<std::string>(),
+        origin));
   }
 }
 
@@ -158,57 +185,73 @@
 void DOMStorageArea::ExtractValues(DOMStorageValuesMap* map) {
   if (is_shutdown_)
     return;
-  InitialImportIfNeeded();
-  map_->ExtractValues(map);
+
+  if (load_state_ == LOAD_STATE_KEYS_AND_VALUES) {
+    map_->ExtractValues(map);
+    return;
+  }
+  LoadMapAndApplyUncommittedChangesIfNeeded(map);
 }
 
 unsigned DOMStorageArea::Length() {
   if (is_shutdown_)
     return 0;
-  InitialImportIfNeeded();
+  LoadMapAndApplyUncommittedChangesIfNeeded(nullptr);
   return map_->Length();
 }
 
 base::NullableString16 DOMStorageArea::Key(unsigned index) {
   if (is_shutdown_)
     return base::NullableString16();
-  InitialImportIfNeeded();
+  LoadMapAndApplyUncommittedChangesIfNeeded(nullptr);
   return map_->Key(index);
 }
 
 base::NullableString16 DOMStorageArea::GetItem(const base::string16& key) {
   if (is_shutdown_)
     return base::NullableString16();
-  InitialImportIfNeeded();
+  LoadMapAndApplyUncommittedChangesIfNeeded(nullptr);
   return map_->GetItem(key);
 }
 
 bool DOMStorageArea::SetItem(const base::string16& key,
                              const base::string16& value,
+                             const base::NullableString16& client_old_value,
                              base::NullableString16* old_value) {
   if (is_shutdown_)
     return false;
-  InitialImportIfNeeded();
+  LoadMapAndApplyUncommittedChangesIfNeeded(nullptr);
   if (!map_->HasOneRef())
     map_ = map_->DeepCopy();
   bool success = map_->SetItem(key, value, old_value);
+  if (map_->has_only_keys())
+    *old_value = client_old_value;
   if (success && backing_ &&
       (old_value->is_null() || old_value->string() != value)) {
     CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
-    // Values are populated later to avoid holding duplicate memory.
-    commit_batch->changed_values[key] = base::NullableString16();
+    if (load_state_ == LOAD_STATE_KEYS_AND_VALUES) {
+      // Values are populated later to avoid holding duplicate memory.
+      commit_batch->changed_values[key] = base::NullableString16();
+    } else {
+      commit_batch->changed_values[key] = base::NullableString16(value, false);
+    }
   }
   return success;
 }
 
 bool DOMStorageArea::RemoveItem(const base::string16& key,
+                                const base::NullableString16& client_old_value,
                                 base::string16* old_value) {
   if (is_shutdown_)
     return false;
-  InitialImportIfNeeded();
+  LoadMapAndApplyUncommittedChangesIfNeeded(nullptr);
   if (!map_->HasOneRef())
     map_ = map_->DeepCopy();
   bool success = map_->RemoveItem(key, old_value);
+  if (map_->has_only_keys()) {
+    DCHECK(!client_old_value.is_null());
+    *old_value = client_old_value.string();
+  }
   if (success && backing_) {
     CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
     commit_batch->changed_values[key] = base::NullableString16();
@@ -219,12 +262,13 @@
 bool DOMStorageArea::Clear() {
   if (is_shutdown_)
     return false;
-  InitialImportIfNeeded();
+  LoadMapAndApplyUncommittedChangesIfNeeded(nullptr);
   if (map_->Length() == 0)
     return false;
 
-  map_ = new DOMStorageMap(kPerStorageAreaQuota +
-                           kPerStorageAreaOverQuotaAllowance);
+  map_ = new DOMStorageMap(
+      kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+      desired_load_state_ == LOAD_STATE_KEYS_ONLY);
 
   if (backing_) {
     CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
@@ -239,11 +283,12 @@
   if (is_shutdown_)
     return;
 
-  map_ = new DOMStorageMap(kPerStorageAreaQuota +
-                           kPerStorageAreaOverQuotaAllowance);
-  // This ensures no import will happen while we're waiting to clear the data
+  map_ = new DOMStorageMap(
+      kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+      desired_load_state_ == LOAD_STATE_KEYS_ONLY);
+  // This ensures no load will happen while we're waiting to clear the data
   // from the database.
-  is_initial_import_done_ = true;
+  load_state_ = desired_load_state_;
 
   if (backing_) {
     CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
@@ -258,22 +303,38 @@
   DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
   DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id);
 
+  auto original_persistent_namespace_ids =
+      base::MakeUnique<std::vector<std::string>>();
+  original_persistent_namespace_ids->push_back(persistent_namespace_id_);
+  if (original_persistent_namespace_ids_) {
+    original_persistent_namespace_ids->insert(
+        original_persistent_namespace_ids->end(),
+        original_persistent_namespace_ids_->begin(),
+        original_persistent_namespace_ids_->end());
+  }
   DOMStorageArea* copy = new DOMStorageArea(
-      destination_namespace_id, destination_persistent_namespace_id, origin_,
+      destination_namespace_id, destination_persistent_namespace_id,
+      std::move(original_persistent_namespace_ids), origin_,
       session_storage_backing_.get(), task_runner_.get());
+  copy->desired_load_state_ = desired_load_state_;
+  copy->load_state_ = load_state_;
   copy->map_ = map_;
   copy->is_shutdown_ = is_shutdown_;
-  copy->is_initial_import_done_ = true;
 
   // All the uncommitted changes to this area need to happen before the actual
   // shallow copy is made (scheduled by the upper layer sometime after return).
-  if (commit_batch_)
+  if (GetCurrentCommitBatch())
     ScheduleImmediateCommit();
+  if (load_state_ != LOAD_STATE_KEYS_AND_VALUES) {
+    copy->commit_batches_ = commit_batches_;
+    for (auto& it : copy->commit_batches_)
+      it.type = CommitBatchHolder::TYPE_CLONE;
+  }
   return copy;
 }
 
 bool DOMStorageArea::HasUncommittedChanges() const {
-  return commit_batch_.get() || commit_batches_in_flight_;
+  return !commit_batches_.empty();
 }
 
 void DOMStorageArea::ScheduleImmediateCommit() {
@@ -281,6 +342,29 @@
   PostCommitTask();
 }
 
+void DOMStorageArea::ClearShallowCopiedCommitBatches() {
+  if (is_shutdown_)
+    return;
+  while (commit_batches_.back().type == CommitBatchHolder::TYPE_CLONE)
+    commit_batches_.pop_back();
+  original_persistent_namespace_ids_ = nullptr;
+}
+
+void DOMStorageArea::SetCacheOnlyKeys(bool only_keys) {
+  LoadState new_desired_state =
+      only_keys ? LOAD_STATE_KEYS_ONLY : LOAD_STATE_KEYS_AND_VALUES;
+  if (is_shutdown_ || !backing_ || desired_load_state_ == new_desired_state)
+    return;
+
+  desired_load_state_ = new_desired_state;
+  // Do not clear values immediately when desired state is set to keys only.
+  // Either commit timer or a purge call will clear the map, in case new process
+  // tries to open again. When values are desired it is ok to clear the map
+  // immediately. The reload only happens when required.
+  if (!map_->Length() || desired_load_state_ == LOAD_STATE_KEYS_AND_VALUES)
+    UnloadMapIfDesired();
+}
+
 void DOMStorageArea::DeleteOrigin() {
   DCHECK(!is_shutdown_);
   // This function shouldn't be called for sessionStorage.
@@ -294,10 +378,11 @@
     Clear();
     return;
   }
-  map_ = new DOMStorageMap(kPerStorageAreaQuota +
-                           kPerStorageAreaOverQuotaAllowance);
+  map_ = new DOMStorageMap(
+      kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+      desired_load_state_ == LOAD_STATE_KEYS_ONLY);
   if (backing_) {
-    is_initial_import_done_ = false;
+    load_state_ = LOAD_STATE_UNLOADED;
     backing_->Reset();
     backing_->DeleteFiles();
   }
@@ -306,8 +391,8 @@
 void DOMStorageArea::PurgeMemory() {
   DCHECK(!is_shutdown_);
 
-  if (!is_initial_import_done_ ||  // We're not using any memory.
-      !backing_.get() ||  // We can't purge anything.
+  if (load_state_ == LOAD_STATE_UNLOADED ||  // We're not using any memory.
+      !backing_.get() ||                     // We can't purge anything.
       HasUncommittedChanges())  // We leave things alone with changes pending.
     return;
 
@@ -315,15 +400,41 @@
   // and its page cache.
   backing_->Reset();
 
-  // Do not set |is_initial_import_done_| to false if map is empty since
-  // FastClear expects no imports while waiting for clearing database.
+  // Do not set load_state_ to |LOAD_STATE_UNLOADED| if map is empty since
+  // FastClear is efficient with no reloads while waiting for clearing database.
   if (!map_ || !map_->Length())
     return;
 
   // Drop the in memory cache, we'll reload when needed.
-  is_initial_import_done_ = false;
-  map_ = new DOMStorageMap(kPerStorageAreaQuota +
-                           kPerStorageAreaOverQuotaAllowance);
+  load_state_ = LOAD_STATE_UNLOADED;
+  map_ = new DOMStorageMap(
+      kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+      desired_load_state_ == LOAD_STATE_KEYS_ONLY);
+}
+
+void DOMStorageArea::UnloadMapIfDesired() {
+  if (load_state_ == LOAD_STATE_UNLOADED || load_state_ == desired_load_state_)
+    return;
+
+  // Do not clear the map if there are uncommitted changes since the commit
+  // batch might not have the values populated.
+  if (!backing_ || HasUncommittedChanges())
+    return;
+
+  if (load_state_ == LOAD_STATE_KEYS_AND_VALUES) {
+    scoped_refptr<DOMStorageMap> keys_values = map_;
+    map_ = new DOMStorageMap(
+        kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+        desired_load_state_ == LOAD_STATE_KEYS_ONLY);
+    map_->TakeKeysFrom(keys_values->keys_values());
+    load_state_ = LOAD_STATE_KEYS_ONLY;
+    return;
+  }
+
+  map_ = new DOMStorageMap(
+      kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+      desired_load_state_ == LOAD_STATE_KEYS_ONLY);
+  load_state_ = LOAD_STATE_UNLOADED;
 }
 
 void DOMStorageArea::Shutdown() {
@@ -331,7 +442,7 @@
     return;
   is_shutdown_ = true;
 
-  if (commit_batch_) {
+  if (GetCurrentCommitBatch()) {
     DCHECK(backing_);
     PopulateCommitBatchValues();
   }
@@ -346,9 +457,13 @@
   DCHECK(success);
 }
 
+bool DOMStorageArea::IsMapReloadNeeded() {
+  return load_state_ < desired_load_state_;
+}
+
 void DOMStorageArea::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) {
   task_runner_->AssertIsRunningOnPrimarySequence();
-  if (!is_initial_import_done_)
+  if (is_shutdown_ || load_state_ == LOAD_STATE_UNLOADED)
     return;
 
   // Limit the url length to 50 and strip special characters.
@@ -364,12 +479,15 @@
   const char* system_allocator_name =
       base::trace_event::MemoryDumpManager::GetInstance()
           ->system_allocator_pool_name();
-  if (commit_batch_) {
+  if (!commit_batches_.empty()) {
+    size_t commit_batches_size = 0;
+    for (const auto& it : commit_batches_)
+      commit_batches_size += it.batch->GetDataSize();
     auto* commit_batch_mad = pmd->CreateAllocatorDump(name + "/commit_batch");
     commit_batch_mad->AddScalar(
         base::trace_event::MemoryAllocatorDump::kNameSize,
         base::trace_event::MemoryAllocatorDump::kUnitsBytes,
-        commit_batch_->GetDataSize());
+        commit_batches_size);
     if (system_allocator_name)
       pmd->AddSuballocation(commit_batch_mad->guid(), system_allocator_name);
   }
@@ -380,79 +498,143 @@
     backing_->ReportMemoryUsage(pmd, name + "/local_storage");
 
   // Do not add storage map usage if less than 1KB.
-  if (map_->memory_usage() < 1024)
+  if (map_->memory_used() < 1024)
     return;
 
   auto* map_mad = pmd->CreateAllocatorDump(name + "/storage_map");
   map_mad->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
                      base::trace_event::MemoryAllocatorDump::kUnitsBytes,
-                     map_->memory_usage());
+                     map_->memory_used());
   if (system_allocator_name)
     pmd->AddSuballocation(map_mad->guid(), system_allocator_name);
 }
 
-void DOMStorageArea::InitialImportIfNeeded() {
-  if (is_initial_import_done_)
+void DOMStorageArea::LoadMapAndApplyUncommittedChangesIfNeeded(
+    DOMStorageValuesMap* map) {
+  if (!backing_ || (!IsMapReloadNeeded() && !map))
     return;
 
-  DCHECK(backing_.get());
-
-  base::TimeTicks before = base::TimeTicks::Now();
-  DOMStorageValuesMap initial_values;
-  backing_->ReadAllValues(&initial_values);
-  map_->SwapValues(&initial_values);
-  is_initial_import_done_ = true;
-  base::TimeDelta time_to_import = base::TimeTicks::Now() - before;
-  UMA_HISTOGRAM_TIMES("LocalStorage.BrowserTimeToPrimeLocalStorage",
-                      time_to_import);
-
-  size_t local_storage_size_kb = map_->bytes_used() / 1024;
-  // Track localStorage size, from 0-6MB. Note that the maximum size should be
-  // 5MB, but we add some slop since we want to make sure the max size is always
-  // above what we see in practice, since histograms can't change.
-  UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.BrowserLocalStorageSizeInKB",
-                              local_storage_size_kb,
-                              1, 6 * 1024, 50);
-  if (local_storage_size_kb < 100) {
-    UMA_HISTOGRAM_TIMES(
-        "LocalStorage.BrowserTimeToPrimeLocalStorageUnder100KB",
-        time_to_import);
-  } else if (local_storage_size_kb < 1000) {
-    UMA_HISTOGRAM_TIMES(
-        "LocalStorage.BrowserTimeToPrimeLocalStorage100KBTo1MB",
-        time_to_import);
-  } else {
-    UMA_HISTOGRAM_TIMES(
-        "LocalStorage.BrowserTimeToPrimeLocalStorage1MBTo5MB",
-        time_to_import);
+  DOMStorageValuesMap read_values;
+  auto most_recent_clear_all_iter = commit_batches_.begin();
+  while (most_recent_clear_all_iter != commit_batches_.end()) {
+    if (most_recent_clear_all_iter->batch->clear_all_first)
+      break;
+    ++most_recent_clear_all_iter;
   }
+
+  if (most_recent_clear_all_iter == commit_batches_.end()) {
+    base::TimeTicks before = base::TimeTicks::Now();
+    backing_->ReadAllValues(&read_values);
+
+    base::TimeDelta time_to_prime = base::TimeTicks::Now() - before;
+    UMA_HISTOGRAM_TIMES("LocalStorage.BrowserTimeToPrimeLocalStorage",
+                        time_to_prime);
+
+    size_t local_storage_size_kb =
+        DOMStorageMap::CountBytes(read_values) / 1024;
+    // Track localStorage size, from 0-6MB. Note that the maximum size should be
+    // 5MB, but we add some slop since we want to make sure the max size is
+    // always above what we see in practice, since histograms can't change.
+    UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.BrowserLocalStorageSizeInKB",
+                                local_storage_size_kb, 1, 6 * 1024, 50);
+    if (local_storage_size_kb < 100) {
+      UMA_HISTOGRAM_TIMES(
+          "LocalStorage.BrowserTimeToPrimeLocalStorageUnder100KB",
+          time_to_prime);
+    } else if (local_storage_size_kb < 1000) {
+      UMA_HISTOGRAM_TIMES(
+          "LocalStorage.BrowserTimeToPrimeLocalStorage100KBTo1MB",
+          time_to_prime);
+    } else {
+      UMA_HISTOGRAM_TIMES("LocalStorage.BrowserTimeToPrimeLocalStorage1MBTo5MB",
+                          time_to_prime);
+    }
+  }
+
+  // Apply changes in reverse order of commit batches starting from the most
+  // recent commit batch with clear all flag. It is possible that the changes in
+  // one or more of the commit batches have already been written to the database
+  // and reflected in the map returned by ReadAllValues(). It is okay to
+  // re-apply these changes.
+  auto it = most_recent_clear_all_iter == commit_batches_.end()
+                ? commit_batches_.end()
+                : ++most_recent_clear_all_iter;
+  while (it != commit_batches_.begin()) {
+    --it;
+    for (const auto& item : it->batch->changed_values) {
+      if (item.second.is_null())
+        read_values.erase(item.first);
+      else
+        read_values[item.first] = item.second;
+    }
+  }
+
+  if (!IsMapReloadNeeded()) {
+    map->swap(read_values);
+    return;
+  }
+
+  map_ = new DOMStorageMap(
+      kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance,
+      desired_load_state_ == LOAD_STATE_KEYS_ONLY);
+  if (desired_load_state_ == LOAD_STATE_KEYS_ONLY) {
+    map_->TakeKeysFrom(read_values);
+    if (map)
+      map->swap(read_values);
+  } else {
+    map_->SwapValues(&read_values);
+    if (map)
+      map_->ExtractValues(map);
+  }
+  load_state_ = desired_load_state_;
 }
 
 DOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() {
   DCHECK(!is_shutdown_);
-  if (!commit_batch_) {
-    commit_batch_.reset(new CommitBatch());
+  DCHECK(backing_);
+  if (!GetCurrentCommitBatch()) {
+    commit_batches_.emplace_front(CommitBatchHolder(
+        CommitBatchHolder::TYPE_CURRENT_BATCH, new CommitBatch()));
     BrowserThread::PostAfterStartupTask(
         FROM_HERE, task_runner_,
         base::BindOnce(&DOMStorageArea::StartCommitTimer, this));
   }
-  return commit_batch_.get();
+  return GetCurrentCommitBatch()->batch.get();
+}
+
+const DOMStorageArea::CommitBatchHolder* DOMStorageArea::GetCurrentCommitBatch()
+    const {
+  return (!commit_batches_.empty() &&
+          commit_batches_.front().type == CommitBatchHolder::TYPE_CURRENT_BATCH)
+             ? &commit_batches_.front()
+             : nullptr;
+}
+
+bool DOMStorageArea::HasCommitBatchInFlight() const {
+  for (const auto& batch : commit_batches_) {
+    if (batch.type == CommitBatchHolder::TYPE_IN_FLIGHT)
+      return true;
+  }
+  return false;
 }
 
 void DOMStorageArea::PopulateCommitBatchValues() {
   task_runner_->AssertIsRunningOnPrimarySequence();
-  for (auto& key_value : commit_batch_->changed_values)
+  if (load_state_ != LOAD_STATE_KEYS_AND_VALUES)
+    return;
+  CommitBatch* current_batch = GetCurrentCommitBatch()->batch.get();
+  for (auto& key_value : current_batch->changed_values)
     key_value.second = map_->GetItem(key_value.first);
 }
 
 void DOMStorageArea::StartCommitTimer() {
-  if (is_shutdown_ || !commit_batch_)
+  if (is_shutdown_ || !GetCurrentCommitBatch())
     return;
 
   // Start a timer to commit any changes that accrue in the batch, but only if
   // no commits are currently in flight. In that case the timer will be
   // started after the commits have happened.
-  if (commit_batches_in_flight_)
+  if (HasCommitBatchInFlight())
     return;
 
   task_runner_->PostDelayedTask(
@@ -479,21 +661,23 @@
 
   // It's possible that there is nothing to commit if an immediate
   // commit occured after the timer was scheduled but before it fired.
-  if (!commit_batch_)
+  if (!GetCurrentCommitBatch())
     return;
 
   PostCommitTask();
 }
 
 void DOMStorageArea::PostCommitTask() {
-  if (is_shutdown_ || !commit_batch_)
+  if (is_shutdown_ || !GetCurrentCommitBatch())
     return;
 
   DCHECK(backing_.get());
-
+  CommitBatchHolder& current_batch = commit_batches_.front();
   PopulateCommitBatchValues();
+  current_batch.type = CommitBatchHolder::TYPE_IN_FLIGHT;
+
   commit_rate_limiter_.add_samples(1);
-  data_rate_limiter_.add_samples(commit_batch_->GetDataSize());
+  data_rate_limiter_.add_samples(current_batch.batch->GetDataSize());
 
   // This method executes on the primary sequence, we schedule
   // a task for immediate execution on the commit sequence.
@@ -501,8 +685,7 @@
   bool success = task_runner_->PostShutdownBlockingTask(
       FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE,
       base::BindOnce(&DOMStorageArea::CommitChanges, this,
-                     base::Owned(commit_batch_.release())));
-  ++commit_batches_in_flight_;
+                     base::RetainedRef(current_batch.batch)));
   DCHECK(success);
 }
 
@@ -520,14 +703,20 @@
 void DOMStorageArea::OnCommitComplete() {
   // We're back on the primary sequence in this method.
   task_runner_->AssertIsRunningOnPrimarySequence();
-  --commit_batches_in_flight_;
   if (is_shutdown_)
     return;
-  if (commit_batch_.get() && !commit_batches_in_flight_) {
+
+  DCHECK_EQ(CommitBatchHolder::TYPE_IN_FLIGHT, commit_batches_.back().type);
+  commit_batches_.pop_back();
+  if (GetCurrentCommitBatch() && !HasCommitBatchInFlight()) {
     // More changes have accrued, restart the timer.
     task_runner_->PostDelayedTask(
         FROM_HERE, base::BindOnce(&DOMStorageArea::OnCommitTimer, this),
         ComputeCommitDelay());
+  } else {
+    // When the desired load state is changed, the unload of map is deferred
+    // when there are uncommitted changes. So, try again after committing.
+    UnloadMapIfDesired();
   }
 }
 
@@ -535,14 +724,14 @@
   // This method executes on the commit sequence.
   task_runner_->AssertIsRunningOnCommitSequence();
   DCHECK(backing_.get());
-  if (commit_batch_) {
+  if (GetCurrentCommitBatch()) {
+    CommitBatch* batch = GetCurrentCommitBatch()->batch.get();
     // Commit any changes that accrued prior to the timer firing.
-    bool success = backing_->CommitChanges(
-        commit_batch_->clear_all_first,
-        commit_batch_->changed_values);
+    bool success =
+        backing_->CommitChanges(batch->clear_all_first, batch->changed_values);
     DCHECK(success);
   }
-  commit_batch_.reset();
+  commit_batches_.clear();
   backing_.reset();
   session_storage_backing_ = NULL;
 }
diff --git a/content/browser/dom_storage/dom_storage_area.h b/content/browser/dom_storage/dom_storage_area.h
index 70ab2bee..b45104e 100644
--- a/content/browser/dom_storage/dom_storage_area.h
+++ b/content/browser/dom_storage/dom_storage_area.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <list>
 #include <memory>
 #include <string>
 
@@ -59,13 +60,15 @@
   // Session storage. Backed on disk if |session_storage_backing| is not NULL.
   DOMStorageArea(int64_t namespace_id,
                  const std::string& persistent_namespace_id,
+                 std::unique_ptr<std::vector<std::string>>
+                     original_persistent_namespace_ids,
                  const GURL& origin,
                  SessionStorageDatabase* session_storage_backing,
                  DOMStorageTaskRunner* task_runner);
 
   const GURL& origin() const { return origin_; }
   int64_t namespace_id() const { return namespace_id_; }
-  size_t map_usage_in_bytes() const { return map_ ? map_->bytes_used() : 0; }
+  size_t map_memory_used() const { return map_ ? map_->memory_used() : 0; }
 
   // Writes a copy of the current set of values in the area to the |map|.
   void ExtractValues(DOMStorageValuesMap* map);
@@ -73,9 +76,13 @@
   unsigned Length();
   base::NullableString16 Key(unsigned index);
   base::NullableString16 GetItem(const base::string16& key);
-  bool SetItem(const base::string16& key, const base::string16& value,
+  bool SetItem(const base::string16& key,
+               const base::string16& value,
+               const base::NullableString16& client_old_value,
                base::NullableString16* old_value);
-  bool RemoveItem(const base::string16& key, base::string16* old_value);
+  bool RemoveItem(const base::string16& key,
+                  const base::NullableString16& client_old_value,
+                  base::string16* old_value);
   bool Clear();
   void FastClear();
 
@@ -85,6 +92,13 @@
 
   bool HasUncommittedChanges() const;
   void ScheduleImmediateCommit();
+  void ClearShallowCopiedCommitBatches();
+
+  // Stores only the keys in the in-memory cache when set to true. Changing this
+  // behavior will reload the cache only when needed and not immediately.
+  // Note: Do not use ExtractValues() frequently since will have a disk access
+  // when only keys are stored.
+  void SetCacheOnlyKeys(bool value);
 
   // Similar to Clear() but more optimized for just deleting
   // without raising events.
@@ -100,26 +114,35 @@
   // no longer do anything.
   void Shutdown();
 
-  // Returns true if the data is loaded in memory.
-  bool IsLoadedInMemory() const { return is_initial_import_done_; }
+  // Returns true if data needs to be loaded in memory.
+  bool IsMapReloadNeeded();
 
   // Adds memory statistics to |pmd| for chrome://tracing.
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd);
 
  private:
   friend class DOMStorageAreaTest;
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, DOMStorageAreaBasics);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, DOMStorageAreaBasics);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, BackingDatabaseOpened);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, ShallowCopyWithBacking);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, SetCacheOnlyKeysWithoutBacking);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, SetCacheOnlyKeysWithBacking);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, TestDatabaseFilePath);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitTasks);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitChangesAtShutdown);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, DeleteOrigin);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, PurgeMemory);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, CommitTasks);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, CommitChangesAtShutdown);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, DeleteOrigin);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, PurgeMemory);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, RateLimiter);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageContextImplTest, PersistentIds);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageContextImplTest, PurgeMemory);
   friend class base::RefCountedThreadSafe<DOMStorageArea>;
 
+  enum LoadState {
+    LOAD_STATE_UNLOADED = 0,
+    LOAD_STATE_KEYS_ONLY = 1,
+    LOAD_STATE_KEYS_AND_VALUES = 2
+  };
+
   // Used to rate limit commits.
   class CONTENT_EXPORT RateLimiter {
    public:
@@ -145,26 +168,46 @@
     base::TimeDelta time_quantum_;
   };
 
-  struct CONTENT_EXPORT CommitBatch {
+  struct CONTENT_EXPORT CommitBatch
+      : public base::RefCountedThreadSafe<CommitBatch> {
     bool clear_all_first;
     DOMStorageValuesMap changed_values;
 
     CommitBatch();
-    ~CommitBatch();
     size_t GetDataSize() const;
+
+   private:
+    friend class base::RefCountedThreadSafe<CommitBatch>;
+    ~CommitBatch();
+  };
+
+  struct CONTENT_EXPORT CommitBatchHolder {
+    enum Type { TYPE_CURRENT_BATCH, TYPE_IN_FLIGHT, TYPE_CLONE };
+    Type type;
+    scoped_refptr<CommitBatch> batch;
+
+    CommitBatchHolder(Type, scoped_refptr<CommitBatch>);
+    CommitBatchHolder(const CommitBatchHolder& other);
+    ~CommitBatchHolder();
   };
 
   ~DOMStorageArea();
 
-  // If we haven't done so already and this is a local storage area,
-  // will attempt to read any values for this origin currently
-  // stored on disk.
-  void InitialImportIfNeeded();
+  // Loads the map for this origin into the |map_| if desired load state is not
+  // met and into the |map| if it's not null.
+  void LoadMapAndApplyUncommittedChangesIfNeeded(DOMStorageValuesMap* map);
+
+  // If the cache state is inconsistent with the map storage, purges the map and
+  // updates with new data if possible without reading from database. Noop if
+  // the area has uncommitted changes.
+  void UnloadMapIfDesired();
 
   // Post tasks to defer writing a batch of changed values to
   // disk on the commit sequence, and to call back on the primary
   // task sequence when complete.
   CommitBatch* CreateCommitBatchIfNeeded();
+  const CommitBatchHolder* GetCurrentCommitBatch() const;
+  bool HasCommitBatchInFlight() const;
   void PopulateCommitBatchValues();
   void StartCommitTimer();
   void OnCommitTimer();
@@ -179,16 +222,17 @@
 
   int64_t namespace_id_;
   std::string persistent_namespace_id_;
+  std::unique_ptr<std::vector<std::string>> original_persistent_namespace_ids_;
   GURL origin_;
   base::FilePath directory_;
   scoped_refptr<DOMStorageTaskRunner> task_runner_;
+  LoadState desired_load_state_;
+  LoadState load_state_;
   scoped_refptr<DOMStorageMap> map_;
   std::unique_ptr<DOMStorageDatabaseAdapter> backing_;
   scoped_refptr<SessionStorageDatabase> session_storage_backing_;
-  bool is_initial_import_done_;
   bool is_shutdown_;
-  std::unique_ptr<CommitBatch> commit_batch_;
-  int commit_batches_in_flight_;
+  std::list<CommitBatchHolder> commit_batches_;
   base::TimeTicks start_time_;
   RateLimiter data_rate_limiter_;
   RateLimiter commit_rate_limiter_;
diff --git a/content/browser/dom_storage/dom_storage_area_unittest.cc b/content/browser/dom_storage/dom_storage_area_unittest.cc
index 7ed06ea1..cd3aacd7 100644
--- a/content/browser/dom_storage/dom_storage_area_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_area_unittest.cc
@@ -17,11 +17,13 @@
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "content/browser/dom_storage/dom_storage_area.h"
 #include "content/browser/dom_storage/dom_storage_database.h"
 #include "content/browser/dom_storage/dom_storage_database_adapter.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
 #include "content/browser/dom_storage/local_storage_database_adapter.h"
+#include "content/browser/dom_storage/session_storage_database.h"
 #include "content/common/dom_storage/dom_storage_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -62,15 +64,15 @@
       const scoped_refptr<DOMStorageArea>& area) {
     // At this point the OnCommitTimer has run.
     // Verify that it put a commit in flight.
-    EXPECT_EQ(1, area->commit_batches_in_flight_);
-    EXPECT_FALSE(area->commit_batch_.get());
+    EXPECT_TRUE(area->HasCommitBatchInFlight());
+    EXPECT_FALSE(area->GetCurrentCommitBatch());
     EXPECT_TRUE(area->HasUncommittedChanges());
     // Make additional change and verify that a new commit batch
     // is created for that change.
     base::NullableString16 old_value;
-    EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
-    EXPECT_TRUE(area->commit_batch_.get());
-    EXPECT_EQ(1, area->commit_batches_in_flight_);
+    EXPECT_TRUE(area->SetItem(kKey2, kValue2, old_value, &old_value));
+    EXPECT_TRUE(area->GetCurrentCommitBatch());
+    EXPECT_TRUE(area->HasCommitBatchInFlight());
     EXPECT_TRUE(area->HasUncommittedChanges());
   }
 
@@ -92,9 +94,20 @@
   base::MessageLoop message_loop_;
 };
 
-TEST_F(DOMStorageAreaTest, DOMStorageAreaBasics) {
+class DOMStorageAreaParamTest : public DOMStorageAreaTest,
+                                public testing::WithParamInterface<bool> {
+ public:
+  DOMStorageAreaParamTest() {}
+  ~DOMStorageAreaParamTest() override {}
+};
+
+INSTANTIATE_TEST_CASE_P(_, DOMStorageAreaParamTest, ::testing::Bool());
+
+TEST_P(DOMStorageAreaParamTest, DOMStorageAreaBasics) {
   scoped_refptr<DOMStorageArea> area(
-      new DOMStorageArea(1, std::string(), kOrigin, NULL, NULL));
+      new DOMStorageArea(1, std::string(), NULL, kOrigin, NULL, NULL));
+  const bool values_cached = GetParam();
+  area->SetCacheOnlyKeys(!values_cached);
   base::string16 old_value;
   base::NullableString16 old_nullable_value;
   scoped_refptr<DOMStorageArea> copy;
@@ -104,8 +117,10 @@
   EXPECT_EQ(kOrigin, area->origin());
   EXPECT_EQ(1, area->namespace_id());
   EXPECT_EQ(0u, area->Length());
-  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
-  EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_nullable_value));
+  EXPECT_TRUE(
+      area->SetItem(kKey, kValue, old_nullable_value, &old_nullable_value));
+  EXPECT_TRUE(
+      area->SetItem(kKey2, kValue2, old_nullable_value, &old_nullable_value));
   EXPECT_FALSE(area->HasUncommittedChanges());
 
   // Verify that a copy shares the same map.
@@ -113,16 +128,20 @@
   EXPECT_EQ(kOrigin, copy->origin());
   EXPECT_EQ(2, copy->namespace_id());
   EXPECT_EQ(area->Length(), copy->Length());
-  EXPECT_EQ(area->GetItem(kKey).string(), copy->GetItem(kKey).string());
+  if (values_cached)
+    EXPECT_EQ(area->GetItem(kKey).string(), copy->GetItem(kKey).string());
   EXPECT_EQ(area->Key(0).string(), copy->Key(0).string());
   EXPECT_EQ(copy->map_.get(), area->map_.get());
 
   // But will deep copy-on-write as needed.
-  EXPECT_TRUE(area->RemoveItem(kKey, &old_value));
+  old_nullable_value = base::NullableString16(kValue, false);
+  EXPECT_TRUE(area->RemoveItem(kKey, old_nullable_value, &old_value));
+  EXPECT_EQ(kValue, old_value);
   EXPECT_NE(copy->map_.get(), area->map_.get());
   copy = area->ShallowCopy(2, std::string());
   EXPECT_EQ(copy->map_.get(), area->map_.get());
-  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_nullable_value));
+  EXPECT_TRUE(
+      area->SetItem(kKey, kValue, old_nullable_value, &old_nullable_value));
   EXPECT_NE(copy->map_.get(), area->map_.get());
   copy = area->ShallowCopy(2, std::string());
   EXPECT_EQ(copy->map_.get(), area->map_.get());
@@ -137,9 +156,11 @@
   EXPECT_FALSE(area->map_.get());
   EXPECT_EQ(0u, area->Length());
   EXPECT_TRUE(area->Key(0).is_null());
-  EXPECT_TRUE(area->GetItem(kKey).is_null());
-  EXPECT_FALSE(area->SetItem(kKey, kValue, &old_nullable_value));
-  EXPECT_FALSE(area->RemoveItem(kKey, &old_value));
+  if (values_cached)
+    EXPECT_TRUE(area->GetItem(kKey).is_null());
+  EXPECT_FALSE(
+      area->SetItem(kKey, kValue, old_nullable_value, &old_nullable_value));
+  EXPECT_FALSE(area->RemoveItem(kKey, old_nullable_value, &old_value));
   EXPECT_FALSE(area->Clear());
 }
 
@@ -155,21 +176,19 @@
     scoped_refptr<DOMStorageArea> area(
         new DOMStorageArea(kOrigin, base::FilePath(), NULL));
     EXPECT_EQ(NULL, area->backing_.get());
-    EXPECT_TRUE(area->is_initial_import_done_);
+    EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_AND_VALUES, area->load_state_);
     EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
   }
 
   // Valid directory and origin but no session storage backing. Backing should
   // be null.
   {
-    scoped_refptr<DOMStorageArea> area(
-        new DOMStorageArea(kSessionStorageNamespaceId, std::string(), kOrigin,
-                           NULL, NULL));
+    scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
+        kSessionStorageNamespaceId, std::string(), NULL, kOrigin, NULL, NULL));
     EXPECT_EQ(NULL, area->backing_.get());
-    EXPECT_TRUE(area->is_initial_import_done_);
 
     base::NullableString16 old_value;
-    EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
+    EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
     ASSERT_TRUE(old_value.is_null());
 
     // Check that saving a value has still left us without a backing database.
@@ -188,7 +207,7 @@
     DOMStorageDatabase* database = static_cast<LocalStorageDatabaseAdapter*>(
         area->backing_.get())->db_.get();
     EXPECT_FALSE(database->IsOpen());
-    EXPECT_FALSE(area->is_initial_import_done_);
+    EXPECT_EQ(DOMStorageArea::LOAD_STATE_UNLOADED, area->load_state_);
 
     // Inject an in-memory db to speed up the test.
     // We will verify that something is written into the database but not
@@ -198,31 +217,185 @@
 
     // Need to write something to ensure that the database is created.
     base::NullableString16 old_value;
-    EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
+    EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
     ASSERT_TRUE(old_value.is_null());
-    EXPECT_TRUE(area->is_initial_import_done_);
-    EXPECT_TRUE(area->commit_batch_.get());
-    EXPECT_EQ(0, area->commit_batches_in_flight_);
+    EXPECT_EQ(area->desired_load_state_, area->load_state_);
+    EXPECT_TRUE(area->GetCurrentCommitBatch());
+    EXPECT_FALSE(area->HasCommitBatchInFlight());
 
     base::RunLoop().RunUntilIdle();
 
-    EXPECT_FALSE(area->commit_batch_.get());
-    EXPECT_EQ(0, area->commit_batches_in_flight_);
+    EXPECT_FALSE(area->GetCurrentCommitBatch());
+    EXPECT_FALSE(area->HasCommitBatchInFlight());
     database = static_cast<LocalStorageDatabaseAdapter*>(
         area->backing_.get())->db_.get();
     EXPECT_TRUE(database->IsOpen());
     EXPECT_EQ(1u, area->Length());
-    EXPECT_EQ(kValue, area->GetItem(kKey).string());
-
-    // Verify the content made it to the in memory database.
-    DOMStorageValuesMap values;
-    area->backing_->ReadAllValues(&values);
-    EXPECT_EQ(1u, values.size());
-    EXPECT_EQ(kValue, values[kKey].string());
+    EXPECT_EQ(kKey, area->Key(0).string());
   }
 }
 
-TEST_F(DOMStorageAreaTest, CommitTasks) {
+TEST_P(DOMStorageAreaParamTest, ShallowCopyWithBacking) {
+  base::ScopedTempDir temp_dir;
+  const std::string kNamespaceId = "id1";
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  scoped_refptr<SessionStorageDatabase> db =
+      new SessionStorageDatabase(temp_dir.GetPath());
+  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
+      1, kNamespaceId, NULL, kOrigin, db.get(),
+      new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
+  EXPECT_TRUE(area->backing_.get());
+  EXPECT_TRUE(area->session_storage_backing_);
+  const bool values_cached = GetParam();
+  area->SetCacheOnlyKeys(!values_cached);
+
+  // Check if shallow copy is consistent.
+  base::string16 old_value;
+  base::NullableString16 old_nullable_value;
+  scoped_refptr<DOMStorageArea> copy;
+  EXPECT_TRUE(
+      area->SetItem(kKey, kValue, old_nullable_value, &old_nullable_value));
+  EXPECT_TRUE(area->HasUncommittedChanges());
+  EXPECT_EQ(DOMStorageArea::CommitBatchHolder::TYPE_CURRENT_BATCH,
+            area->commit_batches_.front().type);
+  copy = area->ShallowCopy(2, std::string());
+  EXPECT_EQ(copy->map_.get(), area->map_.get());
+  EXPECT_EQ(1u, copy->original_persistent_namespace_ids_->size());
+  EXPECT_EQ(kNamespaceId, (*copy->original_persistent_namespace_ids_)[0]);
+  if (!values_cached) {
+    EXPECT_EQ(area->commit_batches_.front().batch,
+              copy->commit_batches_.front().batch);
+    EXPECT_EQ(DOMStorageArea::CommitBatchHolder::TYPE_IN_FLIGHT,
+              area->commit_batches_.front().type);
+    EXPECT_EQ(DOMStorageArea::CommitBatchHolder::TYPE_CLONE,
+              copy->commit_batches_.front().type);
+  } else {
+    EXPECT_TRUE(copy->commit_batches_.empty());
+  }
+
+  DOMStorageValuesMap map;
+  copy->ExtractValues(&map);
+  EXPECT_EQ(1u, map.size());
+  EXPECT_EQ(kValue, map[kKey].string());
+
+  // Check if copy on write works.
+  EXPECT_TRUE(
+      copy->SetItem(kKey2, kValue2, old_nullable_value, &old_nullable_value));
+  EXPECT_TRUE(copy->GetCurrentCommitBatch());
+  EXPECT_FALSE(copy->commit_batches_.front().type);
+  if (!values_cached)
+    EXPECT_EQ(DOMStorageArea::CommitBatchHolder::TYPE_CLONE,
+              copy->commit_batches_.back().type);
+  else
+    EXPECT_FALSE(copy->HasCommitBatchInFlight());
+  EXPECT_EQ(1u, area->Length());
+
+  // Check clearing of cloned batches.
+  area->ClearShallowCopiedCommitBatches();
+  copy->ClearShallowCopiedCommitBatches();
+  EXPECT_EQ(DOMStorageArea::CommitBatchHolder::TYPE_IN_FLIGHT,
+            area->commit_batches_.front().type);
+  EXPECT_FALSE(copy->HasCommitBatchInFlight());
+}
+
+TEST_F(DOMStorageAreaTest, SetCacheOnlyKeysWithoutBacking) {
+  scoped_refptr<DOMStorageArea> area(
+      new DOMStorageArea(1, std::string(), NULL, kOrigin, NULL, NULL));
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_AND_VALUES,
+            area->desired_load_state_);
+  EXPECT_FALSE(area->map_->has_only_keys());
+  base::NullableString16 old_value;
+  EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
+  DOMStorageValuesMap map;
+  area->ExtractValues(&map);
+  EXPECT_EQ(1u, map.size());
+
+  area->SetCacheOnlyKeys(true);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_AND_VALUES,
+            area->desired_load_state_);  // cannot be disabled without backing.
+  area->SetItem(kKey, kValue2, old_value, &old_value);
+  EXPECT_FALSE(area->map_->has_only_keys());
+  EXPECT_EQ(kValue, old_value.string());
+  area->ExtractValues(&map);
+  EXPECT_EQ(kValue2, map[kKey].string());
+  EXPECT_EQ(1u, map.size());
+}
+
+TEST_F(DOMStorageAreaTest, SetCacheOnlyKeysWithBacking) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const base::FilePath kExpectedOriginFilePath = temp_dir.GetPath().Append(
+      DOMStorageArea::DatabaseFileNameFromOrigin(kOrigin));
+  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
+      kOrigin, temp_dir.GetPath(),
+      new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
+
+  EXPECT_TRUE(area->backing_.get());
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_UNLOADED, area->load_state_);
+  area->backing_.reset(new LocalStorageDatabaseAdapter());
+
+#if !defined(OS_ANDROID)
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_AND_VALUES,
+            area->desired_load_state_);
+  area->SetCacheOnlyKeys(true);
+#endif
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_ONLY, area->desired_load_state_);
+  base::NullableString16 old_value;
+  EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_ONLY, area->load_state_);
+  EXPECT_TRUE(area->GetCurrentCommitBatch());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(area->GetCurrentCommitBatch());
+  EXPECT_EQ(1u, area->Length());
+
+  // Fill the current batch and in flight batch.
+  EXPECT_TRUE(area->SetItem(kKey2, kValue, old_value, &old_value));
+  area->PostCommitTask();
+  EXPECT_FALSE(area->GetCurrentCommitBatch());
+  EXPECT_TRUE(area->HasCommitBatchInFlight());
+  EXPECT_TRUE(area->SetItem(kKey2, kValue2, old_value, &old_value));
+  EXPECT_TRUE(area->GetCurrentCommitBatch());
+
+  // The values must be imported from the backing, and from the commit batches.
+  area->SetCacheOnlyKeys(false);
+  EXPECT_EQ(2u, area->Length());
+  EXPECT_EQ(kValue, area->GetItem(kKey).string());
+  EXPECT_EQ(kValue2, area->GetItem(kKey2).string());
+
+  // Check if disabling cache clears the cache after committing only.
+  area->SetCacheOnlyKeys(true);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_ONLY, area->desired_load_state_);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_AND_VALUES, area->load_state_);
+  ASSERT_FALSE(area->map_->has_only_keys());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_ONLY, area->load_state_);
+  EXPECT_TRUE(area->map_->has_only_keys());
+  EXPECT_FALSE(area->HasCommitBatchInFlight());
+
+  // Check if Clear() works as expected when values are desired.
+  area->Clear();
+  EXPECT_TRUE(area->SetItem(kKey2, kValue2, old_value, &old_value));
+  area->PostCommitTask();
+  EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
+  EXPECT_EQ(2u, area->Length());
+  area->Clear();
+  EXPECT_TRUE(area->SetItem(kKey2, kValue, old_value, &old_value));
+  EXPECT_TRUE(area->GetCurrentCommitBatch()->batch->clear_all_first);
+  EXPECT_TRUE(area->commit_batches_.back().batch->clear_all_first);
+  area->SetCacheOnlyKeys(false);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_ONLY, area->load_state_);
+
+  // Unload only after commit.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_UNLOADED, area->load_state_);
+  EXPECT_EQ(1u, area->Length());
+  EXPECT_EQ(kValue, area->GetItem(kKey2).string());
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_KEYS_AND_VALUES, area->load_state_);
+}
+
+TEST_P(DOMStorageAreaParamTest, CommitTasks) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -231,31 +404,31 @@
       new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
   // Inject an in-memory db to speed up the test.
   area->backing_.reset(new LocalStorageDatabaseAdapter());
+  area->SetCacheOnlyKeys(GetParam());
 
   // Unrelated to commits, but while we're here, see that querying Length()
   // causes the backing database to be opened and presumably read from.
-  EXPECT_FALSE(area->is_initial_import_done_);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_UNLOADED, area->load_state_);
   EXPECT_EQ(0u, area->Length());
-  EXPECT_TRUE(area->is_initial_import_done_);
+  EXPECT_EQ(area->desired_load_state_, area->load_state_);
 
   DOMStorageValuesMap values;
   base::NullableString16 old_value;
 
   // See that changes are batched up.
-  EXPECT_FALSE(area->commit_batch_.get());
-  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
+  EXPECT_FALSE(area->GetCurrentCommitBatch());
+  EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
   EXPECT_TRUE(area->HasUncommittedChanges());
-  EXPECT_TRUE(area->commit_batch_.get());
-  EXPECT_FALSE(area->commit_batch_->clear_all_first);
-  EXPECT_EQ(1u, area->commit_batch_->changed_values.size());
-  EXPECT_TRUE(area->SetItem(kKey2, kValue2, &old_value));
-  EXPECT_TRUE(area->commit_batch_.get());
-  EXPECT_FALSE(area->commit_batch_->clear_all_first);
-  EXPECT_EQ(2u, area->commit_batch_->changed_values.size());
+  EXPECT_TRUE(area->GetCurrentCommitBatch());
+  EXPECT_FALSE(area->GetCurrentCommitBatch()->batch->clear_all_first);
+  EXPECT_EQ(1u, area->GetCurrentCommitBatch()->batch->changed_values.size());
+  EXPECT_TRUE(area->SetItem(kKey2, kValue2, old_value, &old_value));
+  EXPECT_FALSE(area->GetCurrentCommitBatch()->batch->clear_all_first);
+  EXPECT_EQ(2u, area->GetCurrentCommitBatch()->batch->changed_values.size());
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(area->HasUncommittedChanges());
-  EXPECT_FALSE(area->commit_batch_.get());
-  EXPECT_EQ(0, area->commit_batches_in_flight_);
+  EXPECT_FALSE(area->GetCurrentCommitBatch());
+  EXPECT_FALSE(area->HasCommitBatchInFlight());
   // Verify the changes made it to the database.
   values.clear();
   area->backing_->ReadAllValues(&values);
@@ -265,12 +438,12 @@
 
   // See that clear is handled properly.
   EXPECT_TRUE(area->Clear());
-  EXPECT_TRUE(area->commit_batch_.get());
-  EXPECT_TRUE(area->commit_batch_->clear_all_first);
-  EXPECT_TRUE(area->commit_batch_->changed_values.empty());
+  EXPECT_TRUE(area->GetCurrentCommitBatch());
+  EXPECT_TRUE(area->GetCurrentCommitBatch()->batch->clear_all_first);
+  EXPECT_TRUE(area->GetCurrentCommitBatch()->batch->changed_values.empty());
   base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(area->commit_batch_.get());
-  EXPECT_EQ(0, area->commit_batches_in_flight_);
+  EXPECT_FALSE(area->GetCurrentCommitBatch());
+  EXPECT_FALSE(area->HasCommitBatchInFlight());
   // Verify the changes made it to the database.
   values.clear();
   area->backing_->ReadAllValues(&values);
@@ -278,7 +451,7 @@
 
   // See that if changes accrue while a commit is "in flight"
   // those will also get committed.
-  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
+  EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
   EXPECT_TRUE(area->HasUncommittedChanges());
   // At this point the StartCommitTimer task has been posted to the after
   // startup task queue. We inject another task in the queue that will
@@ -300,7 +473,7 @@
   EXPECT_EQ(kValue2, values[kKey2].string());
 }
 
-TEST_F(DOMStorageAreaTest, CommitChangesAtShutdown) {
+TEST_P(DOMStorageAreaParamTest, CommitChangesAtShutdown) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
@@ -311,10 +484,11 @@
   // the final changes are commited in it's dtor.
   static_cast<LocalStorageDatabaseAdapter*>(area->backing_.get())->db_.reset(
       new VerifyChangesCommittedDatabase());
+  area->SetCacheOnlyKeys(GetParam());
 
   DOMStorageValuesMap values;
   base::NullableString16 old_value;
-  EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
+  EXPECT_TRUE(area->SetItem(kKey, kValue, old_value, &old_value));
   EXPECT_TRUE(area->HasUncommittedChanges());
   area->backing_->ReadAllValues(&values);
   EXPECT_TRUE(values.empty());  // not committed yet
@@ -329,12 +503,13 @@
   area->Shutdown();
 }
 
-TEST_F(DOMStorageAreaTest, DeleteOrigin) {
+TEST_P(DOMStorageAreaParamTest, DeleteOrigin) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
       kOrigin, temp_dir.GetPath(),
       new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
+  area->SetCacheOnlyKeys(GetParam());
 
   // This test puts files on disk.
   base::FilePath db_file_path = static_cast<LocalStorageDatabaseAdapter*>(
@@ -348,7 +523,7 @@
 
   // Commit something in the database and then delete.
   base::NullableString16 old_value;
-  area->SetItem(kKey, kValue, &old_value);
+  area->SetItem(kKey, kValue, old_value, &old_value);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(base::PathExists(db_file_path));
   area->DeleteOrigin();
@@ -358,7 +533,7 @@
 
   // Put some uncommitted changes to a non-existing database in
   // and then delete. No file ever gets created in this case.
-  area->SetItem(kKey, kValue, &old_value);
+  area->SetItem(kKey, kValue, old_value, &old_value);
   EXPECT_TRUE(area->HasUncommittedChanges());
   EXPECT_EQ(1u, area->Length());
   area->DeleteOrigin();
@@ -370,10 +545,10 @@
 
   // Put some uncommitted changes to a an existing database in
   // and then delete.
-  area->SetItem(kKey, kValue, &old_value);
+  area->SetItem(kKey, kValue, old_value, &old_value);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(base::PathExists(db_file_path));
-  area->SetItem(kKey2, kValue2, &old_value);
+  area->SetItem(kKey2, kValue2, old_value, &old_value);
   EXPECT_TRUE(area->HasUncommittedChanges());
   EXPECT_EQ(2u, area->Length());
   area->DeleteOrigin();
@@ -392,12 +567,13 @@
   area->Shutdown();
 }
 
-TEST_F(DOMStorageAreaTest, PurgeMemory) {
+TEST_P(DOMStorageAreaParamTest, PurgeMemory) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
       kOrigin, temp_dir.GetPath(),
       new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
+  area->SetCacheOnlyKeys(GetParam());
 
   // Inject an in-memory db to speed up the test.
   area->backing_.reset(new LocalStorageDatabaseAdapter());
@@ -409,9 +585,9 @@
   DOMStorageMap* original_map = area->map_.get();
 
   // Should do no harm when called on a newly constructed object.
-  EXPECT_FALSE(area->is_initial_import_done_);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_UNLOADED, area->load_state_);
   area->PurgeMemory();
-  EXPECT_FALSE(area->is_initial_import_done_);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_UNLOADED, area->load_state_);
   DOMStorageDatabase* new_backing = static_cast<LocalStorageDatabaseAdapter*>(
       area->backing_.get())->db_.get();
   EXPECT_EQ(original_backing, new_backing);
@@ -419,11 +595,12 @@
 
   // Should not do anything when commits are pending.
   base::NullableString16 old_value;
-  area->SetItem(kKey, kValue, &old_value);
-  EXPECT_TRUE(area->is_initial_import_done_);
+  area->SetItem(kKey, kValue, old_value, &old_value);
+  original_map = area->map_.get();  // importing creates new map.
+  EXPECT_EQ(area->desired_load_state_, area->load_state_);
   EXPECT_TRUE(area->HasUncommittedChanges());
   area->PurgeMemory();
-  EXPECT_TRUE(area->is_initial_import_done_);
+  EXPECT_EQ(area->desired_load_state_, area->load_state_);
   EXPECT_TRUE(area->HasUncommittedChanges());
   new_backing = static_cast<LocalStorageDatabaseAdapter*>(
       area->backing_.get())->db_.get();
@@ -441,7 +618,7 @@
   // Should drop caches and reset database connections
   // when invoked on an area that's loaded up primed.
   area->PurgeMemory();
-  EXPECT_FALSE(area->is_initial_import_done_);
+  EXPECT_EQ(DOMStorageArea::LOAD_STATE_UNLOADED, area->load_state_);
   new_backing = static_cast<LocalStorageDatabaseAdapter*>(
       area->backing_.get())->db_.get();
   EXPECT_NE(original_backing, new_backing);
diff --git a/content/browser/dom_storage/dom_storage_context_impl_unittest.cc b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
index 0e3bc0a..eb4587c 100644
--- a/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
@@ -111,8 +111,9 @@
   // Put some data into local storage and shutdown the context
   // to ensure data is written to disk.
   base::NullableString16 old_value;
-  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
-      OpenStorageArea(kOrigin)->SetItem(kKey, kValue, &old_value));
+  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)
+                  ->OpenStorageArea(kOrigin)
+                  ->SetItem(kKey, kValue, old_value, &old_value));
   context_->Shutdown();
   context_ = NULL;
   base::RunLoop().RunUntilIdle();
@@ -142,10 +143,12 @@
   // invoke Shutdown() which should delete data for session-only
   // origins.
   base::NullableString16 old_value;
-  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
-      OpenStorageArea(kOrigin)->SetItem(kKey, kValue, &old_value));
-  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
-      OpenStorageArea(kSessionOnlyOrigin)->SetItem(kKey, kValue, &old_value));
+  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)
+                  ->OpenStorageArea(kOrigin)
+                  ->SetItem(kKey, kValue, old_value, &old_value));
+  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)
+                  ->OpenStorageArea(kSessionOnlyOrigin)
+                  ->SetItem(kKey, kValue, old_value, &old_value));
   context_->Shutdown();
   context_ = NULL;
   base::RunLoop().RunUntilIdle();
@@ -161,8 +164,9 @@
   // Store data for a session-only origin, setup to save session data, then
   // shutdown.
   base::NullableString16 old_value;
-  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
-      OpenStorageArea(kSessionOnlyOrigin)->SetItem(kKey, kValue, &old_value));
+  EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)
+                  ->OpenStorageArea(kSessionOnlyOrigin)
+                  ->SetItem(kKey, kValue, old_value, &old_value));
   context_->SetForceKeepSessionState();  // Should override clear behavior.
   context_->Shutdown();
   context_ = NULL;
@@ -220,7 +224,7 @@
   const base::string16 kKey(ASCIIToUTF16("foo"));
   const base::string16 kValue(ASCIIToUTF16("bar"));
   base::NullableString16 old_nullable_value;
-  area->SetItem(kKey, kValue, &old_nullable_value);
+  area->SetItem(kKey, kValue, old_nullable_value, &old_nullable_value);
   dom_namespace->CloseStorageArea(area);
 
   // Destroy and recreate the DOMStorageContextImpl.
@@ -238,8 +242,7 @@
   dom_namespace = context_->GetStorageNamespace(kSessionStorageNamespaceId);
   area = dom_namespace->OpenStorageArea(kOrigin);
   base::NullableString16 read_value;
-  read_value = area->GetItem(kKey);
-  EXPECT_EQ(kValue, read_value.string());
+  EXPECT_EQ(kKey, area->Key(0).string());
   dom_namespace->CloseStorageArea(area);
 
   SessionStorageUsageInfo info;
@@ -261,8 +264,8 @@
                                    kPersistentId);
   dom_namespace = context_->GetStorageNamespace(kSessionStorageNamespaceId);
   area = dom_namespace->OpenStorageArea(kOrigin);
-  read_value = area->GetItem(kKey);
-  EXPECT_TRUE(read_value.is_null());
+
+  EXPECT_EQ(0u, area->Length());
   dom_namespace->CloseStorageArea(area);
   context_->Shutdown();
   context_ = NULL;
@@ -272,7 +275,8 @@
 TEST_F(DOMStorageContextImplTest, PurgeMemory) {
   auto* dom_namespace = context_->GetStorageNamespace(kLocalStorageNamespaceId);
   auto* area1 = dom_namespace->OpenStorageArea(kOrigin);
-  area1->InitialImportIfNeeded();
+  base::NullableString16 old_value;
+  area1->SetItem(kKey, kValue, old_value, &old_value);
 
   // PURGE_UNOPENED does not delete the open area.
   context_->PurgeMemory(DOMStorageContextImpl::PURGE_UNOPENED);
@@ -282,17 +286,17 @@
   // PURGE_UNOPENED deletes the unopened area.
   dom_namespace->CloseStorageArea(area1);
   EXPECT_EQ(1u, dom_namespace->GetUsageStatistics().inactive_area_count);
+  area1->CommitChanges(area1->GetCurrentCommitBatch()->batch.get());
+  area1->commit_batches_.clear();
   context_->PurgeMemory(DOMStorageContextImpl::PURGE_UNOPENED);
   EXPECT_EQ(0u, dom_namespace->GetUsageStatistics().total_area_count);
 
   // Add an item to the database and commit changes, and keep it open. So, cache
   // is kept alive.
   auto* area2 = dom_namespace->OpenStorageArea(kOrigin);
-  base::NullableString16 old_value;
-  area2->SetItem(kKey, kValue, &old_value);
-  // Call commit directly instead of posting task.
-  area2->CommitChanges(area2->commit_batch_.get());
-  area2->commit_batch_ = nullptr;
+  area2->SetItem(kKey, kValue, old_value, &old_value);
+  area2->CommitChanges(area2->GetCurrentCommitBatch()->batch.get());
+  area2->commit_batches_.clear();
 
   // PURGE_AGGRESSIVE clears the cache in the open area.
   EXPECT_NE(0u, dom_namespace->GetUsageStatistics().total_cache_size);
@@ -313,6 +317,8 @@
       context_->GetStorageNamespace(kLocalStorageNamespaceId);
   DOMStorageArea* origin_area = dom_namespace->OpenStorageArea(kOrigin);
   DOMStorageArea* suborigin_area = dom_namespace->OpenStorageArea(kSuborigin);
+  origin_area->SetCacheOnlyKeys(false);
+  suborigin_area->SetCacheOnlyKeys(false);
 
   const base::string16 kOriginKey(ASCIIToUTF16("foo"));
   const base::string16 kOriginValue(ASCIIToUTF16("bar"));
@@ -321,8 +327,10 @@
   base::NullableString16 old_nullable_value;
 
   // Setup data for the first deletion (of the origin rather than the suborigin)
-  origin_area->SetItem(kOriginKey, kOriginValue, &old_nullable_value);
-  suborigin_area->SetItem(kSuboriginKey, kSuboriginValue, &old_nullable_value);
+  origin_area->SetItem(kOriginKey, kOriginValue, old_nullable_value,
+                       &old_nullable_value);
+  suborigin_area->SetItem(kSuboriginKey, kSuboriginValue, old_nullable_value,
+                          &old_nullable_value);
 
   base::NullableString16 read_value;
   read_value = origin_area->GetItem(kOriginKey);
@@ -341,8 +349,10 @@
 
   // Setup data again for the second deletion (of the suborigin rather than the
   // origin)
-  origin_area->SetItem(kOriginKey, kOriginValue, &old_nullable_value);
-  suborigin_area->SetItem(kSuboriginKey, kSuboriginValue, &old_nullable_value);
+  origin_area->SetItem(kOriginKey, kOriginValue, old_nullable_value,
+                       &old_nullable_value);
+  suborigin_area->SetItem(kSuboriginKey, kSuboriginValue, old_nullable_value,
+                          &old_nullable_value);
 
   read_value = origin_area->GetItem(kOriginKey);
   EXPECT_EQ(kOriginValue, read_value.string());
@@ -360,8 +370,10 @@
 
   // Setup data again for the third deletion, to test deleting the storage one
   // at a time.
-  origin_area->SetItem(kOriginKey, kOriginValue, &old_nullable_value);
-  suborigin_area->SetItem(kSuboriginKey, kSuboriginValue, &old_nullable_value);
+  origin_area->SetItem(kOriginKey, kOriginValue, old_nullable_value,
+                       &old_nullable_value);
+  suborigin_area->SetItem(kSuboriginKey, kSuboriginValue, old_nullable_value,
+                          &old_nullable_value);
 
   read_value = origin_area->GetItem(kOriginKey);
   EXPECT_EQ(kOriginValue, read_value.string());
@@ -377,7 +389,8 @@
   EXPECT_EQ(kSuboriginValue, read_value.string());
 
   // Put the origin value back so suborigin deletion can be tested.
-  origin_area->SetItem(kOriginKey, kOriginValue, &old_nullable_value);
+  origin_area->SetItem(kOriginKey, kOriginValue, old_nullable_value,
+                       &old_nullable_value);
 
   read_value = origin_area->GetItem(kOriginKey);
   EXPECT_EQ(kOriginValue, read_value.string());
diff --git a/content/browser/dom_storage/dom_storage_database.h b/content/browser/dom_storage/dom_storage_database.h
index 9f5fd4a..996de6d6 100644
--- a/content/browser/dom_storage/dom_storage_database.h
+++ b/content/browser/dom_storage/dom_storage_database.h
@@ -75,6 +75,8 @@
   FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest,
                            TestCanOpenFileThatIsNotADatabase);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, BackingDatabaseOpened);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, ShallowCopyWithBacking);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, EnableDisableCachingWithBacking);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitTasks);
   FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, PurgeMemory);
 
diff --git a/content/browser/dom_storage/dom_storage_host.cc b/content/browser/dom_storage/dom_storage_host.cc
index f085668e..a509f08 100644
--- a/content/browser/dom_storage/dom_storage_host.cc
+++ b/content/browser/dom_storage/dom_storage_host.cc
@@ -68,7 +68,7 @@
   DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area)
     return false;
-  if (!area->IsLoadedInMemory()) {
+  if (area->IsMapReloadNeeded()) {
     DOMStorageNamespace* ns = GetNamespace(connection_id);
     DCHECK(ns);
     context_->PurgeMemory(DOMStorageContextImpl::PURGE_IF_NEEDED);
@@ -109,7 +109,7 @@
   if (!area)
     return false;
   base::NullableString16 old_value;
-  if (!area->SetItem(key, value, &old_value))
+  if (!area->SetItem(key, value, client_old_value, &old_value))
     return false;
   if (old_value.is_null() || old_value.string() != value)
     context_->NotifyItemSet(area, key, value, old_value, page_url);
@@ -125,7 +125,7 @@
   if (!area)
     return false;
   base::string16 old_value;
-  if (!area->RemoveItem(key, &old_value))
+  if (!area->RemoveItem(key, client_old_value, &old_value))
     return false;
   context_->NotifyItemRemoved(area, key, old_value, page_url);
   return true;
diff --git a/content/browser/dom_storage/dom_storage_namespace.cc b/content/browser/dom_storage/dom_storage_namespace.cc
index a448665..5a44fb6 100644
--- a/content/browser/dom_storage/dom_storage_namespace.cc
+++ b/content/browser/dom_storage/dom_storage_namespace.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "build/build_config.h"
 #include "content/browser/dom_storage/dom_storage_area.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
 #include "content/browser/dom_storage/session_storage_database.h"
@@ -40,15 +41,19 @@
 DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
   if (AreaHolder* holder = GetAreaHolder(origin)) {
     ++(holder->open_count_);
+#if defined(OS_ANDROID)
+    if (holder->open_count_ > 1)
+      holder->area_->SetCacheOnlyKeys(false);
+#endif
     return holder->area_.get();
   }
   DOMStorageArea* area;
   if (namespace_id_ == kLocalStorageNamespaceId) {
     area = new DOMStorageArea(origin, directory_, task_runner_.get());
   } else {
-    area = new DOMStorageArea(
-        namespace_id_, persistent_namespace_id_, origin,
-        session_storage_database_.get(), task_runner_.get());
+    area = new DOMStorageArea(namespace_id_, persistent_namespace_id_, nullptr,
+                              origin, session_storage_database_.get(),
+                              task_runner_.get());
   }
   areas_[origin] = AreaHolder(area, 1);
   return area;
@@ -59,8 +64,8 @@
   DCHECK(holder);
   DCHECK_EQ(holder->area_.get(), area);
   --(holder->open_count_);
-  // TODO(michaeln): Clean up areas that aren't needed in memory anymore.
-  // The in-process-webkit based impl didn't do this either, but would be nice.
+  // TODO(ssid): disable caching when the open count goes to 0 and it's safe,
+  // crbug.com/743187.
 }
 
 DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
@@ -86,13 +91,16 @@
     clone->areas_[it->first] = AreaHolder(area, 0);
   }
   // And clone the on-disk structures, too.
-  if (session_storage_database_.get()) {
-    task_runner_->PostShutdownBlockingTask(
-        FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE,
-        base::BindOnce(
-            base::IgnoreResult(&SessionStorageDatabase::CloneNamespace),
-            session_storage_database_.get(), persistent_namespace_id_,
-            clone_persistent_namespace_id));
+  if (session_storage_database_) {
+    auto clone_task = base::BindOnce(
+        base::IgnoreResult(&SessionStorageDatabase::CloneNamespace),
+        session_storage_database_, persistent_namespace_id_,
+        clone_persistent_namespace_id);
+    auto callback =
+        base::BindOnce(&DOMStorageNamespace::OnCloneStorageDone, clone);
+    task_runner_->GetSequencedTaskRunner(DOMStorageTaskRunner::COMMIT_SEQUENCE)
+        ->PostTaskAndReply(FROM_HERE, std::move(clone_task),
+                           std::move(callback));
   }
   return clone;
 }
@@ -172,8 +180,8 @@
     const {
   UsageStatistics stats = {0};
   for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) {
-    if (it->second.area_->IsLoadedInMemory()) {
-      stats.total_cache_size += it->second.area_->map_usage_in_bytes();
+    if (it->second.area_->map_memory_used()) {
+      stats.total_cache_size += it->second.area_->map_memory_used();
       ++stats.total_area_count;
       if (it->second.open_count_ == 0)
         ++stats.inactive_area_count;
@@ -211,6 +219,14 @@
   return &(found->second);
 }
 
+void DOMStorageNamespace::OnCloneStorageDone() {
+  task_runner_->AssertIsRunningOnPrimarySequence();
+  // Shallow copy of commit batches are no longer needed since the database is
+  // cloned.
+  for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it)
+    it->second.area_->ClearShallowCopiedCommitBatches();
+}
+
 // AreaHolder
 
 DOMStorageNamespace::AreaHolder::AreaHolder()
@@ -222,7 +238,12 @@
     : area_(area), open_count_(count) {
 }
 
-DOMStorageNamespace::AreaHolder::AreaHolder(const AreaHolder& other) = default;
+DOMStorageNamespace::AreaHolder& DOMStorageNamespace::AreaHolder::operator=(
+    AreaHolder&& other) {
+  area_ = std::move(other.area_);
+  open_count_ = other.open_count_;
+  return *this;
+}
 
 DOMStorageNamespace::AreaHolder::~AreaHolder() {
 }
diff --git a/content/browser/dom_storage/dom_storage_namespace.h b/content/browser/dom_storage/dom_storage_namespace.h
index 2fdab5a..9eb8bb5 100644
--- a/content/browser/dom_storage/dom_storage_namespace.h
+++ b/content/browser/dom_storage/dom_storage_namespace.h
@@ -95,10 +95,12 @@
   struct AreaHolder {
     scoped_refptr<DOMStorageArea> area_;
     int open_count_;
+
     AreaHolder();
     AreaHolder(DOMStorageArea* area, int count);
-    AreaHolder(const AreaHolder& other);
+    AreaHolder& operator=(AreaHolder&& other);
     ~AreaHolder();
+    DISALLOW_COPY_AND_ASSIGN(AreaHolder);
   };
   typedef std::map<GURL, AreaHolder> AreaMap;
 
@@ -107,12 +109,14 @@
   // Returns a pointer to the area holder in our map or NULL.
   AreaHolder* GetAreaHolder(const GURL& origin);
 
+  void OnCloneStorageDone();
+
   int64_t namespace_id_;
-  std::string persistent_namespace_id_;
+  const std::string persistent_namespace_id_;
   base::FilePath directory_;
   AreaMap areas_;
-  scoped_refptr<DOMStorageTaskRunner> task_runner_;
-  scoped_refptr<SessionStorageDatabase> session_storage_database_;
+  const scoped_refptr<DOMStorageTaskRunner> task_runner_;
+  const scoped_refptr<SessionStorageDatabase> session_storage_database_;
 };
 
 }  // namespace content
diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
index 28cf0bdf..b829354e4 100644
--- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
@@ -696,7 +696,7 @@
   DOMStorageNamespace* local = local_storage_namespace();
   DOMStorageArea* area = local->OpenStorageArea(origin1.GetURL());
   base::NullableString16 dummy;
-  area->SetItem(key, value, &dummy);
+  area->SetItem(key, value, dummy, &dummy);
   local->CloseStorageArea(area);
   FlushAndPurgeDOMStorageMemory();
 
diff --git a/content/browser/dom_storage/local_storage_database_adapter.h b/content/browser/dom_storage/local_storage_database_adapter.h
index f61407e..f1ec577d 100644
--- a/content/browser/dom_storage/local_storage_database_adapter.h
+++ b/content/browser/dom_storage/local_storage_database_adapter.h
@@ -39,10 +39,11 @@
 
  private:
   FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, BackingDatabaseOpened);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitChangesAtShutdown);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitTasks);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, DeleteOrigin);
-  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, PurgeMemory);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, SetCacheOnlyKeysWithBacking);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, CommitChangesAtShutdown);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, CommitTasks);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, DeleteOrigin);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, PurgeMemory);
 
   std::unique_ptr<DOMStorageDatabase> db_;
 
diff --git a/content/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc
index 7fed2c6..5615b5a0 100644
--- a/content/browser/dom_storage/session_storage_database.cc
+++ b/content/browser/dom_storage/session_storage_database.cc
@@ -110,9 +110,11 @@
 SessionStorageDatabase::~SessionStorageDatabase() {
 }
 
-void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id,
-                                            const GURL& origin,
-                                            DOMStorageValuesMap* result) {
+void SessionStorageDatabase::ReadAreaValues(
+    const std::string& namespace_id,
+    const std::vector<std::string>& original_permanent_namespace_ids,
+    const GURL& origin,
+    DOMStorageValuesMap* result) {
   // We don't create a database if it doesn't exist. In that case, there is
   // nothing to be added to the result.
   if (!LazyOpen(false))
@@ -131,6 +133,26 @@
   if (GetMapForArea(namespace_id, origin.spec(), options, &exists, &map_id) &&
       exists)
     ReadMap(map_id, options, result, false);
+
+  if (exists) {
+    db_->ReleaseSnapshot(options.snapshot);
+    return;
+  }
+
+  // If the area does not exist, |namespace_id| might refer to a clone that
+  // is not yet created. Reading from the original database is expected to be
+  // consistent because tasks posted on commit sequence after clone did not
+  // before capturing the snapshot.
+  for (const auto& original_db_id : original_permanent_namespace_ids) {
+    map_id.clear();
+    if (GetMapForArea(original_db_id, origin.spec(), options, &exists,
+                      &map_id) &&
+        exists) {
+      ReadMap(map_id, options, result, false);
+    }
+    if (exists)
+      break;
+  }
   db_->ReleaseSnapshot(options.snapshot);
 }
 
@@ -187,7 +209,8 @@
 }
 
 bool SessionStorageDatabase::CloneNamespace(
-    const std::string& namespace_id, const std::string& new_namespace_id) {
+    const std::string& namespace_id,
+    const std::string& new_namespace_id) {
   // Go through all origins in the namespace |namespace_id|, create placeholders
   // for them in |new_namespace_id|, and associate them with the existing maps.
 
diff --git a/content/browser/dom_storage/session_storage_database.h b/content/browser/dom_storage/session_storage_database.h
index 2c48aec2..a7ea8ae 100644
--- a/content/browser/dom_storage/session_storage_database.h
+++ b/content/browser/dom_storage/session_storage_database.h
@@ -10,8 +10,11 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <vector>
 
+#include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
@@ -51,9 +54,11 @@
   // assumed to be empty and any duplicate keys will be overwritten. If the
   // database exists on disk then it will be opened. If it does not exist then
   // it will not be created and |result| will be unmodified.
-  void ReadAreaValues(const std::string& namespace_id,
-                      const GURL& origin,
-                      DOMStorageValuesMap* result);
+  void ReadAreaValues(
+      const std::string& namespace_id,
+      const std::vector<std::string>& original_permanent_namespace_ids,
+      const GURL& origin,
+      DOMStorageValuesMap* result);
 
   // Updates the data for |namespace_id| and |origin|. Will remove all keys
   // before updating the database if |clear_all_first| is set. Then all entries
@@ -89,6 +94,7 @@
   class DBOperation;
   friend class SessionStorageDatabase::DBOperation;
   friend class SessionStorageDatabaseTest;
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaParamTest, ShallowCopyWithBacking);
 
   ~SessionStorageDatabase();
 
diff --git a/content/browser/dom_storage/session_storage_database_adapter.cc b/content/browser/dom_storage/session_storage_database_adapter.cc
index 69f5bcd..1bd52500 100644
--- a/content/browser/dom_storage/session_storage_database_adapter.cc
+++ b/content/browser/dom_storage/session_storage_database_adapter.cc
@@ -11,16 +11,18 @@
 SessionStorageDatabaseAdapter::SessionStorageDatabaseAdapter(
     SessionStorageDatabase* db,
     const std::string& permanent_namespace_id,
+    const std::vector<std::string>& original_permanent_namespace_ids,
     const GURL& origin)
     : db_(db),
       permanent_namespace_id_(permanent_namespace_id),
-      origin_(origin) {
-}
+      original_permanent_namespace_ids_(original_permanent_namespace_ids),
+      origin_(origin) {}
 
 SessionStorageDatabaseAdapter::~SessionStorageDatabaseAdapter() { }
 
 void SessionStorageDatabaseAdapter::ReadAllValues(DOMStorageValuesMap* result) {
-  db_->ReadAreaValues(permanent_namespace_id_, origin_, result);
+  db_->ReadAreaValues(permanent_namespace_id_,
+                      original_permanent_namespace_ids_, origin_, result);
 }
 
 bool SessionStorageDatabaseAdapter::CommitChanges(
diff --git a/content/browser/dom_storage/session_storage_database_adapter.h b/content/browser/dom_storage/session_storage_database_adapter.h
index de929842..63d1b2598 100644
--- a/content/browser/dom_storage/session_storage_database_adapter.h
+++ b/content/browser/dom_storage/session_storage_database_adapter.h
@@ -5,6 +5,9 @@
 #ifndef CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
 #define CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
 
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "content/browser/dom_storage/dom_storage_database_adapter.h"
@@ -16,9 +19,11 @@
 
 class SessionStorageDatabaseAdapter : public DOMStorageDatabaseAdapter {
  public:
-  SessionStorageDatabaseAdapter(SessionStorageDatabase* db,
-                                const std::string& permanent_namespace_id,
-                                const GURL& origin);
+  SessionStorageDatabaseAdapter(
+      SessionStorageDatabase* db,
+      const std::string& permanent_namespace_id,
+      const std::vector<std::string>& original_permanent_namespace_ids,
+      const GURL& origin);
   ~SessionStorageDatabaseAdapter() override;
   void ReadAllValues(DOMStorageValuesMap* result) override;
   bool CommitChanges(bool clear_all_first,
@@ -27,6 +32,8 @@
  private:
   scoped_refptr<SessionStorageDatabase> db_;
   std::string permanent_namespace_id_;
+  // IDs of original databases in order of ShallowCopy(s).
+  std::vector<std::string> original_permanent_namespace_ids_;
   GURL origin_;
 
   DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabaseAdapter);
diff --git a/content/browser/dom_storage/session_storage_database_unittest.cc b/content/browser/dom_storage/session_storage_database_unittest.cc
index 21c23bb..1f67c8d 100644
--- a/content/browser/dom_storage/session_storage_database_unittest.cc
+++ b/content/browser/dom_storage/session_storage_database_unittest.cc
@@ -322,7 +322,8 @@
     const std::string& namespace_id, const GURL& origin,
     const DOMStorageValuesMap& reference) const {
   DOMStorageValuesMap values;
-  db_->ReadAreaValues(namespace_id, origin, &values);
+  db_->ReadAreaValues(namespace_id, std::vector<std::string>(), origin,
+                      &values);
   CompareValuesMaps(values, reference);
 }
 
@@ -486,6 +487,19 @@
   data2[kKey1] = kValue2;
   data2[kKey3] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
+
+  // Check if passing original id before cloning returns the original's data.
+  DOMStorageValuesMap values;
+  std::vector<std::string> original_ids;
+  original_ids.push_back(kNamespace1);
+  db_->ReadAreaValues(kNamespaceClone, original_ids, kOrigin1, &values);
+  CompareValuesMaps(values, data1);
+
+  original_ids.insert(original_ids.begin(), kNamespace2);
+  values.clear();
+  db_->ReadAreaValues(kNamespaceClone, original_ids, kOrigin1, &values);
+  CompareValuesMaps(values, data1);
+
   // Make a shallow copy.
   EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone));
   // Now both namespaces should have the same data.
@@ -708,7 +722,8 @@
   EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes));
   CheckDatabaseConsistency();
   DOMStorageValuesMap values;
-  db_->ReadAreaValues(kNamespace1, kOrigin1, &values);
+  db_->ReadAreaValues(kNamespace1, std::vector<std::string>(), kOrigin1,
+                      &values);
   const unsigned char* data =
       reinterpret_cast<const unsigned char*>(values[kKey1].string().data());
   for (int i = 0; i < 10; ++i)
diff --git a/content/browser/frame_host/keep_alive_handle_factory.cc b/content/browser/frame_host/keep_alive_handle_factory.cc
new file mode 100644
index 0000000..08ab034
--- /dev/null
+++ b/content/browser/frame_host/keep_alive_handle_factory.cc
@@ -0,0 +1,105 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/frame_host/keep_alive_handle_factory.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/content_features.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
+
+namespace content {
+
+namespace {
+constexpr base::TimeDelta kDefaultTimeout = base::TimeDelta::FromSeconds(30);
+}  // namespace
+
+class KeepAliveHandleFactory::Context final : public base::RefCounted<Context> {
+ public:
+  explicit Context(RenderProcessHost* process_host)
+      : process_id_(process_host->GetID()), weak_ptr_factory_(this) {
+    DCHECK(!process_host->IsKeepAliveRefCountDisabled());
+    process_host->IncrementKeepAliveRefCount();
+  }
+
+  void Detach() {
+    if (detached_)
+      return;
+    detached_ = true;
+    RenderProcessHost* process_host = RenderProcessHost::FromID(process_id_);
+    if (!process_host || process_host->IsKeepAliveRefCountDisabled())
+      return;
+
+    process_host->DecrementKeepAliveRefCount();
+  }
+
+  void DetachLater() {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    auto timeout = kDefaultTimeout;
+    int timeout_set_by_finch_in_sec = base::GetFieldTrialParamByFeatureAsInt(
+        features::kKeepAliveRendererForKeepaliveRequests, "timeout_in_sec",
+        kDefaultTimeout.InSeconds());
+    // Adopt only "reasonable" values.
+    if (timeout_set_by_finch_in_sec > 0 && timeout_set_by_finch_in_sec <= 60) {
+      timeout = base::TimeDelta::FromSeconds(timeout_set_by_finch_in_sec);
+    } else {
+      DVLOG(0) << "'timeout_in_sec' param for "
+               << "'keep-alive-renderer-for-keepalive-requests' is ignored "
+               << "due to out of range.";
+    }
+    BrowserThread::PostDelayedTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&Context::Detach, weak_ptr_factory_.GetWeakPtr()),
+        timeout);
+  }
+
+  void AddBinding(std::unique_ptr<mojom::KeepAliveHandle> impl,
+                  mojom::KeepAliveHandleRequest request) {
+    binding_set_.AddBinding(std::move(impl), std::move(request));
+  }
+
+ private:
+  friend class base::RefCounted<Context>;
+  ~Context() { Detach(); }
+
+  mojo::StrongBindingSet<mojom::KeepAliveHandle> binding_set_;
+  const int process_id_;
+  bool detached_ = false;
+
+  base::WeakPtrFactory<Context> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(Context);
+};
+
+class KeepAliveHandleFactory::KeepAliveHandleImpl final
+    : public mojom::KeepAliveHandle {
+ public:
+  explicit KeepAliveHandleImpl(scoped_refptr<Context> context)
+      : context_(std::move(context)) {}
+  ~KeepAliveHandleImpl() override {}
+
+ private:
+  scoped_refptr<Context> context_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeepAliveHandleImpl);
+};
+
+KeepAliveHandleFactory::KeepAliveHandleFactory(RenderProcessHost* process_host)
+    : context_(base::MakeRefCounted<Context>(process_host)) {}
+
+KeepAliveHandleFactory::~KeepAliveHandleFactory() {
+  context_->DetachLater();
+}
+
+void KeepAliveHandleFactory::Create(mojom::KeepAliveHandleRequest request) {
+  context_->AddBinding(base::MakeUnique<KeepAliveHandleImpl>(context_),
+                       std::move(request));
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/keep_alive_handle_factory.h b/content/browser/frame_host/keep_alive_handle_factory.h
new file mode 100644
index 0000000..a03493e98
--- /dev/null
+++ b/content/browser/frame_host/keep_alive_handle_factory.h
@@ -0,0 +1,40 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FRAME_HOST_KEEP_ALIVE_HANDLE_FACTORY_H_
+#define CONTENT_BROWSER_FRAME_HOST_KEEP_ALIVE_HANDLE_FACTORY_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/frame.mojom.h"
+
+namespace content {
+
+class RenderProcessHost;
+
+// A KeepAliveHandleFactory creates mojom::KeepAliveHandle. Each created
+// handle prolongs the associated renderer's lifetime by using
+// RenderProcessHost's KeepAliveRefCounts while alive.
+// When a certain time (default: 30sec) passes after the factory is destroyed,
+// all created handles are invalidated, which will result in render process
+// shutdown.
+class KeepAliveHandleFactory final {
+ public:
+  // |process_host->DisableKeepAliveRefCount()| must be false.
+  explicit KeepAliveHandleFactory(RenderProcessHost* process_host);
+  ~KeepAliveHandleFactory();
+
+  void Create(mojom::KeepAliveHandleRequest request);
+
+ private:
+  class KeepAliveHandleImpl;
+  class Context;
+
+  scoped_refptr<Context> context_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeepAliveHandleFactory);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_KEEP_ALIVE_HANDLE_FACTORY_H_
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index c30cfa4d..4539339 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -990,7 +990,7 @@
 
   NotifyNavigationEntryCommitted(details);
 
-  if (active_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+  if (active_entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
     UMA_HISTOGRAM_BOOLEAN("Navigation.SecureSchemeHasSSLStatus",
                           !!active_entry->GetSSL().certificate);
   }
@@ -1155,7 +1155,8 @@
       // this case.
       new_entry->GetSSL() = SSLStatus();
 
-      if (new_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+      if (new_entry->GetURL().SchemeIs(url::kHttpsScheme) &&
+          !rfh->GetParent()) {
         UMA_HISTOGRAM_BOOLEAN(
             "Navigation.SecureSchemeHasSSLStatus.NewPageInPageOriginMismatch",
             !!new_entry->GetSSL().certificate);
@@ -1168,7 +1169,7 @@
 
     update_virtual_url = new_entry->update_virtual_url_with_url();
 
-    if (new_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+    if (new_entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
       UMA_HISTOGRAM_BOOLEAN("Navigation.SecureSchemeHasSSLStatus.NewPageInPage",
                             !!new_entry->GetSSL().certificate);
     }
@@ -1192,7 +1193,7 @@
     update_virtual_url = new_entry->update_virtual_url_with_url();
     new_entry->GetSSL() = handle->ssl_status();
 
-    if (new_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+    if (new_entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
       UMA_HISTOGRAM_BOOLEAN(
           "Navigation.SecureSchemeHasSSLStatus.NewPagePendingEntryMatches",
           !!new_entry->GetSSL().certificate);
@@ -1219,7 +1220,7 @@
     update_virtual_url = needs_update;
     new_entry->GetSSL() = handle->ssl_status();
 
-    if (new_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+    if (new_entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
       UMA_HISTOGRAM_BOOLEAN(
           "Navigation.SecureSchemeHasSSLStatus.NewPageNoMatchingEntry",
           !!new_entry->GetSSL().certificate);
@@ -1297,7 +1298,7 @@
     if (!is_same_document)
       entry->GetSSL() = handle->ssl_status();
 
-    if (entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+    if (entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
       bool has_cert = !!entry->GetSSL().certificate;
       if (is_same_document) {
         UMA_HISTOGRAM_BOOLEAN(
@@ -1336,7 +1337,7 @@
         entry->GetSSL() = handle->ssl_status();
     }
 
-    if (entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+    if (entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
       bool has_cert = !!entry->GetSSL().certificate;
       if (is_same_document && was_restored) {
         UMA_HISTOGRAM_BOOLEAN(
@@ -1370,7 +1371,7 @@
     if (!is_same_document)
       entry->GetSSL() = handle->ssl_status();
 
-    if (entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+    if (entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
       bool has_cert = !!entry->GetSSL().certificate;
       if (is_same_document) {
         UMA_HISTOGRAM_BOOLEAN(
@@ -1461,7 +1462,8 @@
   // update the SSL status.
   existing_entry->GetSSL() = handle->ssl_status();
 
-  if (existing_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+  if (existing_entry->GetURL().SchemeIs(url::kHttpsScheme) &&
+      !rfh->GetParent()) {
     UMA_HISTOGRAM_BOOLEAN("Navigation.SecureSchemeHasSSLStatus.SamePage",
                           !!existing_entry->GetSSL().certificate);
   }
@@ -1505,7 +1507,7 @@
           frame_entry.get(), is_same_document, rfh->frame_tree_node(),
           delegate_->GetFrameTree()->root());
 
-  if (new_entry->GetURL().SchemeIs(url::kHttpsScheme)) {
+  if (new_entry->GetURL().SchemeIs(url::kHttpsScheme) && !rfh->GetParent()) {
     UMA_HISTOGRAM_BOOLEAN("Navigation.SecureSchemeHasSSLStatus.NewSubFrame",
                           !!new_entry->GetSSL().certificate);
   }
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 7e577c8..53b4b1d 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -34,6 +34,7 @@
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/input/input_injector_impl.h"
 #include "content/browser/frame_host/input/legacy_ipc_frame_input_handler.h"
+#include "content/browser/frame_host/keep_alive_handle_factory.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
@@ -2847,6 +2848,25 @@
       main_frame_route_id, main_frame_widget_route_id, cloned_namespace->id());
 }
 
+void RenderFrameHostImpl::IssueKeepAliveHandle(
+    mojom::KeepAliveHandleRequest request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!base::FeatureList::IsEnabled(
+          features::kKeepAliveRendererForKeepaliveRequests)) {
+    bad_message::ReceivedBadMessage(
+        GetProcess(), bad_message::RFH_KEEP_ALIVE_HANDLE_REQUESTED_INCORRECTLY);
+    return;
+  }
+  if (GetProcess()->IsKeepAliveRefCountDisabled())
+    return;
+
+  if (!keep_alive_handle_factory_) {
+    keep_alive_handle_factory_ =
+        base::MakeUnique<KeepAliveHandleFactory>(GetProcess());
+  }
+  keep_alive_handle_factory_->Create(std::move(request));
+}
+
 void RenderFrameHostImpl::RunCreateWindowCompleteCallback(
     CreateNewWindowCallback callback,
     mojom::CreateNewWindowReplyPtr reply,
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 9a4fa29d..97034be 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -96,6 +96,7 @@
 class FrameTree;
 class FrameTreeNode;
 class GeolocationServiceImpl;
+class KeepAliveHandleFactory;
 class MediaInterfaceProxy;
 class NavigationHandleImpl;
 class PermissionServiceContext;
@@ -839,6 +840,7 @@
   // mojom::FrameHost
   void CreateNewWindow(mojom::CreateNewWindowParamsPtr params,
                        CreateNewWindowCallback callback) override;
+  void IssueKeepAliveHandle(mojom::KeepAliveHandleRequest request) override;
 
   void RunCreateWindowCompleteCallback(CreateNewWindowCallback callback,
                                        mojom::CreateNewWindowReplyPtr reply,
@@ -1305,6 +1307,8 @@
   mojom::FrameInputHandlerPtr frame_input_handler_;
   std::unique_ptr<LegacyIPCFrameInputHandler> legacy_frame_input_handler_;
 
+  std::unique_ptr<KeepAliveHandleFactory> keep_alive_handle_factory_;
+
   // NOTE: This must be the last member.
   base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
 
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index c440d80..bd3194a 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -442,9 +442,11 @@
     // TODO: merge this with code path below for non-network service.
     std::unique_ptr<net::CanonicalCookie> cc =
         net::CanonicalCookie::Create(url, cookie, base::Time::Now(), options);
-    cookie_manager_->SetCanonicalCookie(*cc, url.SchemeIsCryptographic(),
-                                        !options.exclude_httponly(),
-                                        net::CookieStore::SetCookiesCallback());
+    if (cc) {
+      cookie_manager_->SetCanonicalCookie(
+          *cc, url.SchemeIsCryptographic(), !options.exclude_httponly(),
+          net::CookieStore::SetCookiesCallback());
+    }
     return;
   }
 
diff --git a/content/browser/histogram_internals_url_loader.cc b/content/browser/histogram_internals_url_loader.cc
index 8e38a9b6..3c1e985 100644
--- a/content/browser/histogram_internals_url_loader.cc
+++ b/content/browser/histogram_internals_url_loader.cc
@@ -26,7 +26,10 @@
   CHECK(mojo::common::BlockingCopyFromString(data, data_pipe.producer_handle));
 
   client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
-  client->OnComplete(ResourceRequestCompletionStatus(data.size()));
+  ResourceRequestCompletionStatus status(net::OK);
+  status.encoded_data_length = data.size();
+  status.encoded_body_length = data.size();
+  client->OnComplete(status);
 }
 
 }  // namespace content
diff --git a/content/browser/image_capture/OWNERS b/content/browser/image_capture/OWNERS
index d9e863e..c261502 100644
--- a/content/browser/image_capture/OWNERS
+++ b/content/browser/image_capture/OWNERS
@@ -2,3 +2,4 @@
 miu@chromium.org
 
 # COMPONENT: Blink>ImageCapture
+# TEAM: media-dev@chromium.org
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 096839f1..2f36a89 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -1811,7 +1811,19 @@
       any_requests_transferring = true;
     if (cancel_all_routes || route_id == info->GetRenderFrameID()) {
       if (info->detachable_handler()) {
-        info->detachable_handler()->Detach();
+        if (base::FeatureList::IsEnabled(
+                features::kKeepAliveRendererForKeepaliveRequests)) {
+          // If the feature is enabled, the renderer process's lifetime is
+          // prolonged so there's no need to detach.
+          if (cancel_all_routes) {
+            // If the process is going to shut down for other reasons, we need
+            // to cancel the request.
+            matching_requests.push_back(id);
+          }
+        } else {
+          // Otherwise, use DetachableResourceHandler's functionality.
+          info->detachable_handler()->Detach();
+        }
       } else if (!info->IsDownload() && !info->is_stream() &&
                  !IsTransferredNavigation(id)) {
         matching_requests.push_back(id);
diff --git a/content/browser/media/media_browsertest.cc b/content/browser/media/media_browsertest.cc
index 239bfb2..1345092 100644
--- a/content/browser/media/media_browsertest.cc
+++ b/content/browser/media/media_browsertest.cc
@@ -241,6 +241,15 @@
 IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated270) {
   RunVideoSizeTest("bear_rotate_270.mp4", 720, 1280);
 }
+
+// Android can't reliably load lots of videos on a page.
+// See http://crbug.com/749265
+#if !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(MediaTest, LoadManyVideos) {
+  base::StringPairs query_params;
+  RunMediaTestPage("load_many_videos.html", query_params, kEnded, true);
+}
+#endif  // !defined(OS_ANDROID)
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
 #if defined(OS_CHROMEOS)
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index b44340c..700109a 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -467,8 +467,10 @@
     // called in the same call stack and so to ensure that the fallback surface
     // is set, then primary surface must be set prior to calling
     // CompositorFrameSinkSupport::SubmitCompositorFrame.
-    bool result =
-        support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
+    // TODO(kenrb): Supply HitTestRegionList data here as described in
+    // crbug.com/750755.
+    bool result = support_->SubmitCompositorFrame(local_surface_id,
+                                                  std::move(frame), nullptr);
     DCHECK(result);
   }
   local_surface_id_ = local_surface_id;
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
index f85a8db7..e665a622 100644
--- a/content/browser/renderer_host/input/web_input_event_builders_mac.mm
+++ b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -195,6 +195,18 @@
   return ui::DomKey::UNIDENTIFIED;
 }
 
+blink::WebMouseEvent::Button ButtonFromPressedMouseButtons() {
+  NSUInteger pressed_buttons = [NSEvent pressedMouseButtons];
+
+  if (pressed_buttons & (1 << 0))
+    return blink::WebMouseEvent::Button::kLeft;
+  if (pressed_buttons & (1 << 1))
+    return blink::WebMouseEvent::Button::kRight;
+  if (pressed_buttons & (1 << 2))
+    return blink::WebMouseEvent::Button::kMiddle;
+  return blink::WebMouseEvent::Button::kNoButton;
+}
+
 }  // namespace
 
 blink::WebKeyboardEvent WebKeyboardEventBuilder::Build(NSEvent* event) {
@@ -296,6 +308,7 @@
     case NSMouseMoved:
     case NSMouseEntered:
       event_type = blink::WebInputEvent::kMouseMove;
+      button = ButtonFromPressedMouseButtons();
       break;
     case NSLeftMouseDragged:
       event_type = blink::WebInputEvent::kMouseMove;
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
index 1155857..e0d8bfc1 100644
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
@@ -77,6 +77,14 @@
     base::OnceClosure done_cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(state_ == State::READY_TO_LAUNCH);
+  if (receiver) {
+    std::ostringstream string_stream;
+    string_stream
+        << "InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync: Posting "
+           "start request to device thread for device_id = "
+        << device_id;
+    receiver->OnLog(string_stream.str());
+  }
 
   const int max_buffers =
       (stream_type == MEDIA_TAB_VIDEO_CAPTURE ? kMaxNumberOfBuffersForTabCapture
diff --git a/content/browser/renderer_host/media/in_process_video_capture_provider.cc b/content/browser/renderer_host/media/in_process_video_capture_provider.cc
index 5b9bbce9..e5a4df65 100644
--- a/content/browser/renderer_host/media/in_process_video_capture_provider.cc
+++ b/content/browser/renderer_host/media/in_process_video_capture_provider.cc
@@ -10,9 +10,11 @@
 
 InProcessVideoCaptureProvider::InProcessVideoCaptureProvider(
     std::unique_ptr<media::VideoCaptureSystem> video_capture_system,
-    scoped_refptr<base::SingleThreadTaskRunner> device_task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
+    base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
     : video_capture_system_(std::move(video_capture_system)),
-      device_task_runner_(std::move(device_task_runner)) {
+      device_task_runner_(std::move(device_task_runner)),
+      emit_log_message_cb_(std::move(emit_log_message_cb)) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
@@ -23,28 +25,36 @@
 // static
 std::unique_ptr<VideoCaptureProvider>
 InProcessVideoCaptureProvider::CreateInstanceForNonDeviceCapture(
-    scoped_refptr<base::SingleThreadTaskRunner> device_task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
+    base::RepeatingCallback<void(const std::string&)> emit_log_message_cb) {
   return base::MakeUnique<InProcessVideoCaptureProvider>(
-      nullptr, std::move(device_task_runner));
+      nullptr, std::move(device_task_runner), std::move(emit_log_message_cb));
 }
 
 // static
 std::unique_ptr<VideoCaptureProvider>
 InProcessVideoCaptureProvider::CreateInstance(
     std::unique_ptr<media::VideoCaptureSystem> video_capture_system,
-    scoped_refptr<base::SingleThreadTaskRunner> device_task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
+    base::RepeatingCallback<void(const std::string&)> emit_log_message_cb) {
   return base::MakeUnique<InProcessVideoCaptureProvider>(
-      std::move(video_capture_system), std::move(device_task_runner));
+      std::move(video_capture_system), std::move(device_task_runner),
+      std::move(emit_log_message_cb));
 }
 
 void InProcessVideoCaptureProvider::GetDeviceInfosAsync(
     GetDeviceInfosCallback result_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!video_capture_system_) {
+    emit_log_message_cb_.Run(
+        "InProcessVideoCaptureProvider::GetDeviceInfosAsync: No video capture "
+        "system, returning empty results.");
     std::vector<media::VideoCaptureDeviceInfo> empty_result;
     base::ResetAndReturn(&result_callback).Run(empty_result);
     return;
   }
+  emit_log_message_cb_.Run(
+      "InProcessVideoCaptureProvider::GetDeviceInfosAsync");
   // Using Unretained() is safe because |this| owns
   // |video_capture_system_| and |result_callback| has ownership of
   // |this|.
diff --git a/content/browser/renderer_host/media/in_process_video_capture_provider.h b/content/browser/renderer_host/media/in_process_video_capture_provider.h
index 5405a54c..b713f0d 100644
--- a/content/browser/renderer_host/media/in_process_video_capture_provider.h
+++ b/content/browser/renderer_host/media/in_process_video_capture_provider.h
@@ -18,17 +18,20 @@
  public:
   InProcessVideoCaptureProvider(
       std::unique_ptr<media::VideoCaptureSystem> video_capture_system,
-      scoped_refptr<base::SingleThreadTaskRunner> device_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
+      base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
 
   ~InProcessVideoCaptureProvider() override;
 
   static std::unique_ptr<VideoCaptureProvider>
   CreateInstanceForNonDeviceCapture(
-      scoped_refptr<base::SingleThreadTaskRunner> device_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
+      base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
 
   static std::unique_ptr<VideoCaptureProvider> CreateInstance(
       std::unique_ptr<media::VideoCaptureSystem> video_capture_system,
-      scoped_refptr<base::SingleThreadTaskRunner> device_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
+      base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
 
   void GetDeviceInfosAsync(GetDeviceInfosCallback result_callback) override;
 
@@ -39,6 +42,7 @@
   const std::unique_ptr<media::VideoCaptureSystem> video_capture_system_;
   // The message loop of media stream device thread, where VCD's live.
   const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
+  base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 };
diff --git a/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
index 7cc37705..f0daa8a 100644
--- a/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
@@ -54,6 +54,8 @@
 const char* const kDefaultVideoDeviceID = kZeroResolutionVideoDeviceID;
 const char kDefaultAudioDeviceID[] = "fake_audio_input_2";
 
+const auto kIgnoreLogMessageCB = base::BindRepeating([](const std::string&) {});
+
 void PhysicalDevicesEnumerated(base::Closure quit_closure,
                                MediaDeviceEnumeration* out,
                                const MediaDeviceEnumeration& enumeration) {
@@ -103,7 +105,7 @@
     auto video_capture_provider =
         base::MakeUnique<InProcessVideoCaptureProvider>(
             std::move(video_capture_system),
-            base::ThreadTaskRunnerHandle::Get());
+            base::ThreadTaskRunnerHandle::Get(), kIgnoreLogMessageCB);
 
     media_stream_manager_ = base::MakeUnique<MediaStreamManager>(
         audio_system_.get(), audio_manager_->GetTaskRunner(),
diff --git a/content/browser/renderer_host/media/media_devices_manager_unittest.cc b/content/browser/renderer_host/media/media_devices_manager_unittest.cc
index 0c78d24..8e81ce4 100644
--- a/content/browser/renderer_host/media/media_devices_manager_unittest.cc
+++ b/content/browser/renderer_host/media/media_devices_manager_unittest.cc
@@ -38,6 +38,7 @@
 // is performed when cache is enabled, regardless of the number of client calls.
 const int kNumCalls = 3;
 
+const auto kIgnoreLogMessageCB = base::BindRepeating([](const std::string&) {});
 // This class mocks the audio manager and overrides some methods to ensure that
 // we can run simulate device changes.
 class MockAudioManager : public media::FakeAudioManager {
@@ -152,9 +153,9 @@
     auto video_capture_provider =
         base::MakeUnique<InProcessVideoCaptureProvider>(
             std::move(video_capture_system),
-            base::ThreadTaskRunnerHandle::Get());
-    video_capture_manager_ =
-        new VideoCaptureManager(std::move(video_capture_provider));
+            base::ThreadTaskRunnerHandle::Get(), kIgnoreLogMessageCB);
+    video_capture_manager_ = new VideoCaptureManager(
+        std::move(video_capture_provider), kIgnoreLogMessageCB);
     media_devices_manager_.reset(new MediaDevicesManager(
         audio_system_.get(), video_capture_manager_, nullptr));
   }
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
index c7bc368..0fa6124 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -67,16 +67,8 @@
   DVLOG(1) << __func__ << " label= " << label;
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  // TODO(c.padhi): Remove this when OnStreamGenerated's input types are
-  // changed to MediaStreamDevice, see https://crbug.com/760493.
-  StreamDeviceInfoArray audio_array, video_array;
-  for (const MediaStreamDevice& device : audio_devices)
-    audio_array.push_back(StreamDeviceInfo(device));
-  for (const MediaStreamDevice& device : video_devices)
-    video_array.push_back(StreamDeviceInfo(device));
-
   GetMediaStreamDispatcherForFrame(render_frame_id)
-      ->OnStreamGenerated(page_request_id, label, audio_array, video_array);
+      ->OnStreamGenerated(page_request_id, label, audio_devices, video_devices);
 }
 
 void MediaStreamDispatcherHost::StreamGenerationFailed(
@@ -99,7 +91,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   GetMediaStreamDispatcherForFrame(render_frame_id)
-      ->OnDeviceStopped(label, StreamDeviceInfo(device));
+      ->OnDeviceStopped(label, device);
 }
 
 void MediaStreamDispatcherHost::DeviceOpened(int render_frame_id,
@@ -110,7 +102,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   GetMediaStreamDispatcherForFrame(render_frame_id)
-      ->OnDeviceOpened(page_request_id, label, StreamDeviceInfo(device));
+      ->OnDeviceOpened(page_request_id, label, device);
 }
 
 mojom::MediaStreamDispatcher*
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 1788e194..c4d0c63 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -130,9 +130,9 @@
   // mojom::MediaStreamDispatcher implementation.
   void OnStreamGenerated(int32_t request_id,
                          const std::string& label,
-                         const StreamDeviceInfoArray& audio_array,
-                         const StreamDeviceInfoArray& video_array) override {
-    OnStreamGeneratedInternal(request_id, label, audio_array, video_array);
+                         const MediaStreamDevices& audio_devices,
+                         const MediaStreamDevices& video_devices) override {
+    OnStreamGeneratedInternal(request_id, label, audio_devices, video_devices);
   }
 
   void OnStreamGenerationFailed(int32_t request_id,
@@ -142,15 +142,15 @@
 
   void OnDeviceOpened(int32_t request_id,
                       const std::string& label,
-                      const StreamDeviceInfo& device_info) override {
-    OnDeviceOpenedInternal(request_id, label, device_info);
+                      const MediaStreamDevice& device) override {
+    OnDeviceOpenedInternal(request_id, label, device);
   }
 
   void OnDeviceOpenFailed(int32_t request_id) override {}
 
   void OnDeviceStopped(const std::string& label,
-                       const StreamDeviceInfo& device_info) override {
-    OnDeviceStoppedInternal(label, device_info);
+                       const MediaStreamDevice& device) override {
+    OnDeviceStoppedInternal(label, device);
   }
 
   mojom::MediaStreamDispatcherPtr CreateInterfacePtrAndBind() {
@@ -160,19 +160,18 @@
   }
 
   std::string label_;
-  StreamDeviceInfoArray audio_devices_;
-  StreamDeviceInfoArray video_devices_;
-  StreamDeviceInfo opened_device_;
+  MediaStreamDevices audio_devices_;
+  MediaStreamDevices video_devices_;
+  MediaStreamDevice opened_device_;
 
  private:
   // These handler methods do minimal things and delegate to the mock methods.
-  void OnStreamGeneratedInternal(
-      int request_id,
-      std::string label,
-      StreamDeviceInfoArray audio_device_list,
-      StreamDeviceInfoArray video_device_list) {
-    OnStreamGenerationSuccess(request_id, audio_device_list.size(),
-                              video_device_list.size());
+  void OnStreamGeneratedInternal(int request_id,
+                                 std::string label,
+                                 const MediaStreamDevices& audio_devices,
+                                 const MediaStreamDevices& video_devices) {
+    OnStreamGenerationSuccess(request_id, audio_devices.size(),
+                              video_devices.size());
     // Simulate the stream started event back to host for UI testing.
     OnStreamStarted(label);
 
@@ -182,8 +181,8 @@
     task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
 
     label_ = label;
-    audio_devices_ = audio_device_list;
-    video_devices_ = video_device_list;
+    audio_devices_ = audio_devices;
+    video_devices_ = video_devices;
   }
 
   void OnStreamGenerationFailedInternal(int request_id,
@@ -199,18 +198,18 @@
   }
 
   void OnDeviceStoppedInternal(const std::string& label,
-                               const StreamDeviceInfo& device) {
-    if (IsVideoMediaType(device.device.type))
-      EXPECT_TRUE(StreamDeviceInfo::IsEqual(device, video_devices_[0]));
-    if (IsAudioInputMediaType(device.device.type))
-      EXPECT_TRUE(StreamDeviceInfo::IsEqual(device, audio_devices_[0]));
+                               const MediaStreamDevice& device) {
+    if (IsVideoMediaType(device.type))
+      EXPECT_TRUE(device.IsSameDevice(video_devices_[0]));
+    if (IsAudioInputMediaType(device.type))
+      EXPECT_TRUE(device.IsSameDevice(audio_devices_[0]));
 
     OnDeviceStopSuccess();
   }
 
   void OnDeviceOpenedInternal(int request_id,
                               const std::string& label,
-                              const StreamDeviceInfo& device) {
+                              const MediaStreamDevice& device) {
     base::Closure quit_closure = quit_closures_.front();
     quit_closures_.pop();
     task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
@@ -370,26 +369,25 @@
     EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->video_devices_, origin_));
   }
 
-  bool DoesContainRawIds(const StreamDeviceInfoArray& devices) {
+  bool DoesContainRawIds(const MediaStreamDevices& devices) {
     for (size_t i = 0; i < devices.size(); ++i) {
-      if (devices[i].device.id !=
-              media::AudioDeviceDescription::kDefaultDeviceId &&
-          devices[i].device.id !=
+      if (devices[i].id != media::AudioDeviceDescription::kDefaultDeviceId &&
+          devices[i].id !=
               media::AudioDeviceDescription::kCommunicationsDeviceId) {
         for (const auto& audio_device : audio_device_descriptions_) {
-          if (audio_device.unique_id == devices[i].device.id)
+          if (audio_device.unique_id == devices[i].id)
             return true;
         }
       }
       for (const std::string& device_id : stub_video_device_ids_) {
-        if (device_id == devices[i].device.id)
+        if (device_id == devices[i].id)
           return true;
       }
     }
     return false;
   }
 
-  bool DoesEveryDeviceMapToRawId(const StreamDeviceInfoArray& devices,
+  bool DoesEveryDeviceMapToRawId(const MediaStreamDevices& devices,
                                  const url::Origin& origin) {
     for (size_t i = 0; i < devices.size(); ++i) {
       bool found_match = false;
@@ -397,7 +395,7 @@
           audio_device_descriptions_.begin();
       for (; audio_it != audio_device_descriptions_.end(); ++audio_it) {
         if (DoesMediaDeviceIDMatchHMAC(browser_context_.GetMediaDeviceIDSalt(),
-                                       origin, devices[i].device.id,
+                                       origin, devices[i].id,
                                        audio_it->unique_id)) {
           EXPECT_FALSE(found_match);
           found_match = true;
@@ -405,8 +403,7 @@
       }
       for (const std::string& device_id : stub_video_device_ids_) {
         if (DoesMediaDeviceIDMatchHMAC(browser_context_.GetMediaDeviceIDSalt(),
-                                       origin, devices[i].device.id,
-                                       device_id)) {
+                                       origin, devices[i].id, device_id)) {
           EXPECT_FALSE(found_match);
           found_match = true;
         }
@@ -417,24 +414,6 @@
     return true;
   }
 
-  // Returns true if all devices have labels, false otherwise.
-  bool DoesContainLabels(const StreamDeviceInfoArray& devices) {
-    for (size_t i = 0; i < devices.size(); ++i) {
-      if (devices[i].device.name.empty())
-        return false;
-    }
-    return true;
-  }
-
-  // Returns true if no devices have labels, false otherwise.
-  bool DoesNotContainLabels(const StreamDeviceInfoArray& devices) {
-    for (size_t i = 0; i < devices.size(); ++i) {
-      if (!devices[i].device.name.empty())
-        return false;
-    }
-    return true;
-  }
-
   std::unique_ptr<MockMediaStreamDispatcherHost> host_;
   std::unique_ptr<MediaStreamManager> media_stream_manager_;
   TestBrowserThreadBundle thread_bundle_;
@@ -509,7 +488,7 @@
   // host_->video_devices_[0] contains the information about generated video
   // stream device (the depth device).
   const base::Optional<CameraCalibration> calibration =
-      host_->video_devices_[0].device.camera_calibration;
+      host_->video_devices_[0].camera_calibration;
   EXPECT_TRUE(calibration);
   EXPECT_EQ(calibration->focal_length_x, kStubFocalLengthX);
   EXPECT_EQ(calibration->focal_length_y, kStubFocalLengthY);
@@ -531,7 +510,7 @@
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
   const std::string label1 = host_->label_;
-  const std::string device_id1 = host_->video_devices_.front().device.id;
+  const std::string device_id1 = host_->video_devices_.front().id;
   const int session_id1 = host_->video_devices_.front().session_id;
 
   // Generate second stream.
@@ -542,7 +521,7 @@
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
   const std::string label2 = host_->label_;
-  const std::string device_id2 = host_->video_devices_.front().device.id;
+  const std::string device_id2 = host_->video_devices_.front().id;
   int session_id2 = host_->video_devices_.front().session_id;
   EXPECT_EQ(device_id1, device_id2);
   EXPECT_EQ(session_id1, session_id2);
@@ -560,13 +539,13 @@
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
   const std::string label1 = host_->label_;
-  const std::string device_id1 = host_->video_devices_.front().device.id;
+  const std::string device_id1 = host_->video_devices_.front().id;
   const int session_id1 = host_->video_devices_.front().session_id;
 
   // Generate second stream.
   OpenVideoDeviceAndWaitForResult(kRenderId, kPageRequestId, device_id1);
 
-  const std::string device_id2 = host_->opened_device_.device.id;
+  const std::string device_id2 = host_->opened_device_.id;
   const int session_id2 = host_->opened_device_.session_id;
   const std::string label2 = host_->label_;
 
@@ -589,7 +568,7 @@
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
   const std::string label1 = host_->label_;
-  const std::string device_id1 = host_->video_devices_.front().device.id;
+  const std::string device_id1 = host_->video_devices_.front().id;
   const int session_id1 = host_->video_devices_.front().session_id;
 
   // Generate second stream from another render frame.
@@ -604,7 +583,7 @@
   EXPECT_EQ(host_->audio_devices_.size(), 0u);
   EXPECT_EQ(host_->video_devices_.size(), 1u);
   const std::string label2 = host_->label_;
-  const std::string device_id2 = host_->video_devices_.front().device.id;
+  const std::string device_id2 = host_->video_devices_.front().id;
   const int session_id2 = host_->video_devices_.front().session_id;
   EXPECT_EQ(device_id1, device_id2);
   EXPECT_NE(session_id1, session_id2);
@@ -654,7 +633,7 @@
 
     SetupFakeUI(true);
     GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
-    EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
+    EXPECT_EQ(host_->audio_devices_[0].id, source_id);
   }
 
   for (const std::string& device_id : stub_video_device_ids_) {
@@ -666,7 +645,7 @@
 
     SetupFakeUI(true);
     GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
-    EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
+    EXPECT_EQ(host_->video_devices_[0].id, source_id);
   }
 }
 
@@ -707,17 +686,16 @@
   GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   std::string stream_request_label = host_->label_;
-  StreamDeviceInfo video_device_info = host_->video_devices_.front();
+  MediaStreamDevice video_device = host_->video_devices_.front();
   ASSERT_EQ(1u, media_stream_manager_->GetDevicesOpenedByRequest(
       stream_request_label).size());
 
   // Open the same device by Pepper.
-  OpenVideoDeviceAndWaitForResult(kRenderId, kPageRequestId,
-                                  video_device_info.device.id);
+  OpenVideoDeviceAndWaitForResult(kRenderId, kPageRequestId, video_device.id);
   std::string open_device_request_label = host_->label_;
 
   // Stop the device in the MediaStream.
-  host_->OnStopStreamDevice(kRenderId, video_device_info.device.id);
+  host_->OnStopStreamDevice(kRenderId, video_device.id);
 
   EXPECT_EQ(0u, media_stream_manager_->GetDevicesOpenedByRequest(
       stream_request_label).size());
@@ -732,12 +710,12 @@
   GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
 
   std::string request_label1 = host_->label_;
-  StreamDeviceInfo video_device_info = host_->video_devices_.front();
+  MediaStreamDevice video_device = host_->video_devices_.front();
   // Expect that 1 audio and 1 video device has been opened.
   EXPECT_EQ(2u, media_stream_manager_->GetDevicesOpenedByRequest(
       request_label1).size());
 
-  host_->OnStopStreamDevice(kRenderId, video_device_info.device.id);
+  host_->OnStopStreamDevice(kRenderId, video_device.id);
   EXPECT_EQ(1u, media_stream_manager_->GetDevicesOpenedByRequest(
       request_label1).size());
 
@@ -774,7 +752,7 @@
 
   // Stop the video stream device from stream 1 while waiting for the
   // second stream to be generated.
-  host_->OnStopStreamDevice(kRenderId, host_->video_devices_[0].device.id);
+  host_->OnStopStreamDevice(kRenderId, host_->video_devices_[0].id);
   run_loop1.Run();
 
   EXPECT_EQ(host_->video_devices_.size(), 1u);
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 2ddf793..07d63d6 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -213,6 +213,10 @@
   return NUM_MEDIA_DEVICE_TYPES;
 }
 
+void SendVideoCaptureLogMessage(const std::string& message) {
+  MediaStreamManager::SendMessageToNativeLog("video capture: " + message);
+}
+
 }  // namespace
 
 
@@ -428,9 +432,11 @@
 #endif
     if (base::FeatureList::IsEnabled(video_capture::kMojoVideoCapture)) {
       video_capture_provider = base::MakeUnique<VideoCaptureProviderSwitcher>(
-          base::MakeUnique<ServiceVideoCaptureProvider>(),
+          base::MakeUnique<ServiceVideoCaptureProvider>(
+              base::BindRepeating(&SendVideoCaptureLogMessage)),
           InProcessVideoCaptureProvider::CreateInstanceForNonDeviceCapture(
-              std::move(device_task_runner)));
+              std::move(device_task_runner),
+              base::BindRepeating(&SendVideoCaptureLogMessage)));
     } else {
       video_capture::uma::LogVideoCaptureServiceEvent(
           video_capture::uma::BROWSER_USING_LEGACY_CAPTURE);
@@ -439,7 +445,8 @@
               media::VideoCaptureDeviceFactory::CreateFactory(
                   BrowserThread::GetTaskRunnerForThread(BrowserThread::UI),
                   BrowserGpuMemoryBufferManager::current())),
-          std::move(device_task_runner));
+          std::move(device_task_runner),
+          base::BindRepeating(&SendVideoCaptureLogMessage));
     }
   }
   InitializeMaybeAsync(std::move(video_capture_provider));
@@ -1295,7 +1302,8 @@
           "457525 MediaStreamManager::InitializeDeviceManagersOnIOThread 4"));
 
   video_capture_manager_ =
-      new VideoCaptureManager(std::move(video_capture_provider));
+      new VideoCaptureManager(std::move(video_capture_provider),
+                              base::BindRepeating(&SendVideoCaptureLogMessage));
   video_capture_manager_->RegisterListener(this);
 
   media_devices_manager_.reset(
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy.cc b/content/browser/renderer_host/media/media_stream_ui_proxy.cc
index 92c903a..096d2def0 100644
--- a/content/browser/renderer_host/media/media_stream_ui_proxy.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_proxy.cc
@@ -7,13 +7,16 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_delegate.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "media/capture/video/fake_video_capture_device.h"
+#include "third_party/WebKit/public/platform/WebFeaturePolicyFeature.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -50,10 +53,13 @@
   void RequestAccess(std::unique_ptr<MediaStreamRequest> request);
   void OnStarted(gfx::NativeViewId* window_id);
 
- private:
-  void ProcessAccessRequestResponse(const MediaStreamDevices& devices,
+  void ProcessAccessRequestResponse(int render_process_id,
+                                    int render_frame_id,
+                                    const MediaStreamDevices& devices,
                                     content::MediaStreamRequestResult result,
                                     std::unique_ptr<MediaStreamUI> stream_ui);
+
+ private:
   void ProcessStopRequestFromUI();
   RenderFrameHostDelegate* GetRenderFrameHostDelegate(int render_process_id,
                                                       int render_frame_id);
@@ -90,7 +96,8 @@
 
   // Tab may have gone away, or has no delegate from which to request access.
   if (!render_delegate) {
-    ProcessAccessRequestResponse(MediaStreamDevices(),
+    ProcessAccessRequestResponse(request->render_process_id,
+                                 request->render_frame_id, MediaStreamDevices(),
                                  MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
                                  std::unique_ptr<MediaStreamUI>());
     return;
@@ -98,8 +105,10 @@
   SetAndCheckAncestorFlag(request.get());
 
   render_delegate->RequestMediaAccessPermission(
-      *request, base::Bind(&Core::ProcessAccessRequestResponse,
-                           weak_factory_.GetWeakPtr()));
+      *request,
+      base::Bind(&Core::ProcessAccessRequestResponse,
+                 weak_factory_.GetWeakPtr(), request->render_process_id,
+                 request->render_frame_id));
 }
 
 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
@@ -111,16 +120,42 @@
 }
 
 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse(
+    int render_process_id,
+    int render_frame_id,
     const MediaStreamDevices& devices,
     content::MediaStreamRequestResult result,
     std::unique_ptr<MediaStreamUI> stream_ui) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+  MediaStreamDevices filtered_devices;
+  if (base::FeatureList::IsEnabled(features::kUseFeaturePolicyForPermissions)) {
+    RenderFrameHost* host =
+        RenderFrameHost::FromID(render_process_id, render_frame_id);
+    for (const MediaStreamDevice& device : devices) {
+      if (device.type == MEDIA_DEVICE_AUDIO_CAPTURE &&
+          !host->IsFeatureEnabled(
+              blink::WebFeaturePolicyFeature::kMicrophone)) {
+        continue;
+      }
+
+      if (device.type == MEDIA_DEVICE_VIDEO_CAPTURE &&
+          !host->IsFeatureEnabled(blink::WebFeaturePolicyFeature::kCamera)) {
+        continue;
+      }
+
+      filtered_devices.push_back(device);
+    }
+    if (filtered_devices.empty() && result == MEDIA_DEVICE_OK)
+      result = MEDIA_DEVICE_PERMISSION_DENIED;
+  } else {
+    filtered_devices = devices;
+  }
+
   ui_ = std::move(stream_ui);
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::BindOnce(&MediaStreamUIProxy::ProcessAccessRequestResponse, proxy_,
-                     devices, result));
+                     filtered_devices, result));
 }
 
 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
@@ -249,10 +284,12 @@
           switches::kUseFakeUIForMediaStream) == "deny") {
     // Immediately deny the request.
     BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&MediaStreamUIProxy::ProcessAccessRequestResponse,
-                       weak_factory_.GetWeakPtr(), MediaStreamDevices(),
-                       MEDIA_DEVICE_PERMISSION_DENIED));
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&MediaStreamUIProxy::Core::ProcessAccessRequestResponse,
+                       base::Unretained(core_.get()),
+                       request->render_process_id, request->render_frame_id,
+                       MediaStreamDevices(), MEDIA_DEVICE_PERMISSION_DENIED,
+                       std::unique_ptr<MediaStreamUI>()));
     return;
   }
 
@@ -288,11 +325,13 @@
   }
 
   BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
+      BrowserThread::UI, FROM_HERE,
       base::BindOnce(
-          &MediaStreamUIProxy::ProcessAccessRequestResponse,
-          weak_factory_.GetWeakPtr(), devices_to_use,
-          devices_to_use.empty() ? MEDIA_DEVICE_NO_HARDWARE : MEDIA_DEVICE_OK));
+          &MediaStreamUIProxy::Core::ProcessAccessRequestResponse,
+          base::Unretained(core_.get()), request->render_process_id,
+          request->render_frame_id, devices_to_use,
+          devices_to_use.empty() ? MEDIA_DEVICE_NO_HARDWARE : MEDIA_DEVICE_OK,
+          std::unique_ptr<MediaStreamUI>()));
 }
 
 void FakeMediaStreamUIProxy::OnStarted(base::OnceClosure stop_callback,
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
index debd4c7..75e8c121 100644
--- a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
@@ -9,8 +9,11 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "content/browser/frame_host/render_frame_host_delegate.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/test_browser_thread.h"
+#include "content/test/test_render_frame_host.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
@@ -259,4 +262,173 @@
   base::RunLoop().RunUntilIdle();
 }
 
+// Basic tests for feature policy checks through the MediaStreamUIProxy. These
+// tests are not meant to cover every edge case as the FeaturePolicy class
+// itself is tested thoroughly in feature_policy_unittest.cc and in
+// render_frame_host_feature_policy_unittest.cc.
+class MediaStreamUIProxyFeaturePolicyTest
+    : public RenderViewHostImplTestHarness {
+ public:
+  void SetUp() override {
+    RenderViewHostImplTestHarness::SetUp();
+    NavigateAndCommit(GURL("https://example.com"));
+  }
+
+ protected:
+  // The header policy should only be set once on page load, so we refresh the
+  // page to simulate that.
+  void RefreshPageAndSetHeaderPolicy(RenderFrameHost* rfh,
+                                     blink::WebFeaturePolicyFeature feature,
+                                     bool enabled) {
+    NavigateAndCommit(rfh->GetLastCommittedURL());
+    std::vector<url::Origin> whitelist;
+    if (enabled)
+      whitelist.push_back(rfh->GetLastCommittedOrigin());
+    RenderFrameHostTester::For(rfh)->SimulateFeaturePolicyHeader(feature,
+                                                                 whitelist);
+  }
+
+  void GetResultForRequest(std::unique_ptr<MediaStreamRequest> request,
+                           MediaStreamDevices* devices_out,
+                           MediaStreamRequestResult* result_out) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    base::RunLoop run_loop;
+    quit_closure_ = run_loop.QuitClosure();
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(
+            &MediaStreamUIProxyFeaturePolicyTest::GetResultForRequestOnIOThread,
+            base::Unretained(this), base::Passed(&request)));
+    run_loop.Run();
+    *devices_out = devices_;
+    *result_out = result_;
+  }
+
+  std::unique_ptr<MediaStreamRequest> CreateRequest(RenderFrameHost* rfh,
+                                                    MediaStreamType mic_type,
+                                                    MediaStreamType cam_type) {
+    return base::MakeUnique<MediaStreamRequest>(
+        rfh->GetProcess()->GetID(), rfh->GetRoutingID(), 0,
+        rfh->GetLastCommittedURL(), false, MEDIA_GENERATE_STREAM, std::string(),
+        std::string(), mic_type, cam_type, false);
+  }
+
+ private:
+  class TestRFHDelegate : public RenderFrameHostDelegate {
+    void RequestMediaAccessPermission(
+        const MediaStreamRequest& request,
+        const MediaResponseCallback& callback) override {
+      MediaStreamDevices devices;
+      if (request.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
+        devices.push_back(
+            MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic"));
+      }
+      if (request.video_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
+        devices.push_back(
+            MediaStreamDevice(MEDIA_DEVICE_VIDEO_CAPTURE, "Camera", "Camera"));
+      }
+      std::unique_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
+      callback.Run(devices, MEDIA_DEVICE_OK, std::move(ui));
+    }
+  };
+
+  void GetResultForRequestOnIOThread(
+      std::unique_ptr<MediaStreamRequest> request) {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    proxy_ = MediaStreamUIProxy::CreateForTests(&delegate_);
+    proxy_->RequestAccess(
+        std::move(request),
+        base::Bind(
+            &MediaStreamUIProxyFeaturePolicyTest::FinishedGetResultOnIOThread,
+            base::Unretained(this)));
+  }
+
+  void FinishedGetResultOnIOThread(const MediaStreamDevices& devices,
+                                   MediaStreamRequestResult result) {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    proxy_.reset();
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(&MediaStreamUIProxyFeaturePolicyTest::FinishedGetResult,
+                   base::Unretained(this), devices, result));
+  }
+
+  void FinishedGetResult(const MediaStreamDevices& devices,
+                         MediaStreamRequestResult result) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    devices_ = devices;
+    result_ = result;
+    quit_closure_.Run();
+  }
+
+  // These should only be accessed on the UI thread.
+  MediaStreamDevices devices_;
+  MediaStreamRequestResult result_;
+  base::Closure quit_closure_;
+
+  // These should only be accessed on the IO thread.
+  TestRFHDelegate delegate_;
+  std::unique_ptr<MediaStreamUIProxy> proxy_;
+};
+
+TEST_F(MediaStreamUIProxyFeaturePolicyTest, FeaturePolicy) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kUseFeaturePolicyForPermissions);
+  MediaStreamDevices devices;
+  MediaStreamRequestResult result;
+
+  // Default FP.
+  GetResultForRequest(CreateRequest(main_rfh(), MEDIA_DEVICE_AUDIO_CAPTURE,
+                                    MEDIA_DEVICE_VIDEO_CAPTURE),
+                      &devices, &result);
+  EXPECT_EQ(MEDIA_DEVICE_OK, result);
+  ASSERT_EQ(2u, devices.size());
+  EXPECT_EQ(MEDIA_DEVICE_AUDIO_CAPTURE, devices[0].type);
+  EXPECT_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, devices[1].type);
+
+  // Mic disabled.
+  RefreshPageAndSetHeaderPolicy(main_rfh(),
+                                blink::WebFeaturePolicyFeature::kMicrophone,
+                                /*enabled=*/false);
+  GetResultForRequest(CreateRequest(main_rfh(), MEDIA_DEVICE_AUDIO_CAPTURE,
+                                    MEDIA_DEVICE_VIDEO_CAPTURE),
+                      &devices, &result);
+  EXPECT_EQ(MEDIA_DEVICE_OK, result);
+  ASSERT_EQ(1u, devices.size());
+  EXPECT_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, devices[0].type);
+
+  // Camera disabled.
+  RefreshPageAndSetHeaderPolicy(main_rfh(),
+                                blink::WebFeaturePolicyFeature::kCamera,
+                                /*enabled=*/false);
+  GetResultForRequest(CreateRequest(main_rfh(), MEDIA_DEVICE_AUDIO_CAPTURE,
+                                    MEDIA_DEVICE_VIDEO_CAPTURE),
+                      &devices, &result);
+  EXPECT_EQ(MEDIA_DEVICE_OK, result);
+  ASSERT_EQ(1u, devices.size());
+  EXPECT_EQ(MEDIA_DEVICE_AUDIO_CAPTURE, devices[0].type);
+
+  // Camera disabled resulting in no devices being returned.
+  RefreshPageAndSetHeaderPolicy(main_rfh(),
+                                blink::WebFeaturePolicyFeature::kCamera,
+                                /*enabled=*/false);
+  GetResultForRequest(
+      CreateRequest(main_rfh(), MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE),
+      &devices, &result);
+  EXPECT_EQ(MEDIA_DEVICE_PERMISSION_DENIED, result);
+  ASSERT_EQ(0u, devices.size());
+
+  // Ensure that the policy is ignored if kUseFeaturePolicyForPermissions is
+  // disabled.
+  base::test::ScopedFeatureList empty_feature_list;
+  empty_feature_list.Init();
+  GetResultForRequest(CreateRequest(main_rfh(), MEDIA_DEVICE_AUDIO_CAPTURE,
+                                    MEDIA_DEVICE_VIDEO_CAPTURE),
+                      &devices, &result);
+  EXPECT_EQ(MEDIA_DEVICE_OK, result);
+  ASSERT_EQ(2u, devices.size());
+  EXPECT_EQ(MEDIA_DEVICE_AUDIO_CAPTURE, devices[0].type);
+  EXPECT_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, devices[1].type);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/media/service_video_capture_device_launcher.cc b/content/browser/renderer_host/media/service_video_capture_device_launcher.cc
index 1f6dce22..0c6a228 100644
--- a/content/browser/renderer_host/media/service_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/service_video_capture_device_launcher.cc
@@ -88,6 +88,16 @@
                                     callbacks, std::move(done_cb));
     return;
   }
+
+  if (receiver) {
+    std::ostringstream string_stream;
+    string_stream
+        << "ServiceVideoCaptureDeviceLauncher::LaunchDeviceAsync: Asking "
+           "video capture service to create device for device_id = "
+        << device_id;
+    receiver->OnLog(string_stream.str());
+  }
+
   video_capture::mojom::DevicePtr device;
   auto device_request = mojo::MakeRequest(&device);
   // Ownership of |done_cb| is moved to |this|. It is not sufficient to attach
diff --git a/content/browser/renderer_host/media/service_video_capture_provider.cc b/content/browser/renderer_host/media/service_video_capture_provider.cc
index 44155f1..df14047 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider.cc
+++ b/content/browser/renderer_host/media/service_video_capture_provider.cc
@@ -40,12 +40,16 @@
 
 namespace content {
 
-ServiceVideoCaptureProvider::ServiceVideoCaptureProvider()
-    : ServiceVideoCaptureProvider(base::MakeUnique<ServiceConnectorImpl>()) {}
+ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
+    base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
+    : ServiceVideoCaptureProvider(base::MakeUnique<ServiceConnectorImpl>(),
+                                  std::move(emit_log_message_cb)) {}
 
 ServiceVideoCaptureProvider::ServiceVideoCaptureProvider(
-    std::unique_ptr<ServiceConnector> service_connector)
+    std::unique_ptr<ServiceConnector> service_connector,
+    base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
     : service_connector_(std::move(service_connector)),
+      emit_log_message_cb_(std::move(emit_log_message_cb)),
       usage_count_(0),
       launcher_has_connected_to_device_factory_(false),
       weak_ptr_factory_(this) {
@@ -60,6 +64,7 @@
 void ServiceVideoCaptureProvider::GetDeviceInfosAsync(
     GetDeviceInfosCallback result_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  emit_log_message_cb_.Run("ServiceVideoCaptureProvider::GetDeviceInfosAsync");
   IncreaseUsageCount();
   LazyConnectToService();
   // Use a ScopedCallbackRunner to make sure that |result_callback| gets
@@ -129,6 +134,8 @@
 
 void ServiceVideoCaptureProvider::OnLostConnectionToDeviceFactory() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  emit_log_message_cb_.Run(
+      "ServiceVideoCaptureProvider::OnLostConnectionToDeviceFactory");
   // This may indicate that the video capture service has crashed. Uninitialize
   // here, so that a new connection will be established when clients try to
   // reconnect.
diff --git a/content/browser/renderer_host/media/service_video_capture_provider.h b/content/browser/renderer_host/media/service_video_capture_provider.h
index 85cd966..b91fb14 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider.h
+++ b/content/browser/renderer_host/media/service_video_capture_provider.h
@@ -30,10 +30,12 @@
   // The parameterless constructor creates a default ServiceConnector which
   // uses the ServiceManager associated with the current process to connect
   // to the video capture service.
-  ServiceVideoCaptureProvider();
-  // Lets clients provide a custom ServiceConnector.
   explicit ServiceVideoCaptureProvider(
-      std::unique_ptr<ServiceConnector> service_connector);
+      base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
+  // Lets clients provide a custom ServiceConnector.
+  ServiceVideoCaptureProvider(
+      std::unique_ptr<ServiceConnector> service_connector,
+      base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
   ~ServiceVideoCaptureProvider() override;
 
   // VideoCaptureProvider implementation.
@@ -54,6 +56,7 @@
   void UninitializeInternal(ReasonForUninitialize reason);
 
   std::unique_ptr<ServiceConnector> service_connector_;
+  base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
   // We must hold on to |device_factory_provider_| because it holds the
   // service-side binding for |device_factory_|.
   video_capture::mojom::DeviceFactoryProviderPtr device_factory_provider_;
diff --git a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
index 4564428..c5347f15 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
+++ b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
@@ -23,6 +23,8 @@
 static const std::string kStubDeviceId = "StubDevice";
 static const media::VideoCaptureParams kArbitraryParams;
 static const base::WeakPtr<media::VideoFrameReceiver> kNullReceiver;
+static const auto kIgnoreLogMessageCB =
+    base::BindRepeating([](const std::string&) {});
 
 class MockServiceConnector
     : public ServiceVideoCaptureProvider::ServiceConnector {
@@ -90,7 +92,7 @@
     auto mock_service_connector = base::MakeUnique<MockServiceConnector>();
     mock_service_connector_ = mock_service_connector.get();
     provider_ = base::MakeUnique<ServiceVideoCaptureProvider>(
-        std::move(mock_service_connector));
+        std::move(mock_service_connector), kIgnoreLogMessageCB);
 
     ON_CALL(*mock_service_connector_, BindFactoryProvider(_))
         .WillByDefault(
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index bee6fab..e9fb72a 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -167,12 +167,14 @@
     const std::string& device_id,
     MediaStreamType stream_type,
     const media::VideoCaptureParams& params,
-    std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher)
+    std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher,
+    base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
     : serial_id_(g_device_start_id++),
       device_id_(device_id),
       stream_type_(stream_type),
       parameters_(params),
       device_launcher_(std::move(device_launcher)),
+      emit_log_message_cb_(std::move(emit_log_message_cb)),
       device_launch_observer_(nullptr),
       state_(VIDEO_CAPTURE_STATE_STARTING),
       has_received_frames_(false),
@@ -193,9 +195,12 @@
     media::VideoCaptureSessionId session_id,
     const media::VideoCaptureParams& params) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "VideoCaptureController::AddClient() -- id=" << id
-           << ", session_id=" << session_id << ", params.requested_format="
-           << media::VideoCaptureFormat::ToString(params.requested_format);
+  std::ostringstream string_stream;
+  string_stream << "VideoCaptureController::AddClient(): id = " << id
+                << ", session_id = " << session_id
+                << ", params.requested_format = "
+                << media::VideoCaptureFormat::ToString(params.requested_format);
+  EmitLogMessage(string_stream.str(), 1);
 
   // Check that requested VideoCaptureParams are valid and supported.  If not,
   // report an error immediately and punt.
@@ -242,7 +247,9 @@
     VideoCaptureControllerID id,
     VideoCaptureControllerEventHandler* event_handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "VideoCaptureController::RemoveClient, id " << id;
+  std::ostringstream string_stream;
+  string_stream << "VideoCaptureController::RemoveClient: id = " << id;
+  EmitLogMessage(string_stream.str(), 1);
 
   ControllerClient* client = FindClient(id, event_handler, controller_clients_);
   if (!client)
@@ -268,7 +275,7 @@
     VideoCaptureControllerID id,
     VideoCaptureControllerEventHandler* event_handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "VideoCaptureController::PauseClient, id " << id;
+  DVLOG(1) << "VideoCaptureController::PauseClient: id = " << id;
 
   ControllerClient* client = FindClient(id, event_handler, controller_clients_);
   if (!client)
@@ -283,7 +290,7 @@
     VideoCaptureControllerID id,
     VideoCaptureControllerEventHandler* event_handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "VideoCaptureController::ResumeClient, id " << id;
+  DVLOG(1) << "VideoCaptureController::ResumeClient: id = " << id;
 
   ControllerClient* client = FindClient(id, event_handler, controller_clients_);
   if (!client)
@@ -323,7 +330,10 @@
 
 void VideoCaptureController::StopSession(int session_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id;
+  std::ostringstream string_stream;
+  string_stream << "VideoCaptureController::StopSession: session_id = "
+                << session_id;
+  EmitLogMessage(string_stream.str(), 1);
 
   ControllerClient* client = FindClient(session_id, controller_clients_);
 
@@ -477,7 +487,7 @@
 
 void VideoCaptureController::OnLog(const std::string& message) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  MediaStreamManager::SendMessageToNativeLog("Video capture: " + message);
+  EmitLogMessage(message, 3);
 }
 
 void VideoCaptureController::OnStarted() {
@@ -532,6 +542,11 @@
     VideoCaptureDeviceLaunchObserver* observer,
     base::OnceClosure done_cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  std::ostringstream string_stream;
+  string_stream
+      << "VideoCaptureController::CreateAndStartDeviceAsync: serial_id = "
+      << serial_id() << ", device_id = " << device_id();
+  EmitLogMessage(string_stream.str(), 1);
   time_of_start_request_ = base::TimeTicks::Now();
   device_launch_observer_ = observer;
   device_launcher_->LaunchDeviceAsync(
@@ -543,6 +558,10 @@
 
 void VideoCaptureController::ReleaseDeviceAsync(base::OnceClosure done_cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  std::ostringstream string_stream;
+  string_stream << "VideoCaptureController::ReleaseDeviceAsync: serial_id = "
+                << serial_id() << ", device_id = " << device_id();
+  EmitLogMessage(string_stream.str(), 1);
   if (!launched_device_) {
     device_launcher_->AbortLaunch();
     return;
@@ -686,4 +705,10 @@
   }
 }
 
+void VideoCaptureController::EmitLogMessage(const std::string& message,
+                                            int verbose_log_level) {
+  DVLOG(verbose_log_level) << message;
+  emit_log_message_cb_.Run(message);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h
index 6f7cd6a..39c7825c 100644
--- a/content/browser/renderer_host/media/video_capture_controller.h
+++ b/content/browser/renderer_host/media/video_capture_controller.h
@@ -44,7 +44,8 @@
       const std::string& device_id,
       MediaStreamType stream_type,
       const media::VideoCaptureParams& params,
-      std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher);
+      std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher,
+      base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
 
   base::WeakPtr<VideoCaptureController> GetWeakPtrForIOThread();
 
@@ -220,11 +221,14 @@
                           VideoCaptureControllerID id)>;
   void PerformForClientsWithOpenSession(EventHandlerAction action);
 
+  void EmitLogMessage(const std::string& message, int verbose_log_level);
+
   const int serial_id_;
   const std::string device_id_;
   const MediaStreamType stream_type_;
   const media::VideoCaptureParams parameters_;
   std::unique_ptr<VideoCaptureDeviceLauncher> device_launcher_;
+  base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
   std::unique_ptr<LaunchedVideoCaptureDevice> launched_device_;
   VideoCaptureDeviceLaunchObserver* device_launch_observer_;
 
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index 593039d..99d2280e 100644
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -142,7 +142,8 @@
     auto device_launcher = base::MakeUnique<MockVideoCaptureDeviceLauncher>();
     controller_ = new VideoCaptureController(
         arbitrary_device_id, arbitrary_stream_type, arbitrary_params,
-        std::move(device_launcher));
+        std::move(device_launcher),
+        base::BindRepeating([](const std::string&) {}));
     InitializeNewDeviceClientAndBufferPoolInstances();
     auto mock_launched_device =
         base::MakeUnique<MockLaunchedVideoCaptureDevice>();
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 09fe221..59616a01 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -102,9 +102,11 @@
     : controller_(controller), session_id_(session_id), params_(params) {}
 
 VideoCaptureManager::VideoCaptureManager(
-    std::unique_ptr<VideoCaptureProvider> video_capture_provider)
+    std::unique_ptr<VideoCaptureProvider> video_capture_provider,
+    base::RepeatingCallback<void(const std::string&)> emit_log_message_cb)
     : new_capture_session_id_(1),
-      video_capture_provider_(std::move(video_capture_provider)) {}
+      video_capture_provider_(std::move(video_capture_provider)),
+      emit_log_message_cb_(std::move(emit_log_message_cb)) {}
 
 VideoCaptureManager::~VideoCaptureManager() {
   DCHECK(controllers_.empty());
@@ -145,7 +147,7 @@
 void VideoCaptureManager::EnumerateDevices(
     const EnumerationCallback& client_callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "VideoCaptureManager::EnumerateDevices";
+  EmitLogMessage("VideoCaptureManager::EnumerateDevices", 1);
 
   // Pass a timer for UMA histogram collection.
   video_capture_provider_->GetDeviceInfosAsync(media::BindToCurrentLoop(
@@ -161,14 +163,18 @@
       new_capture_session_id_++;
 
   DCHECK(sessions_.find(capture_session_id) == sessions_.end());
-  DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id;
+  std::ostringstream string_stream;
+  string_stream << "VideoCaptureManager::Open, device.name = " << device.name
+                << ", device.id = " << device.id
+                << ", capture_session_id = " << capture_session_id;
+  EmitLogMessage(string_stream.str(), 1);
 
   // We just save the stream info for processing later.
   sessions_[capture_session_id] = device;
 
   // Notify our listener asynchronously; this ensures that we return
-  // |capture_session_id| to the caller of this function before using that same
-  // id in a listener event.
+  // |capture_session_id| to the caller of this function before using that
+  // same id in a listener event.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureManager::OnOpened, this,
                                 device.type, capture_session_id));
@@ -177,7 +183,10 @@
 
 void VideoCaptureManager::Close(int capture_session_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id;
+  std::ostringstream string_stream;
+  string_stream << "VideoCaptureManager::Close, capture_session_id = "
+                << capture_session_id;
+  EmitLogMessage(string_stream.str(), 1);
 
   SessionMap::iterator session_it = sessions_.find(capture_session_id);
   if (session_it == sessions_.end()) {
@@ -248,12 +257,6 @@
       observer.OnVideoCaptureStopped(device_info->descriptor.facing);
   }
 
-  DVLOG(3) << "DoStopDevice. Send stop request for device = "
-           << controller->device_id()
-           << " serial_id = " << controller->serial_id() << ".";
-  controller->OnLog(base::StringPrintf("Stopping device: id: %s",
-                                       controller->device_id().c_str()));
-
   // Since we may be removing |controller| from |controllers_| while
   // ReleaseDeviceAsnyc() is executing, we pass it shared ownership to
   // |controller|.
@@ -270,9 +273,7 @@
 
   VideoCaptureController* const controller = request->controller();
 
-  DVLOG(3) << "HandleQueuedStartRequest, Post start to device thread, device = "
-           << controller->device_id()
-           << " start id = " << controller->serial_id();
+  EmitLogMessage("VideoCaptureManager::ProcessDeviceStartRequestQueue", 3);
   // The unit test VideoCaptureManagerTest.OpenNotExisting requires us to fail
   // synchronously if the stream_type is MEDIA_DEVICE_VIDEO_CAPTURE and no
   // DeviceInfo matching the requested id is present (which is the case when
@@ -309,8 +310,11 @@
 }
 
 void VideoCaptureManager::OnDeviceLaunched(VideoCaptureController* controller) {
-  DVLOG(3) << __func__;
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  std::ostringstream string_stream;
+  string_stream << "Launching device has succeeded. device_id = "
+                << controller->device_id();
+  EmitLogMessage(string_stream.str(), 1);
   DCHECK(!device_start_request_queue_.empty());
   DCHECK_EQ(controller, device_start_request_queue_.begin()->controller());
   DCHECK(controller);
@@ -339,11 +343,10 @@
 
 void VideoCaptureManager::OnDeviceLaunchFailed(
     VideoCaptureController* controller) {
-  const std::string log_message = base::StringPrintf(
-      "Starting device %s has failed. Maybe recently disconnected?",
-      controller->device_id().c_str());
-  DLOG(ERROR) << log_message;
-  controller->OnLog(log_message);
+  std::ostringstream string_stream;
+  string_stream << "Launching device has failed. device_id = "
+                << controller->device_id();
+  EmitLogMessage(string_stream.str(), 1);
   controller->OnError();
 
   device_start_request_queue_.pop_front();
@@ -351,16 +354,17 @@
 }
 
 void VideoCaptureManager::OnDeviceLaunchAborted() {
+  EmitLogMessage("Launching device has been aborted.", 1);
   device_start_request_queue_.pop_front();
   ProcessDeviceStartRequestQueue();
 }
 
 void VideoCaptureManager::OnDeviceConnectionLost(
     VideoCaptureController* controller) {
-  const std::string log_message = base::StringPrintf(
-      "Lost connection to device %d.", controller->serial_id());
-  DLOG(WARNING) << log_message;
-  controller->OnLog(log_message);
+  std::ostringstream string_stream;
+  string_stream << "Lost connection to device. device_id = "
+                << controller->device_id();
+  EmitLogMessage(string_stream.str(), 1);
   controller->OnError();
 }
 
@@ -371,8 +375,10 @@
     VideoCaptureControllerEventHandler* client_handler,
     const DoneCB& done_cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << __func__ << ", session_id = " << session_id << ", request: "
-           << media::VideoCaptureFormat::ToString(params.requested_format);
+  std::ostringstream string_stream;
+  string_stream << "ConnectClient: session_id = " << session_id << ", request: "
+                << media::VideoCaptureFormat::ToString(params.requested_format);
+  EmitLogMessage(string_stream.str(), 1);
 
   VideoCaptureController* controller =
       GetOrCreateController(session_id, params);
@@ -385,8 +391,11 @@
 
   // First client starts the device.
   if (!controller->HasActiveClient() && !controller->HasPausedClient()) {
-    DVLOG(1) << "VideoCaptureManager starting device (id = "
-             << controller->device_id() << ")";
+    std::ostringstream string_stream;
+    string_stream
+        << "VideoCaptureManager queueing device start for device_id = "
+        << controller->device_id();
+    EmitLogMessage(string_stream.str(), 1);
     QueueStartDevice(session_id, controller, params);
   }
   // Run the callback first, as AddClient() may trigger OnFrameInfo().
@@ -435,7 +444,9 @@
   // Detach client from controller.
   const media::VideoCaptureSessionId session_id =
       controller->RemoveClient(client_id, client_handler);
-  DVLOG(1) << __func__ << ", session_id = " << session_id;
+  std::ostringstream string_stream;
+  string_stream << "DisconnectClient: session_id = " << session_id;
+  EmitLogMessage(string_stream.str(), 1);
 
   // If controller has no more clients, delete controller and device.
   DestroyControllerIfNoClients(controller);
@@ -502,7 +513,9 @@
   SessionMap::iterator it = sessions_.find(capture_session_id);
   if (it == sessions_.end())
     return false;
-  DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name;
+  std::ostringstream string_stream;
+  string_stream << "GetDeviceSupportedFormats for device: " << it->second.name;
+  EmitLogMessage(string_stream.str(), 1);
 
   return GetDeviceSupportedFormats(it->second.id, supported_formats);
 }
@@ -529,7 +542,9 @@
   SessionMap::iterator it = sessions_.find(capture_session_id);
   if (it == sessions_.end())
     return false;
-  DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name;
+  std::ostringstream string_stream;
+  string_stream << "GetDeviceFormatsInUse for device: " << it->second.name;
+  EmitLogMessage(string_stream.str(), 1);
 
   base::Optional<media::VideoCaptureFormat> format =
       GetDeviceFormatInUse(it->second.type, it->second.id);
@@ -681,6 +696,16 @@
       timer->Elapsed());
   devices_info_cache_ = device_infos;
 
+  std::ostringstream string_stream;
+  string_stream << "VideoCaptureManager::OnDeviceInfosReceived: Recevied "
+                << device_infos.size() << " device infos.";
+  for (const auto& entry : device_infos) {
+    string_stream << std::endl
+                  << "device_id: " << entry.descriptor.device_id
+                  << ", display_name: " << entry.descriptor.display_name;
+  }
+  EmitLogMessage(string_stream.str(), 1);
+
   // Walk the |devices_info_cache_| and produce a
   // media::VideoCaptureDeviceDescriptors for |client_callback|.
   media::VideoCaptureDeviceDescriptors devices;
@@ -702,9 +727,11 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // Removal of the last client stops the device.
   if (!controller->HasActiveClient() && !controller->HasPausedClient()) {
-    DVLOG(1) << "VideoCaptureManager stopping device (type = "
-             << controller->stream_type()
-             << ", id = " << controller->device_id() << ")";
+    std::ostringstream string_stream;
+    string_stream << "VideoCaptureManager stopping device (stream_type = "
+                  << controller->stream_type()
+                  << ", device_id = " << controller->device_id() << ")";
+    EmitLogMessage(string_stream.str(), 1);
 
     // The VideoCaptureController is removed from |controllers_| immediately.
     // The controller is deleted immediately, and the device is freed
@@ -795,7 +822,7 @@
 
   VideoCaptureController* new_controller = new VideoCaptureController(
       device_info.id, device_info.type, params,
-      video_capture_provider_->CreateDeviceLauncher());
+      video_capture_provider_->CreateDeviceLauncher(), emit_log_message_cb_);
   controllers_.emplace_back(new_controller);
   return new_controller;
 }
@@ -866,4 +893,10 @@
 }
 #endif  // defined(OS_ANDROID)
 
+void VideoCaptureManager::EmitLogMessage(const std::string& message,
+                                         int verbose_log_level) {
+  DVLOG(verbose_log_level) << message;
+  emit_log_message_cb_.Run(message);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/media/video_capture_manager.h b/content/browser/renderer_host/media/video_capture_manager.h
index 3272725..65390fd 100644
--- a/content/browser/renderer_host/media/video_capture_manager.h
+++ b/content/browser/renderer_host/media/video_capture_manager.h
@@ -54,7 +54,8 @@
       base::Callback<void(const base::WeakPtr<VideoCaptureController>&)>;
 
   explicit VideoCaptureManager(
-      std::unique_ptr<VideoCaptureProvider> video_capture_provider);
+      std::unique_ptr<VideoCaptureProvider> video_capture_provider,
+      base::RepeatingCallback<void(const std::string&)> emit_log_message_cb);
 
   // AddVideoCaptureObserver() can be called only before any devices are opened.
   // RemoveAllVideoCaptureObservers() can be called only after all devices
@@ -262,6 +263,8 @@
   bool application_state_has_running_activities_;
 #endif
 
+  void EmitLogMessage(const std::string& message, int verbose_log_level);
+
   // Only accessed on Browser::IO thread.
   base::ObserverList<MediaStreamProviderListener> listeners_;
   media::VideoCaptureSessionId new_capture_session_id_;
@@ -285,6 +288,7 @@
   std::list<std::pair<int, base::Closure>> photo_request_queue_;
 
   const std::unique_ptr<VideoCaptureProvider> video_capture_provider_;
+  base::RepeatingCallback<void(const std::string&)> emit_log_message_cb_;
 
   base::ObserverList<media::VideoCaptureObserver> capture_observers_;
 
diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index 35421734..c62a3bd 100644
--- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -41,6 +41,8 @@
 
 namespace {
 
+const auto kIgnoreLogMessageCB = base::BindRepeating([](const std::string&) {});
+
 // Wraps FakeVideoCaptureDeviceFactory to allow mocking of the
 // VideoCaptureDevice MaybeSuspend() and Resume() methods. This is used to check
 // that devices are asked to suspend or resume at the correct times.
@@ -206,8 +208,10 @@
     auto video_capture_provider =
         base::MakeUnique<InProcessVideoCaptureProvider>(
             std::move(video_capture_system),
-            base::ThreadTaskRunnerHandle::Get());
-    vcm_ = new VideoCaptureManager(std::move(video_capture_provider));
+            base::ThreadTaskRunnerHandle::Get(), kIgnoreLogMessageCB);
+    vcm_ =
+        new VideoCaptureManager(std::move(video_capture_provider),
+                                base::BindRepeating([](const std::string&) {}));
     const int32_t kNumberOfFakeDevices = 2;
     video_capture_device_factory_->SetToDefaultDevicesConfig(
         kNumberOfFakeDevices);
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc
index b42768d..ecf7e14 100644
--- a/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
 #include "build/build_config.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
@@ -14,6 +15,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
@@ -30,6 +32,8 @@
 #include "media/base/test_data_util.h"
 #include "media/mojo/features.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
@@ -50,6 +54,20 @@
   return count;
 }
 
+std::unique_ptr<net::test_server::HttpResponse> HandleBeacon(
+    const net::test_server::HttpRequest& request) {
+  if (request.relative_url != "/beacon")
+    return nullptr;
+  return base::MakeUnique<net::test_server::BasicHttpResponse>();
+}
+
+std::unique_ptr<net::test_server::HttpResponse> HandleHungBeacon(
+    const net::test_server::HttpRequest& request) {
+  if (request.relative_url != "/beacon")
+    return nullptr;
+  return base::MakeUnique<net::test_server::HungResponse>();
+}
+
 class RenderProcessHostTest : public ContentBrowserTest,
                               public RenderProcessHostObserver {
  public:
@@ -79,6 +97,10 @@
   void RenderProcessHostDestroyed(RenderProcessHost* host) override {
     ++host_destructions_;
   }
+  void WaitUntilProcessExits(int target) {
+    while (process_exits_ < target)
+      base::RunLoop().RunUntilIdle();
+  }
 
   int process_exits_;
   int host_destructions_;
@@ -676,5 +698,59 @@
     rph->RemoveObserver(this);
 }
 
+IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KeepAliveRendererProcess) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kKeepAliveRendererForKeepaliveRequests,
+      {std::make_pair("timeout_in_sec", "30")});
+
+  embedded_test_server()->RegisterRequestHandler(
+      base::BindRepeating(HandleBeacon));
+  ASSERT_TRUE(embedded_test_server()->Start());
+  RenderProcessHostImpl* rph = static_cast<RenderProcessHostImpl*>(
+      shell()->web_contents()->GetMainFrame()->GetProcess());
+
+  host_destructions_ = 0;
+  process_exits_ = 0;
+  rph->AddObserver(this);
+
+  NavigateToURL(shell(), embedded_test_server()->GetURL("/send-beacon.html"));
+  base::TimeTicks start = base::TimeTicks::Now();
+  NavigateToURL(shell(), GURL("data:text/html,<p>hello</p>"));
+
+  WaitUntilProcessExits(1);
+
+  EXPECT_LT(base::TimeTicks::Now() - start, base::TimeDelta::FromSeconds(30));
+  if (!host_destructions_)
+    rph->RemoveObserver(this);
+}
+
+IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KeepAliveRendererProcess_Hung) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kKeepAliveRendererForKeepaliveRequests,
+      {std::make_pair("timeout_in_sec", "1")});
+
+  embedded_test_server()->RegisterRequestHandler(
+      base::BindRepeating(HandleHungBeacon));
+  ASSERT_TRUE(embedded_test_server()->Start());
+  RenderProcessHostImpl* rph = static_cast<RenderProcessHostImpl*>(
+      shell()->web_contents()->GetMainFrame()->GetProcess());
+
+  host_destructions_ = 0;
+  process_exits_ = 0;
+  rph->AddObserver(this);
+
+  NavigateToURL(shell(), embedded_test_server()->GetURL("/send-beacon.html"));
+  base::TimeTicks start = base::TimeTicks::Now();
+  NavigateToURL(shell(), GURL("data:text/html,<p>hello</p>"));
+
+  WaitUntilProcessExits(1);
+
+  EXPECT_GE(base::TimeTicks::Now() - start, base::TimeDelta::FromSeconds(1));
+  if (!host_destructions_)
+    rph->RemoveObserver(this);
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 97a576ed..f7fb982 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -405,8 +405,10 @@
     const ui::LatencyInfo& latency) {
   switch (event->GetType()) {
     case blink::WebInputEvent::kTouchStart: {
+      int current_active_touches = active_touches_;
       active_touches_ += CountChangedTouchPoints(*event);
-      if (active_touches_ == 1) {
+      DCHECK(active_touches_);
+      if (!current_active_touches) {
         // Since this is the first touch, it defines the target for the rest
         // of this sequence.
         DCHECK(!touch_target_.target);
@@ -453,12 +455,12 @@
       break;
     case blink::WebInputEvent::kTouchEnd:
     case blink::WebInputEvent::kTouchCancel:
-      // It might be safer to test active_touches_ and only decrement it if it's
-      // non-zero, since active_touches_ can be reset to 0 in
-      // OnRenderWidgetHostViewBaseDestroyed, and this can happen between the
-      // TouchStart and a subsequent TouchMove/End/Cancel.
-      DCHECK(active_touches_);
-      active_touches_ -= CountChangedTouchPoints(*event);
+      // Test active_touches_ before decrementing, since its value can be
+      // reset to 0 in OnRenderWidgetHostViewBaseDestroyed, and this can
+      // happen between the TouchStart and a subsequent TouchMove/End/Cancel.
+      if (active_touches_)
+        active_touches_ -= CountChangedTouchPoints(*event);
+      DCHECK_GE(active_touches_, 0);
       if (!touch_target_.target)
         return;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index dda1da68..74a5b0f 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -926,30 +926,14 @@
   UpdateBackgroundColorFromRenderer(frame.metadata.root_background_color);
 
   last_scroll_offset_ = frame.metadata.root_scroll_offset;
-  cc::Selection<gfx::SelectionBound> selection = frame.metadata.selection;
-  if (IsUseZoomForDSFEnabled()) {
-    float viewportToDIPScale = 1.0f / current_device_scale_factor_;
-    gfx::PointF start_edge_top = selection.start.edge_top();
-    gfx::PointF start_edge_bottom = selection.start.edge_bottom();
-    gfx::PointF end_edge_top = selection.end.edge_top();
-    gfx::PointF end_edge_bottom = selection.end.edge_bottom();
-
-    start_edge_top.Scale(viewportToDIPScale);
-    start_edge_bottom.Scale(viewportToDIPScale);
-    end_edge_top.Scale(viewportToDIPScale);
-    end_edge_bottom.Scale(viewportToDIPScale);
-
-    selection.start.SetEdge(start_edge_top, start_edge_bottom);
-    selection.end.SetEdge(end_edge_top, end_edge_bottom);
-  }
-
   if (delegated_frame_host_) {
     delegated_frame_host_->SubmitCompositorFrame(local_surface_id,
                                                  std::move(frame));
   }
-  if (selection.start != selection_start_ || selection.end != selection_end_) {
-    selection_start_ = selection.start;
-    selection_end_ = selection.end;
+  if (frame.metadata.selection.start != selection_start_ ||
+      frame.metadata.selection.end != selection_end_) {
+    selection_start_ = frame.metadata.selection.start;
+    selection_end_ = frame.metadata.selection.end;
     selection_controller_client_->UpdateClientSelectionBounds(selection_start_,
                                                               selection_end_);
   }
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 fc5197ab..913526ad 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
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/debug/dump_without_crashing.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
@@ -79,6 +80,7 @@
       current_surface_scale_factor_(1.f),
       frame_connector_(nullptr),
       background_color_(SK_ColorWHITE),
+      destroy_was_called_(false),
       weak_factory_(this) {
   if (!IsUsingMus()) {
     GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
@@ -87,6 +89,14 @@
 }
 
 RenderWidgetHostViewChildFrame::~RenderWidgetHostViewChildFrame() {
+  // This is diagnostic code to capture a stacktrace in the case where this
+  // class is destructed without calling Destroy(). This code will be removed
+  // once a representative sample of stack traces are collected (or we determine
+  // that this isn't actually happening).
+  // https://crbug.com/762511 .
+  if (!destroy_was_called_)
+    base::debug::DumpWithoutCrashing();
+
   // TODO(wjmaclean): The next two lines are a speculative fix for
   // https://crbug.com/760074, based on the theory that perhaps something is
   // destructing the class without calling Destroy() first.
@@ -356,6 +366,7 @@
 }
 
 void RenderWidgetHostViewChildFrame::Destroy() {
+  destroy_was_called_ = true;
   // FrameSinkIds registered with RenderWidgetHostInputEventRouter
   // have already been cleared when RenderWidgetHostViewBase notified its
   // observers of our impending destruction.
@@ -500,8 +511,10 @@
   current_surface_size_ = frame.size_in_pixels();
   current_surface_scale_factor_ = frame.device_scale_factor();
 
-  bool result =
-      support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
+  // TODO(kenrb): Supply HitTestRegionList data here as described in
+  // crbug.com/750755.
+  bool result = support_->SubmitCompositorFrame(local_surface_id,
+                                                std::move(frame), nullptr);
   DCHECK(result);
   has_frame_ = true;
 
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 e994ab27f..154d05b 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
@@ -312,6 +312,10 @@
   std::unique_ptr<TouchSelectionControllerClientChildFrame>
       selection_controller_client_;
 
+  // Used to trigger a non-crashing stack dump when this class is destructed
+  // without calling Destroy() first.
+  bool destroy_was_called_;
+
   base::WeakPtrFactory<RenderWidgetHostViewChildFrame> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewChildFrame);
 };
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 0cf7c5f..dd8cd66 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -364,6 +364,11 @@
 
 EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
     const base::FilePath& user_data_directory)
+    : EmbeddedWorkerTestHelper(user_data_directory, nullptr) {}
+
+EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
+    const base::FilePath& user_data_directory,
+    scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter)
     : browser_context_(base::MakeUnique<TestBrowserContext>()),
       render_process_host_(
           base::MakeUnique<MockRenderProcessHost>(browser_context_.get())),
@@ -375,11 +380,13 @@
       next_thread_id_(0),
       mock_render_process_id_(render_process_host_->GetID()),
       new_mock_render_process_id_(new_render_process_host_->GetID()),
+      url_loader_factory_getter_(std::move(url_loader_factory_getter)),
       weak_factory_(this) {
   scoped_refptr<base::SequencedTaskRunner> database_task_runner =
       base::ThreadTaskRunnerHandle::Get();
   wrapper_->InitInternal(user_data_directory, std::move(database_task_runner),
-                         nullptr, nullptr, nullptr, nullptr);
+                         nullptr, nullptr, nullptr,
+                         url_loader_factory_getter_.get());
   wrapper_->process_manager()->SetProcessIdForTest(mock_render_process_id());
   wrapper_->process_manager()->SetNewProcessIdForTest(new_render_process_id());
 
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index ee99525..921a629 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -19,6 +19,7 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
+#include "content/browser/url_loader_factory_getter.h"
 #include "content/common/service_worker/embedded_worker.mojom.h"
 #include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
 #include "content/common/service_worker/service_worker_status_code.h"
@@ -105,6 +106,10 @@
   // If |user_data_directory| is empty, the context makes storage stuff in
   // memory.
   explicit EmbeddedWorkerTestHelper(const base::FilePath& user_data_directory);
+  // S13nServiceWorker
+  EmbeddedWorkerTestHelper(
+      const base::FilePath& user_data_directory,
+      scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter);
   ~EmbeddedWorkerTestHelper() override;
 
   // Call this to simulate add/associate a process to a pattern.
@@ -173,6 +178,10 @@
 
   static net::HttpResponseInfo CreateHttpResponseInfo();
 
+  URLLoaderFactoryGetter* url_loader_factory_getter() {
+    return url_loader_factory_getter_.get();
+  }
+
  protected:
   // StartWorker IPC handler routed through MockEmbeddedWorkerInstanceClient.
   // This simulates each legacy IPC sent from the renderer and binds |request|
@@ -386,6 +395,7 @@
       embedded_worker_id_remote_provider_map_;
 
   std::vector<Event> events_;
+  scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter_;
 
   base::WeakPtrFactory<EmbeddedWorkerTestHelper> weak_factory_;
 
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 963f93610..b80e421 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -119,8 +119,33 @@
   }
 }
 
+void StatusCodeToBoolCallbackAdapter(
+    ServiceWorkerContext::ResultCallback callback,
+    ServiceWorkerStatusCode code) {
+  std::move(callback).Run(code == ServiceWorkerStatusCode::SERVICE_WORKER_OK);
+}
+
+void FinishRegistrationOnIO(ServiceWorkerContext::ResultCallback callback,
+                            ServiceWorkerStatusCode status,
+                            const std::string& status_message,
+                            int64_t registration_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(std::move(callback), status == SERVICE_WORKER_OK));
+}
+
+void FinishUnregistrationOnIO(ServiceWorkerContext::ResultCallback callback,
+                              ServiceWorkerStatusCode status) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(std::move(callback), status == SERVICE_WORKER_OK));
+}
+
 }  // namespace
 
+// static
 void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
     const std::set<std::string>& header_names) {
   // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
@@ -132,6 +157,7 @@
                                           header_names.end());
 }
 
+// static
 bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
     const std::string& header_name) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -139,26 +165,11 @@
          g_excluded_header_name_set.Get().end();
 }
 
+// static
 bool ServiceWorkerContext::ScopeMatches(const GURL& scope, const GURL& url) {
   return ServiceWorkerUtils::ScopeMatches(scope, url);
 }
 
-void ServiceWorkerContextWrapper::OnRegistrationStored(int64_t registration_id,
-                                                       const GURL& pattern) {
-  for (auto& observer : observer_list_)
-    observer.OnRegistrationStored(pattern);
-}
-
-void ServiceWorkerContextWrapper::AddObserver(
-    ServiceWorkerContextObserver* observer) {
-  observer_list_.AddObserver(observer);
-}
-
-void ServiceWorkerContextWrapper::RemoveObserver(
-    ServiceWorkerContextObserver* observer) {
-  observer_list_.RemoveObserver(observer);
-}
-
 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
     BrowserContext* browser_context)
     : core_observer_list_(
@@ -174,14 +185,6 @@
   core_observer_list_->AddObserver(this);
 }
 
-ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
-  // Explicitly remove this object as an observer to avoid use-after-frees in
-  // tests where this object is not guaranteed to outlive the
-  // ServiceWorkerContextCore it wraps.
-  core_observer_list_->RemoveObserver(this);
-  DCHECK(!resource_context_);
-}
-
 void ServiceWorkerContextWrapper::Init(
     const base::FilePath& user_data_directory,
     storage::QuotaManagerProxy* quota_manager_proxy,
@@ -248,272 +251,86 @@
   return resource_context_;
 }
 
-static void FinishRegistrationOnIO(
-    const ServiceWorkerContext::ResultCallback& continuation,
-    ServiceWorkerStatusCode status,
-    const std::string& status_message,
-    int64_t registration_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::BindOnce(continuation, status == SERVICE_WORKER_OK));
+void ServiceWorkerContextWrapper::OnRegistrationStored(int64_t registration_id,
+                                                       const GURL& pattern) {
+  for (auto& observer : observer_list_)
+    observer.OnRegistrationStored(pattern);
+}
+
+void ServiceWorkerContextWrapper::AddObserver(
+    ServiceWorkerContextObserver* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void ServiceWorkerContextWrapper::RemoveObserver(
+    ServiceWorkerContextObserver* observer) {
+  observer_list_.RemoveObserver(observer);
 }
 
 void ServiceWorkerContextWrapper::RegisterServiceWorker(
     const GURL& pattern,
     const GURL& script_url,
-    const ResultCallback& continuation) {
+    ResultCallback callback) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(&ServiceWorkerContextWrapper::RegisterServiceWorker,
-                       this, pattern, script_url, continuation));
+                       this, pattern, script_url, std::move(callback)));
     return;
   }
   if (!context_core_) {
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                            base::BindOnce(continuation, false));
+                            base::BindOnce(std::move(callback), false));
     return;
   }
   ServiceWorkerRegistrationOptions options(net::SimplifyUrlForRequest(pattern));
   context()->RegisterServiceWorker(
       net::SimplifyUrlForRequest(script_url), options,
       nullptr /* provider_host */,
-      base::Bind(&FinishRegistrationOnIO, continuation));
-}
-
-static void FinishUnregistrationOnIO(
-    const ServiceWorkerContext::ResultCallback& continuation,
-    ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::BindOnce(continuation, status == SERVICE_WORKER_OK));
+      base::Bind(&FinishRegistrationOnIO, base::Passed(std::move(callback))));
 }
 
 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
     const GURL& pattern,
-    const ResultCallback& continuation) {
+    ResultCallback callback) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(&ServiceWorkerContextWrapper::UnregisterServiceWorker,
-                       this, pattern, continuation));
+                       this, pattern, std::move(callback)));
     return;
   }
   if (!context_core_) {
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                            base::BindOnce(continuation, false));
+                            base::BindOnce(std::move(callback), false));
     return;
   }
 
   context()->UnregisterServiceWorker(
       net::SimplifyUrlForRequest(pattern),
-      base::Bind(&FinishUnregistrationOnIO, continuation));
+      base::Bind(&FinishUnregistrationOnIO, base::Passed(std::move(callback))));
 }
 
-void ServiceWorkerContextWrapper::UpdateRegistration(const GURL& pattern) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ServiceWorkerContextWrapper::UpdateRegistration, this,
-                       pattern));
-    return;
-  }
-  if (!context_core_)
-    return;
-  context_core_->storage()->FindRegistrationForPattern(
-      net::SimplifyUrlForRequest(pattern),
-      base::Bind(&ServiceWorkerContextWrapper::DidFindRegistrationForUpdate,
-                 this));
-}
-
-void ServiceWorkerContextWrapper::StartServiceWorker(
-    const GURL& pattern,
-    const StatusCallback& callback) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ServiceWorkerContextWrapper::StartServiceWorker, this,
-                       pattern, callback));
-    return;
-  }
-  if (!context_core_) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::BindOnce(callback, SERVICE_WORKER_ERROR_ABORT));
-    return;
-  }
-  context_core_->storage()->FindRegistrationForPattern(
-      net::SimplifyUrlForRequest(pattern),
-      base::Bind(&StartActiveWorkerOnIO, callback));
-}
-
-void ServiceWorkerContextWrapper::SkipWaitingWorker(const GURL& pattern) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ServiceWorkerContextWrapper::SkipWaitingWorker, this,
-                       pattern));
-    return;
-  }
-  if (!context_core_)
-    return;
-  context_core_->storage()->FindRegistrationForPattern(
-      net::SimplifyUrlForRequest(pattern), base::Bind(&SkipWaitingWorkerOnIO));
-}
-
-void ServiceWorkerContextWrapper::SetForceUpdateOnPageLoad(
-    bool force_update_on_page_load) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ServiceWorkerContextWrapper::SetForceUpdateOnPageLoad,
-                       this, force_update_on_page_load));
-    return;
-  }
-  if (!context_core_)
-    return;
-  context_core_->set_force_update_on_page_load(force_update_on_page_load);
-}
-
-void ServiceWorkerContextWrapper::GetAllOriginsInfo(
-    const GetUsageInfoCallback& callback) {
+bool ServiceWorkerContextWrapper::StartingExternalRequest(
+    int64_t service_worker_version_id,
+    const std::string& request_uuid) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (!context_core_) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(callback, std::vector<ServiceWorkerUsageInfo>()));
-    return;
-  }
-  context()->storage()->GetAllRegistrationsInfos(base::Bind(
-      &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
-      this, callback));
+  ServiceWorkerVersion* version =
+      context()->GetLiveVersion(service_worker_version_id);
+  if (!version)
+    return false;
+  return version->StartExternalRequest(request_uuid);
 }
 
-void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
-    const GetUsageInfoCallback& callback,
-    ServiceWorkerStatusCode status,
-    const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+bool ServiceWorkerContextWrapper::FinishedExternalRequest(
+    int64_t service_worker_version_id,
+    const std::string& request_uuid) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  std::vector<ServiceWorkerUsageInfo> usage_infos;
-
-  std::map<GURL, ServiceWorkerUsageInfo> origins;
-  for (const auto& registration_info : registrations) {
-    GURL origin = registration_info.pattern.GetOrigin();
-
-    ServiceWorkerUsageInfo& usage_info = origins[origin];
-    if (usage_info.origin.is_empty())
-      usage_info.origin = origin;
-    usage_info.scopes.push_back(registration_info.pattern);
-    usage_info.total_size_bytes += registration_info.stored_version_size_bytes;
-  }
-
-  for (const auto& origin_info_pair : origins) {
-    usage_infos.push_back(origin_info_pair.second);
-  }
-  callback.Run(usage_infos);
-}
-
-void ServiceWorkerContextWrapper::DidCheckHasServiceWorker(
-    const CheckHasServiceWorkerCallback& callback,
-    ServiceWorkerCapability capability) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                          base::BindOnce(callback, capability));
-}
-
-void ServiceWorkerContextWrapper::StopAllServiceWorkersForOrigin(
-    const GURL& origin) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(
-            &ServiceWorkerContextWrapper::StopAllServiceWorkersForOrigin, this,
-            origin));
-    return;
-  }
-  if (!context_core_.get()) {
-    return;
-  }
-  std::vector<ServiceWorkerVersionInfo> live_versions = GetAllLiveVersionInfo();
-  for (const ServiceWorkerVersionInfo& info : live_versions) {
-    ServiceWorkerVersion* version = GetLiveVersion(info.version_id);
-    if (version && version->scope().GetOrigin() == origin)
-      version->StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
-  }
-}
-
-void ServiceWorkerContextWrapper::DidFindRegistrationForUpdate(
-    ServiceWorkerStatusCode status,
-    scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (status != SERVICE_WORKER_OK)
-    return;
-  if (!context_core_)
-    return;
-  DCHECK(registration);
-  // TODO(jungkees): |force_bypass_cache| is set to true because the call stack
-  // is initiated by an update button on DevTools that expects the cache is
-  // bypassed. However, in order to provide options for callers to choose the
-  // cache bypass mode, plumb |force_bypass_cache| through to
-  // UpdateRegistration().
-  context_core_->UpdateServiceWorker(registration.get(),
-                                     true /* force_bypass_cache */);
-}
-
-namespace {
-
-void StatusCodeToBoolCallbackAdapter(
-    const ServiceWorkerContext::ResultCallback& callback,
-    ServiceWorkerStatusCode code) {
-  callback.Run(code == ServiceWorkerStatusCode::SERVICE_WORKER_OK);
-}
-
-}  // namespace
-
-void ServiceWorkerContextWrapper::DeleteForOrigin(
-    const GURL& origin,
-    const ResultCallback& result) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ServiceWorkerContextWrapper::DeleteForOrigin, this,
-                       origin, result));
-    return;
-  }
-  if (!context_core_) {
-    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-                            base::BindOnce(result, false));
-    return;
-  }
-  context()->UnregisterServiceWorkers(
-      origin.GetOrigin(), base::Bind(&StatusCodeToBoolCallbackAdapter, result));
-}
-
-void ServiceWorkerContextWrapper::CheckHasServiceWorker(
-    const GURL& url,
-    const GURL& other_url,
-    const CheckHasServiceWorkerCallback& callback) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&ServiceWorkerContextWrapper::CheckHasServiceWorker,
-                       this, url, other_url, callback));
-    return;
-  }
-  if (!context_core_) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::BindOnce(callback, ServiceWorkerCapability::NO_SERVICE_WORKER));
-    return;
-  }
-  context()->CheckHasServiceWorker(
-      net::SimplifyUrlForRequest(url), net::SimplifyUrlForRequest(other_url),
-      base::Bind(&ServiceWorkerContextWrapper::DidCheckHasServiceWorker, this,
-                 callback));
+  ServiceWorkerVersion* version =
+      context()->GetLiveVersion(service_worker_version_id);
+  if (!version)
+    return false;
+  return version->FinishExternalRequest(request_uuid);
 }
 
 void ServiceWorkerContextWrapper::CountExternalRequestsForTest(
@@ -544,6 +361,62 @@
       base::BindOnce(callback, pending_external_request_count));
 }
 
+void ServiceWorkerContextWrapper::GetAllOriginsInfo(
+    const GetUsageInfoCallback& callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (!context_core_) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(callback, std::vector<ServiceWorkerUsageInfo>()));
+    return;
+  }
+  context()->storage()->GetAllRegistrationsInfos(base::Bind(
+      &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
+      this, callback));
+}
+
+void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin,
+                                                  ResultCallback callback) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&ServiceWorkerContextWrapper::DeleteForOrigin, this,
+                       origin, std::move(callback)));
+    return;
+  }
+  if (!context_core_) {
+    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                            base::BindOnce(std::move(callback), false));
+    return;
+  }
+  context()->UnregisterServiceWorkers(
+      origin.GetOrigin(), base::Bind(&StatusCodeToBoolCallbackAdapter,
+                                     base::Passed(std::move(callback))));
+}
+
+void ServiceWorkerContextWrapper::CheckHasServiceWorker(
+    const GURL& url,
+    const GURL& other_url,
+    const CheckHasServiceWorkerCallback& callback) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&ServiceWorkerContextWrapper::CheckHasServiceWorker,
+                       this, url, other_url, callback));
+    return;
+  }
+  if (!context_core_) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(callback, ServiceWorkerCapability::NO_SERVICE_WORKER));
+    return;
+  }
+  context()->CheckHasServiceWorker(
+      net::SimplifyUrlForRequest(url), net::SimplifyUrlForRequest(other_url),
+      base::Bind(&ServiceWorkerContextWrapper::DidCheckHasServiceWorker, this,
+                 callback));
+}
+
 void ServiceWorkerContextWrapper::ClearAllServiceWorkersForTest(
     const base::Closure& callback) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
@@ -561,6 +434,55 @@
   context_core_->ClearAllServiceWorkersForTest(callback);
 }
 
+void ServiceWorkerContextWrapper::StartActiveWorkerForPattern(
+    const GURL& pattern,
+    StartActiveWorkerCallback info_callback,
+    base::OnceClosure failure_callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  FindReadyRegistrationForPattern(
+      pattern, base::Bind(&FoundReadyRegistrationForStartActiveWorker,
+                          base::Passed(&info_callback),
+                          base::Passed(&failure_callback)));
+}
+
+void ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHint(
+    const GURL& document_url,
+    const StartServiceWorkerForNavigationHintCallback& callback) {
+  TRACE_EVENT1("ServiceWorker", "StartServiceWorkerForNavigationHint",
+               "document_url", document_url.spec());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(
+          &ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHintOnIO,
+          this, document_url,
+          base::Bind(&ServiceWorkerContextWrapper::
+                         RecordStartServiceWorkerForNavigationHintResult,
+                     this, callback)));
+}
+
+void ServiceWorkerContextWrapper::StopAllServiceWorkersForOrigin(
+    const GURL& origin) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(
+            &ServiceWorkerContextWrapper::StopAllServiceWorkersForOrigin, this,
+            origin));
+    return;
+  }
+  if (!context_core_.get()) {
+    return;
+  }
+  std::vector<ServiceWorkerVersionInfo> live_versions = GetAllLiveVersionInfo();
+  for (const ServiceWorkerVersionInfo& info : live_versions) {
+    ServiceWorkerVersion* version = GetLiveVersion(info.version_id);
+    if (version && version->scope().GetOrigin() == origin)
+      version->StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+  }
+}
+
 ServiceWorkerRegistration* ServiceWorkerContextWrapper::GetLiveRegistration(
     int64_t registration_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -683,54 +605,6 @@
                  this, callback));
 }
 
-void ServiceWorkerContextWrapper::DidFindRegistrationForFindReady(
-    const FindRegistrationCallback& callback,
-    ServiceWorkerStatusCode status,
-    scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (status != SERVICE_WORKER_OK) {
-    callback.Run(status, nullptr);
-    return;
-  }
-
-  // Attempt to activate the waiting version because the registration retrieved
-  // from the disk might have only the waiting version.
-  if (registration->waiting_version())
-    registration->ActivateWaitingVersionWhenReady();
-
-  scoped_refptr<ServiceWorkerVersion> active_version =
-      registration->active_version();
-  if (!active_version) {
-    callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, nullptr);
-    return;
-  }
-
-  if (active_version->status() == ServiceWorkerVersion::ACTIVATING) {
-    // Wait until the version is activated.
-    active_version->RegisterStatusChangeCallback(base::BindOnce(
-        &ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration,
-        this, callback, std::move(registration)));
-    return;
-  }
-
-  DCHECK_EQ(ServiceWorkerVersion::ACTIVATED, active_version->status());
-  callback.Run(SERVICE_WORKER_OK, std::move(registration));
-}
-
-void ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration(
-    const FindRegistrationCallback& callback,
-    scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  scoped_refptr<ServiceWorkerVersion> active_version =
-      registration->active_version();
-  if (!active_version ||
-      active_version->status() != ServiceWorkerVersion::ACTIVATED) {
-    callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, nullptr);
-    return;
-  }
-  callback.Run(SERVICE_WORKER_OK, registration);
-}
-
 void ServiceWorkerContextWrapper::GetAllRegistrations(
     const GetRegistrationsInfosCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -833,6 +707,71 @@
       key_prefix, callback);
 }
 
+void ServiceWorkerContextWrapper::StartServiceWorker(
+    const GURL& pattern,
+    const StatusCallback& callback) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&ServiceWorkerContextWrapper::StartServiceWorker, this,
+                       pattern, callback));
+    return;
+  }
+  if (!context_core_) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(callback, SERVICE_WORKER_ERROR_ABORT));
+    return;
+  }
+  context_core_->storage()->FindRegistrationForPattern(
+      net::SimplifyUrlForRequest(pattern),
+      base::Bind(&StartActiveWorkerOnIO, callback));
+}
+
+void ServiceWorkerContextWrapper::SkipWaitingWorker(const GURL& pattern) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&ServiceWorkerContextWrapper::SkipWaitingWorker, this,
+                       pattern));
+    return;
+  }
+  if (!context_core_)
+    return;
+  context_core_->storage()->FindRegistrationForPattern(
+      net::SimplifyUrlForRequest(pattern), base::Bind(&SkipWaitingWorkerOnIO));
+}
+
+void ServiceWorkerContextWrapper::UpdateRegistration(const GURL& pattern) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&ServiceWorkerContextWrapper::UpdateRegistration, this,
+                       pattern));
+    return;
+  }
+  if (!context_core_)
+    return;
+  context_core_->storage()->FindRegistrationForPattern(
+      net::SimplifyUrlForRequest(pattern),
+      base::Bind(&ServiceWorkerContextWrapper::DidFindRegistrationForUpdate,
+                 this));
+}
+
+void ServiceWorkerContextWrapper::SetForceUpdateOnPageLoad(
+    bool force_update_on_page_load) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&ServiceWorkerContextWrapper::SetForceUpdateOnPageLoad,
+                       this, force_update_on_page_load));
+    return;
+  }
+  if (!context_core_)
+    return;
+  context_core_->set_force_update_on_page_load(force_update_on_page_load);
+}
+
 void ServiceWorkerContextWrapper::AddObserver(
     ServiceWorkerContextCoreObserver* observer) {
   core_observer_list_->AddObserver(observer);
@@ -851,6 +790,14 @@
   return context_core_->storage()->OriginHasForeignFetchRegistrations(origin);
 }
 
+ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
+  // Explicitly remove this object as an observer to avoid use-after-frees in
+  // tests where this object is not guaranteed to outlive the
+  // ServiceWorkerContextCore it wraps.
+  core_observer_list_->RemoveObserver(this);
+  DCHECK(!resource_context_);
+}
+
 void ServiceWorkerContextWrapper::InitInternal(
     const base::FilePath& user_data_directory,
     scoped_refptr<base::SequencedTaskRunner> database_task_runner,
@@ -890,37 +837,52 @@
   context_core_.reset();
 }
 
-bool ServiceWorkerContextWrapper::StartingExternalRequest(
-    int64_t service_worker_version_id,
-    const std::string& request_uuid) {
+void ServiceWorkerContextWrapper::DidFindRegistrationForFindReady(
+    const FindRegistrationCallback& callback,
+    ServiceWorkerStatusCode status,
+    scoped_refptr<ServiceWorkerRegistration> registration) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  ServiceWorkerVersion* version =
-      context()->GetLiveVersion(service_worker_version_id);
-  if (!version)
-    return false;
-  return version->StartExternalRequest(request_uuid);
+  if (status != SERVICE_WORKER_OK) {
+    callback.Run(status, nullptr);
+    return;
+  }
+
+  // Attempt to activate the waiting version because the registration retrieved
+  // from the disk might have only the waiting version.
+  if (registration->waiting_version())
+    registration->ActivateWaitingVersionWhenReady();
+
+  scoped_refptr<ServiceWorkerVersion> active_version =
+      registration->active_version();
+  if (!active_version) {
+    callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, nullptr);
+    return;
+  }
+
+  if (active_version->status() == ServiceWorkerVersion::ACTIVATING) {
+    // Wait until the version is activated.
+    active_version->RegisterStatusChangeCallback(base::BindOnce(
+        &ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration,
+        this, callback, std::move(registration)));
+    return;
+  }
+
+  DCHECK_EQ(ServiceWorkerVersion::ACTIVATED, active_version->status());
+  callback.Run(SERVICE_WORKER_OK, std::move(registration));
 }
 
-bool ServiceWorkerContextWrapper::FinishedExternalRequest(
-    int64_t service_worker_version_id,
-    const std::string& request_uuid) {
+void ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration(
+    const FindRegistrationCallback& callback,
+    scoped_refptr<ServiceWorkerRegistration> registration) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  ServiceWorkerVersion* version =
-      context()->GetLiveVersion(service_worker_version_id);
-  if (!version)
-    return false;
-  return version->FinishExternalRequest(request_uuid);
-}
-
-void ServiceWorkerContextWrapper::StartActiveWorkerForPattern(
-    const GURL& pattern,
-    StartActiveWorkerCallback info_callback,
-    base::OnceClosure failure_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  FindReadyRegistrationForPattern(
-      pattern, base::Bind(&FoundReadyRegistrationForStartActiveWorker,
-                          base::Passed(&info_callback),
-                          base::Passed(&failure_callback)));
+  scoped_refptr<ServiceWorkerVersion> active_version =
+      registration->active_version();
+  if (!active_version ||
+      active_version->status() != ServiceWorkerVersion::ACTIVATED) {
+    callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, nullptr);
+    return;
+  }
+  callback.Run(SERVICE_WORKER_OK, registration);
 }
 
 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
@@ -935,21 +897,56 @@
   context_core_->OnStorageWiped();
 }
 
-void ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHint(
-    const GURL& document_url,
-    const StartServiceWorkerForNavigationHintCallback& callback) {
-  TRACE_EVENT1("ServiceWorker", "StartServiceWorkerForNavigationHint",
-               "document_url", document_url.spec());
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
+    const GetUsageInfoCallback& callback,
+    ServiceWorkerStatusCode status,
+    const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  std::vector<ServiceWorkerUsageInfo> usage_infos;
 
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::BindOnce(
-          &ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHintOnIO,
-          this, document_url,
-          base::Bind(&ServiceWorkerContextWrapper::
-                         RecordStartServiceWorkerForNavigationHintResult,
-                     this, callback)));
+  std::map<GURL, ServiceWorkerUsageInfo> origins;
+  for (const auto& registration_info : registrations) {
+    GURL origin = registration_info.pattern.GetOrigin();
+
+    ServiceWorkerUsageInfo& usage_info = origins[origin];
+    if (usage_info.origin.is_empty())
+      usage_info.origin = origin;
+    usage_info.scopes.push_back(registration_info.pattern);
+    usage_info.total_size_bytes += registration_info.stored_version_size_bytes;
+  }
+
+  for (const auto& origin_info_pair : origins) {
+    usage_infos.push_back(origin_info_pair.second);
+  }
+  callback.Run(usage_infos);
+}
+
+void ServiceWorkerContextWrapper::DidCheckHasServiceWorker(
+    const CheckHasServiceWorkerCallback& callback,
+    ServiceWorkerCapability capability) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::BindOnce(callback, capability));
+}
+
+void ServiceWorkerContextWrapper::DidFindRegistrationForUpdate(
+    ServiceWorkerStatusCode status,
+    scoped_refptr<ServiceWorkerRegistration> registration) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (status != SERVICE_WORKER_OK)
+    return;
+  if (!context_core_)
+    return;
+  DCHECK(registration);
+  // TODO(jungkees): |force_bypass_cache| is set to true because the call stack
+  // is initiated by an update button on DevTools that expects the cache is
+  // bypassed. However, in order to provide options for callers to choose the
+  // cache bypass mode, plumb |force_bypass_cache| through to
+  // UpdateRegistration().
+  context_core_->UpdateServiceWorker(registration.get(),
+                                     true /* force_bypass_cache */);
 }
 
 void ServiceWorkerContextWrapper::StartServiceWorkerForNavigationHintOnIO(
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h
index 79ef061..dab50e2 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/macros.h"
@@ -38,10 +39,10 @@
 class StoragePartitionImpl;
 class URLLoaderFactoryGetter;
 
-// A refcounted wrapper class for our core object. Higher level content lib
-// classes keep references to this class on mutliple threads. The inner core
-// instance is strictly single threaded and is not refcounted, the core object
-// is what is used internally in the service worker lib.
+// A refcounted wrapper class for ServiceWorkerContextCore. Higher level content
+// lib classes keep references to this class on multiple threads. The inner core
+// instance is strictly single threaded and is not refcounted. The core object
+// is what is used internally by service worker classes.
 class CONTENT_EXPORT ServiceWorkerContextWrapper
     : public ServiceWorkerContext,
       public ServiceWorkerContextCoreObserver,
@@ -57,7 +58,7 @@
   using GetUserDataForAllRegistrationsCallback =
       ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback;
 
-  ServiceWorkerContextWrapper(BrowserContext* browser_context);
+  explicit ServiceWorkerContextWrapper(BrowserContext* browser_context);
 
   // Init and Shutdown are for use on the UI thread when the profile,
   // storagepartition is being setup and torn down.
@@ -103,31 +104,30 @@
   void RemoveObserver(ServiceWorkerContextObserver* observer) override;
   void RegisterServiceWorker(const GURL& pattern,
                              const GURL& script_url,
-                             const ResultCallback& continuation) override;
+                             ResultCallback callback) override;
   void UnregisterServiceWorker(const GURL& pattern,
-                               const ResultCallback& continuation) override;
-  void GetAllOriginsInfo(const GetUsageInfoCallback& callback) override;
-  void DeleteForOrigin(const GURL& origin,
-                       const ResultCallback& callback) override;
-  void CheckHasServiceWorker(
-      const GURL& url,
-      const GURL& other_url,
-      const CheckHasServiceWorkerCallback& callback) override;
-  void CountExternalRequestsForTest(
-      const GURL& url,
-      const CountExternalRequestsCallback& callback) override;
-  void StopAllServiceWorkersForOrigin(const GURL& origin) override;
-  void ClearAllServiceWorkersForTest(const base::Closure& callback) override;
+                               ResultCallback callback) override;
   bool StartingExternalRequest(int64_t service_worker_version_id,
                                const std::string& request_uuid) override;
   bool FinishedExternalRequest(int64_t service_worker_version_id,
                                const std::string& request_uuid) override;
-  void StartServiceWorkerForNavigationHint(
-      const GURL& document_url,
-      const StartServiceWorkerForNavigationHintCallback& callback) override;
+  void CountExternalRequestsForTest(
+      const GURL& url,
+      const CountExternalRequestsCallback& callback) override;
+  void GetAllOriginsInfo(const GetUsageInfoCallback& callback) override;
+  void DeleteForOrigin(const GURL& origin, ResultCallback callback) override;
+  void CheckHasServiceWorker(
+      const GURL& url,
+      const GURL& other_url,
+      const CheckHasServiceWorkerCallback& callback) override;
+  void ClearAllServiceWorkersForTest(const base::Closure& callback) override;
   void StartActiveWorkerForPattern(const GURL& pattern,
                                    StartActiveWorkerCallback info_callback,
                                    base::OnceClosure failure_callback) override;
+  void StartServiceWorkerForNavigationHint(
+      const GURL& document_url,
+      const StartServiceWorkerForNavigationHintCallback& callback) override;
+  void StopAllServiceWorkersForOrigin(const GURL& origin) override;
 
   // These methods must only be called from the IO thread.
   ServiceWorkerRegistration* GetLiveRegistration(int64_t registration_id);
@@ -238,12 +238,12 @@
   // be called on the UI thread.
   void StartServiceWorker(const GURL& pattern, const StatusCallback& callback);
 
-  // This function can be called from any thread.
-  void SkipWaitingWorker(const GURL& pattern);
-
   // These methods can be called from any thread.
+  void SkipWaitingWorker(const GURL& pattern);
   void UpdateRegistration(const GURL& pattern);
   void SetForceUpdateOnPageLoad(bool force_update_on_page_load);
+  // Different from AddObserver/RemoveObserver(ServiceWorkerContextObserver*).
+  // But we must keep the same name, or else base::ScopedObserver breaks.
   void AddObserver(ServiceWorkerContextCoreObserver* observer);
   void RemoveObserver(ServiceWorkerContextCoreObserver* observer);
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index 8be993b..dccc20b 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -221,7 +221,9 @@
 
   url_job_ = base::MakeUnique<ServiceWorkerURLJobWrapper>(
       base::MakeUnique<ServiceWorkerURLLoaderJob>(
-          std::move(callback), this, resource_request, blob_storage_context_));
+          std::move(callback), this, resource_request,
+          make_scoped_refptr(context_->loader_factory_getter()),
+          blob_storage_context_));
 
   resource_context_ = resource_context;
 
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index d4ffc47b..ab29a95d 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -19,8 +19,10 @@
 #include "content/browser/loader/resource_requester_info.h"
 #include "content/browser/loader/url_loader_factory_impl.h"
 #include "content/browser/service_worker/embedded_worker_status.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_metrics.h"
 #include "content/browser/service_worker/service_worker_version.h"
+#include "content/browser/url_loader_factory_getter.h"
 #include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_status_code.h"
@@ -114,9 +116,10 @@
     agent_host->NavigationPreloadCompleted(request_id, completion_status);
 }
 
-// This class wraps a mojo::InterfacePtr<URLLoaderClient>. It also is a
-// URLLoaderClient implementation and delegates URLLoaderClient calls to the
-// wrapped client.
+// DelegatingURLLoaderClient is the URLLoaderClient for the navigation preload
+// network request. It watches as the response comes in, and pipes the response
+// back to the service worker while also doing extra processing like notifying
+// DevTools.
 class DelegatingURLLoaderClient final : public mojom::URLLoaderClient {
  public:
   using WorkerId = std::pair<int, int>;
@@ -492,7 +495,6 @@
 void ServiceWorkerFetchDispatcher::DispatchFetchEvent() {
   DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, version_->running_status())
       << "Worker stopped too soon after it was started.";
-
   DCHECK(!prepare_callback_.is_null());
   base::Closure prepare_callback = prepare_callback_;
   prepare_callback.Run();
@@ -678,13 +680,83 @@
       net::MutableNetworkTrafficAnnotationTag(
           original_request->traffic_annotation()));
 
-  std::unique_ptr<DelegatingURLLoader> url_loader(
-      base::MakeUnique<DelegatingURLLoader>(
-          std::move(url_loader_associated_ptr)));
+  auto url_loader = std::make_unique<DelegatingURLLoader>(
+      std::move(url_loader_associated_ptr));
   preload_handle_->url_loader = url_loader->CreateInterfacePtrAndBind();
-  url_loader_assets_ =
-      new URLLoaderAssets(std::move(url_loader_factory), std::move(url_loader),
-                          std::move(url_loader_client));
+  url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
+      std::move(url_loader_factory), std::move(url_loader),
+      std::move(url_loader_client));
+  return true;
+}
+
+// S13nServiceWorker
+bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreloadWithURLLoader(
+    const ResourceRequest& original_request,
+    URLLoaderFactoryGetter* url_loader_factory_getter,
+    base::OnceClosure on_response) {
+  if (resource_type_ != RESOURCE_TYPE_MAIN_FRAME &&
+      resource_type_ != RESOURCE_TYPE_SUB_FRAME) {
+    return false;
+  }
+  if (!version_->navigation_preload_state().enabled)
+    return false;
+  // TODO(horo): Currently NavigationPreload doesn't support request body.
+  if (!request_->blob_uuid.empty())
+    return false;
+
+  ResourceRequest resource_request(original_request);
+  // Set to SUB_RESOURCE because we shouldn't trigger NavigationResourceThrottle
+  // for the service worker navigation preload request.
+  resource_request.resource_type = RESOURCE_TYPE_SUB_RESOURCE;
+  resource_request.service_worker_mode = ServiceWorkerMode::NONE;
+  resource_request.do_not_prompt_for_login = true;
+  DCHECK(net::HttpUtil::IsValidHeaderValue(
+      version_->navigation_preload_state().header));
+  // TODO(crbug/762357): Record header size UMA, but not until *all* the
+  // navigation preload metrics are recorded on the S13N path; otherwise the
+  // metrics will get unbalanced.
+  // ServiceWorkerMetrics::RecordNavigationPreloadRequestHeaderSize(
+  //     version_->navigation_preload_state().header.length());
+  resource_request.headers.SetHeader(
+      "Service-Worker-Navigation-Preload",
+      version_->navigation_preload_state().header);
+
+  preload_handle_ = mojom::FetchEventPreloadHandle::New();
+
+  // Create the DelegatingURLLoaderClient, which becomes the
+  // URLLoaderClient for the navigation preload network request.
+  mojom::URLLoaderClientPtr url_loader_client_ptr;
+  preload_handle_->url_loader_client_request =
+      mojo::MakeRequest(&url_loader_client_ptr);
+  auto url_loader_client = base::MakeUnique<DelegatingURLLoaderClient>(
+      std::move(url_loader_client_ptr), std::move(on_response),
+      resource_request);
+
+  // Start the network request for the URL using the network loader.
+  // TODO(falken): What to do about routing_id, request_id, traffic annotation?
+  mojom::URLLoaderClientPtr url_loader_client_ptr_to_pass;
+  url_loader_client->Bind(&url_loader_client_ptr_to_pass);
+  mojom::URLLoaderPtr url_loader_associated_ptr;
+  url_loader_factory_getter->GetNetworkFactory()->get()->CreateLoaderAndStart(
+      mojo::MakeRequest(&url_loader_associated_ptr), -1 /* routing_id? */,
+      -1 /* request_id? */, mojom::kURLLoadOptionNone, resource_request,
+      std::move(url_loader_client_ptr_to_pass),
+      net::MutableNetworkTrafficAnnotationTag() /* empty? */);
+
+  // Hook the load up to DelegatingURLLoader, which will call our
+  // DelegatingURLLoaderClient.
+  auto url_loader = std::make_unique<DelegatingURLLoader>(
+      std::move(url_loader_associated_ptr));
+  preload_handle_->url_loader = url_loader->CreateInterfacePtrAndBind();
+
+  DCHECK(!url_loader_assets_);
+  // Unlike the non-S13N code path, we don't own the URLLoaderFactory being used
+  // (it's the generic network factory), so we don't need to pass it to
+  // URLLoaderAssets to keep it alive.
+  mojom::URLLoaderFactoryPtr null_factory;
+  url_loader_assets_ = base::MakeRefCounted<URLLoaderAssets>(
+      std::move(null_factory), std::move(url_loader),
+      std::move(url_loader_client));
   return true;
 }
 
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h
index aa6029a..3df99fe 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -32,6 +32,7 @@
 namespace content {
 
 class ServiceWorkerVersion;
+class URLLoaderFactoryGetter;
 
 // A helper class to dispatch fetch event to a service worker.
 class CONTENT_EXPORT ServiceWorkerFetchDispatcher {
@@ -59,6 +60,12 @@
   // |on_response| is invoked in OnReceiveResponse().
   bool MaybeStartNavigationPreload(net::URLRequest* original_request,
                                    base::OnceClosure on_response);
+  // S13nServiceWorker
+  // Same as above but for S13N.
+  bool MaybeStartNavigationPreloadWithURLLoader(
+      const ResourceRequest& original_request,
+      URLLoaderFactoryGetter* url_loader_factory_getter,
+      base::OnceClosure on_response);
 
   // Dispatches a fetch event to the |version| given in ctor, and fires
   // |fetch_callback| (also given in ctor) when finishes. It runs
@@ -109,6 +116,9 @@
 
   scoped_refptr<URLLoaderAssets> url_loader_assets_;
 
+  // |preload_handle_| holds the URLLoader and URLLoaderClient for the service
+  // worker to receive the navigation preload response. It's passed to the
+  // service worker along with the fetch event.
   mojom::FetchEventPreloadHandlePtr preload_handle_;
 
   base::WeakPtrFactory<ServiceWorkerFetchDispatcher> weak_factory_;
diff --git a/content/browser/service_worker/service_worker_script_url_loader.cc b/content/browser/service_worker/service_worker_script_url_loader.cc
index b491867..3d68f4a2 100644
--- a/content/browser/service_worker/service_worker_script_url_loader.cc
+++ b/content/browser/service_worker/service_worker_script_url_loader.cc
@@ -45,22 +45,26 @@
     const ResourceResponseHead& response_head,
     const base::Optional<net::SSLInfo>& ssl_info,
     mojom::DownloadedTempFilePtr downloaded_file) {
-  if (version_->context() && !version_->is_redundant()) {
-    // We don't have complete info here, but fill in what we have now.
-    // At least we need headers and SSL info.
-    net::HttpResponseInfo response_info;
-    response_info.headers = response_head.headers;
-    if (ssl_info.has_value())
-      response_info.ssl_info = *ssl_info;
-    response_info.was_fetched_via_spdy = response_head.was_fetched_via_spdy;
-    response_info.was_alpn_negotiated = response_head.was_alpn_negotiated;
-    response_info.alpn_negotiated_protocol =
-        response_head.alpn_negotiated_protocol;
-    response_info.connection_info = response_head.connection_info;
-    response_info.socket_address = response_head.socket_address;
-
-    version_->SetMainScriptHttpResponseInfo(response_info);
+  if (!version_->context() || version_->is_redundant()) {
+    OnComplete(ResourceRequestCompletionStatus(net::ERR_FAILED));
+    return;
   }
+
+  // We don't have complete info here, but fill in what we have now.
+  // At least we need headers and SSL info.
+  net::HttpResponseInfo response_info;
+  response_info.headers = response_head.headers;
+  if (ssl_info.has_value())
+    response_info.ssl_info = *ssl_info;
+  response_info.was_fetched_via_spdy = response_head.was_fetched_via_spdy;
+  response_info.was_alpn_negotiated = response_head.was_alpn_negotiated;
+  response_info.alpn_negotiated_protocol =
+      response_head.alpn_negotiated_protocol;
+  response_info.connection_info = response_head.connection_info;
+  response_info.socket_address = response_head.socket_address;
+
+  version_->SetMainScriptHttpResponseInfo(response_info);
+
   forwarding_client_->OnReceiveResponse(response_head, ssl_info,
                                         std::move(downloaded_file));
 }
diff --git a/content/browser/service_worker/service_worker_url_loader_job.cc b/content/browser/service_worker/service_worker_url_loader_job.cc
index 020ca4a..212f1830 100644
--- a/content/browser/service_worker/service_worker_url_loader_job.cc
+++ b/content/browser/service_worker/service_worker_url_loader_job.cc
@@ -4,16 +4,15 @@
 
 #include "content/browser/service_worker/service_worker_url_loader_job.h"
 
-#include "base/strings/stringprintf.h"
 #include "content/browser/blob_storage/blob_url_loader_factory.h"
 #include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
 #include "content/browser/service_worker/service_worker_version.h"
+#include "content/browser/url_loader_factory_getter.h"
+#include "content/common/service_worker/service_worker_loader_helpers.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/content_switches.h"
-#include "net/base/io_buffer.h"
-#include "net/http/http_util.h"
 #include "storage/browser/blob/blob_reader.h"
 #include "storage/browser/blob/blob_storage_context.h"
 
@@ -23,15 +22,16 @@
     LoaderCallback callback,
     Delegate* delegate,
     const ResourceRequest& resource_request,
+    scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter,
     base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
     : loader_callback_(std::move(callback)),
       delegate_(delegate),
       resource_request_(resource_request),
+      url_loader_factory_getter_(std::move(url_loader_factory_getter)),
       blob_storage_context_(blob_storage_context),
       blob_client_binding_(this),
       binding_(this),
-      weak_factory_(this) {
-}
+      weak_factory_(this) {}
 
 ServiceWorkerURLLoaderJob::~ServiceWorkerURLLoaderJob() {}
 
@@ -100,88 +100,24 @@
   }
 
   fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher(
-      CreateFetchRequest(resource_request_), active_worker,
-      resource_request_.resource_type, base::nullopt,
+      ServiceWorkerLoaderHelpers::CreateFetchRequest(resource_request_),
+      active_worker, resource_request_.resource_type, base::nullopt,
       net::NetLogWithSource() /* TODO(scottmg): net log? */,
       base::Bind(&ServiceWorkerURLLoaderJob::DidPrepareFetchEvent,
                  weak_factory_.GetWeakPtr(), make_scoped_refptr(active_worker)),
       base::Bind(&ServiceWorkerURLLoaderJob::DidDispatchFetchEvent,
                  weak_factory_.GetWeakPtr())));
-  // TODO(kinuko): Handle navigation preload.
+  fetch_dispatcher_->MaybeStartNavigationPreloadWithURLLoader(
+      resource_request_, url_loader_factory_getter_.get(),
+      base::BindOnce(&base::DoNothing /* TODO(crbug/762357): metrics? */));
   fetch_dispatcher_->Run();
 }
 
-std::unique_ptr<ServiceWorkerFetchRequest>
-ServiceWorkerURLLoaderJob::CreateFetchRequest(const ResourceRequest& request) {
-  std::string blob_uuid;
-  uint64_t blob_size = 0;
-  // TODO(scottmg): Implement passing body as blob to handler.
-  DCHECK(!request.request_body);
-  auto new_request = base::MakeUnique<ServiceWorkerFetchRequest>();
-  new_request->mode = request.fetch_request_mode;
-  new_request->is_main_resource_load =
-      ServiceWorkerUtils::IsMainResourceType(request.resource_type);
-  new_request->request_context_type = request.fetch_request_context_type;
-  new_request->frame_type = request.fetch_frame_type;
-  new_request->url = request.url;
-  new_request->method = request.method;
-  new_request->blob_uuid = blob_uuid;
-  new_request->blob_size = blob_size;
-  new_request->credentials_mode = request.fetch_credentials_mode;
-  new_request->redirect_mode = request.fetch_redirect_mode;
-  new_request->is_reload = ui::PageTransitionCoreTypeIs(
-      request.transition_type, ui::PAGE_TRANSITION_RELOAD);
-  new_request->referrer =
-      Referrer(GURL(request.referrer), request.referrer_policy);
-  new_request->fetch_type = ServiceWorkerFetchType::FETCH;
-  return new_request;
-}
-
-void ServiceWorkerURLLoaderJob::SaveResponseInfo(
-    const ServiceWorkerResponse& response) {
-  response_head_.was_fetched_via_service_worker = true;
-  response_head_.was_fetched_via_foreign_fetch = false;
-  response_head_.was_fallback_required_by_service_worker = false;
-  response_head_.url_list_via_service_worker = response.url_list;
-  response_head_.response_type_via_service_worker = response.response_type;
-  response_head_.is_in_cache_storage = response.is_in_cache_storage;
-  response_head_.cache_storage_cache_name = response.cache_storage_cache_name;
-  response_head_.cors_exposed_header_names = response.cors_exposed_header_names;
-  response_head_.did_service_worker_navigation_preload =
-      did_navigation_preload_;
-}
-
-void ServiceWorkerURLLoaderJob::SaveResponseHeaders(
-    int status_code,
-    const std::string& status_text,
-    const ServiceWorkerHeaderMap& headers) {
-  // Build a string instead of using HttpResponseHeaders::AddHeader on
-  // each header, since AddHeader has O(n^2) performance.
-  std::string buf(base::StringPrintf("HTTP/1.1 %d %s\r\n", status_code,
-                                     status_text.c_str()));
-  for (const auto& item : headers) {
-    buf.append(item.first);
-    buf.append(": ");
-    buf.append(item.second);
-    buf.append("\r\n");
-  }
-  buf.append("\r\n");
-
-  response_head_.headers = new net::HttpResponseHeaders(
-      net::HttpUtil::AssembleRawHeaders(buf.c_str(), buf.size()));
-  if (response_head_.mime_type.empty()) {
-    std::string mime_type;
-    response_head_.headers->GetMimeType(&mime_type);
-    if (mime_type.empty())
-      mime_type = "text/plain";
-    response_head_.mime_type = mime_type;
-  }
-}
-
 void ServiceWorkerURLLoaderJob::CommitResponseHeaders() {
   DCHECK_EQ(Status::kStarted, status_);
   status_ = Status::kSentHeader;
-  url_loader_client_->OnReceiveResponse(response_head_, ssl_info_, nullptr);
+  url_loader_client_->OnReceiveResponse(response_head_, ssl_info_,
+                                        nullptr /* downloaded_file */);
 }
 
 void ServiceWorkerURLLoaderJob::CommitCompleted(int error_code) {
@@ -197,8 +133,9 @@
   DCHECK_GT(status_, Status::kNotStarted);
   DCHECK_LT(status_, Status::kCompleted);
   if (status_ < Status::kSentHeader) {
-    SaveResponseHeaders(500, "Service Worker Response Error",
-                        ServiceWorkerHeaderMap());
+    ServiceWorkerLoaderHelpers::SaveResponseHeaders(
+        500, "Service Worker Response Error", ServiceWorkerHeaderMap(),
+        &response_head_);
     CommitResponseHeaders();
   }
   CommitCompleted(net::ERR_FAILED);
@@ -274,9 +211,10 @@
       &ServiceWorkerURLLoaderJob::Cancel, base::Unretained(this)));
   url_loader_client_ = std::move(client);
 
-  SaveResponseInfo(response);
-  SaveResponseHeaders(response.status_code, response.status_text,
-                      response.headers);
+  ServiceWorkerLoaderHelpers::SaveResponseInfo(response, &response_head_);
+  ServiceWorkerLoaderHelpers::SaveResponseHeaders(
+      response.status_code, response.status_text, response.headers,
+      &response_head_);
 
   // Handle a stream response body.
   if (!body_as_stream.is_null() && body_as_stream->stream.is_valid()) {
@@ -330,8 +268,11 @@
     mojom::DownloadedTempFilePtr downloaded_file) {
   DCHECK_EQ(Status::kStarted, status_);
   status_ = Status::kSentHeader;
-  if (response_head.headers->response_code() >= 400)
+  if (response_head.headers->response_code() >= 400) {
+    DVLOG(1) << "Blob::OnReceiveResponse got error: "
+             << response_head.headers->response_code();
     response_head_.headers = response_head.headers;
+  }
   url_loader_client_->OnReceiveResponse(response_head_, ssl_info,
                                         std::move(downloaded_file));
 }
diff --git a/content/browser/service_worker/service_worker_url_loader_job.h b/content/browser/service_worker/service_worker_url_loader_job.h
index 1d292a04..1aa34897 100644
--- a/content/browser/service_worker/service_worker_url_loader_job.h
+++ b/content/browser/service_worker/service_worker_url_loader_job.h
@@ -11,6 +11,7 @@
 #include "content/browser/service_worker/service_worker_metrics.h"
 #include "content/browser/service_worker/service_worker_response_type.h"
 #include "content/browser/service_worker/service_worker_url_job_wrapper.h"
+#include "content/browser/url_loader_factory_getter.h"
 #include "content/common/service_worker/service_worker_status_code.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/url_loader.mojom.h"
@@ -73,6 +74,7 @@
       LoaderCallback loader_callback,
       Delegate* delegate,
       const ResourceRequest& resource_request,
+      scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter,
       base::WeakPtr<storage::BlobStorageContext> blob_storage_context);
 
   ~ServiceWorkerURLLoaderJob() override;
@@ -109,17 +111,7 @@
                      mojom::URLLoaderClientPtr client);
   void AfterRead(scoped_refptr<net::IOBuffer> buffer, int bytes);
 
-  std::unique_ptr<ServiceWorkerFetchRequest> CreateFetchRequest(
-      const ResourceRequest& request);
-
-  // Populates |response_info_| (except for headers) with given |response|.
-  void SaveResponseInfo(const ServiceWorkerResponse& response);
-  // Generates and populates |response.headers|.
-  void SaveResponseHeaders(int status_code,
-                           const std::string& status_text,
-                           const ServiceWorkerHeaderMap& headers);
   // Calls url_loader_client_->OnReceiveResopnse() with |response_head_|.
-  // Expected to be called afer saving response info/headers.
   void CommitResponseHeaders();
   // Calls url_loader_client_->OnComplete(). Expected to be called after
   // CommitResponseHeaders (i.e. status_ == kSentHeader).
@@ -155,6 +147,7 @@
 
   Delegate* delegate_;
   ResourceRequest resource_request_;
+  scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter_;
   base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
   std::unique_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
 
diff --git a/content/browser/service_worker/service_worker_url_loader_job_unittest.cc b/content/browser/service_worker/service_worker_url_loader_job_unittest.cc
index 977bfe8..b5c7025 100644
--- a/content/browser/service_worker/service_worker_url_loader_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_loader_job_unittest.cc
@@ -14,6 +14,8 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_url_loader_client.h"
 #include "mojo/common/data_pipe_utils.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/http/http_util.h"
 #include "net/ssl/ssl_info.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -31,13 +33,168 @@
   *out_callback = std::move(callback);
 }
 
-}  // namespace
+// NavigationPreloadLoaderClient mocks the renderer-side URLLoaderClient for the
+// navigation preload network request performed by the browser. In production
+// code, this is ServiceWorkerContextClient::NavigationPreloadRequest,
+// which it forwards the response to FetchEvent#preloadResponse. Here, it
+// simulates passing the response to FetchEvent#respondWith.
+//
+// The navigation preload test is quite involved. The flow of data is:
+// 1. ServiceWorkerURLLoaderJob asks ServiceWorkerFetchDispatcher to start
+//    navigation preload.
+// 2. ServiceWorkerFetchDispatcher starts the network request which is mocked
+//    by MockNetworkURLLoaderFactory. The response is sent to
+//    ServiceWorkerFetchDispatcher::DelegatingURLLoaderClient.
+// 3. DelegatingURLLoaderClient sends the response to the |preload_handle|
+//    that was passed to Helper::OnFetchEvent().
+// 4. Helper::OnFetchEvent() creates NavigationPreloadLoaderClient, which
+//    receives the response.
+// 5. NavigationPreloadLoaderClient calls OnFetchEvent()'s callbacks
+//    with the response.
+// 6. Like all FetchEvent responses, the response is sent to
+//    ServiceWorkerURLLoaderJob::DidDispatchFetchEvent, and the
+//    StartLoaderCallback is returned.
+class NavigationPreloadLoaderClient final : public mojom::URLLoaderClient {
+ public:
+  NavigationPreloadLoaderClient(
+      mojom::FetchEventPreloadHandlePtr preload_handle,
+      mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
+      EmbeddedWorkerTestHelper::FetchCallback finish_callback)
+      : url_loader_(std::move(preload_handle->url_loader)),
+        binding_(this, std::move(preload_handle->url_loader_client_request)),
+        response_callback_(std::move(response_callback)),
+        finish_callback_(std::move(finish_callback)) {
+    binding_.set_connection_error_handler(
+        base::BindOnce(&NavigationPreloadLoaderClient::OnConnectionError,
+                       base::Unretained(this)));
+  }
+  ~NavigationPreloadLoaderClient() override = default;
+
+  // mojom::URLLoaderClient implementation
+  void OnReceiveResponse(
+      const ResourceResponseHead& response_head,
+      const base::Optional<net::SSLInfo>& ssl_info,
+      mojom::DownloadedTempFilePtr downloaded_file) override {
+    response_head_ = response_head;
+  }
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override {
+    body_ = std::move(body);
+    // We could call OnResponseStream() here, but for simplicity, don't do
+    // anything until OnComplete().
+  }
+  void OnComplete(const ResourceRequestCompletionStatus& status) override {
+    blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
+    auto stream_handle = blink::mojom::ServiceWorkerStreamHandle::New();
+    stream_handle->callback_request = mojo::MakeRequest(&stream_callback);
+    stream_handle->stream = std::move(body_);
+
+    // Simulate passing the navigation preload response to
+    // FetchEvent#respondWith.
+    response_callback_->OnResponseStream(
+        ServiceWorkerResponse(
+            base::MakeUnique<std::vector<GURL>>(
+                response_head_.url_list_via_service_worker),
+            response_head_.headers->response_code(),
+            response_head_.headers->GetStatusText(),
+            response_head_.response_type_via_service_worker,
+            base::MakeUnique<ServiceWorkerHeaderMap>(), "" /* blob_uuid */,
+            0 /* blob_size */, nullptr /* blob */,
+            blink::kWebServiceWorkerResponseErrorUnknown, base::Time(),
+            false /* response_is_in_cache_storage */,
+            std::string() /* response_cache_storage_cache_name */,
+            base::MakeUnique<
+                ServiceWorkerHeaderList>() /* cors_exposed_header_names */),
+        std::move(stream_handle), base::Time::Now());
+    std::move(finish_callback_).Run(SERVICE_WORKER_OK, base::Time::Now());
+    stream_callback->OnCompleted();
+    delete this;
+  }
+  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+                         const ResourceResponseHead& response_head) override {}
+  void OnDataDownloaded(int64_t data_length,
+                        int64_t encoded_data_length) override {}
+  void OnUploadProgress(int64_t current_position,
+                        int64_t total_size,
+                        OnUploadProgressCallback ack_callback) override {}
+  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
+
+  void OnConnectionError() { delete this; }
+
+ private:
+  mojom::URLLoaderPtr url_loader_;
+  mojo::Binding<mojom::URLLoaderClient> binding_;
+
+  ResourceResponseHead response_head_;
+  mojo::ScopedDataPipeConsumerHandle body_;
+
+  // Callbacks that complete Helper::OnFetchEvent().
+  mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_;
+  EmbeddedWorkerTestHelper::FetchCallback finish_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(NavigationPreloadLoaderClient);
+};
+
+// A URLLoaderFactory that returns 200 OK with a simple body to any request.
+//
+// ServiceWorkerURLLoaderJobTest sets the network factory for
+// ServiceWorkerContextCore to MockNetworkURLLoaderFactory. So far, it's only
+// used for navigation preload in these tests.
+class MockNetworkURLLoaderFactory final : public mojom::URLLoaderFactory {
+ public:
+  MockNetworkURLLoaderFactory() = default;
+
+  // mojom::URLLoaderFactory implementation.
+  void CreateLoaderAndStart(mojom::URLLoaderRequest request,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const ResourceRequest& url_request,
+                            mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override {
+    std::string headers = "HTTP/1.1 200 OK\n\n";
+    net::HttpResponseInfo info;
+    info.headers = new net::HttpResponseHeaders(
+        net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.length()));
+    ResourceResponseHead response;
+    response.headers = info.headers;
+    response.headers->GetMimeType(&response.mime_type);
+    client->OnReceiveResponse(response, base::nullopt, nullptr);
+
+    std::string body = "this body came from the network";
+    uint32_t bytes_written = body.size();
+    mojo::DataPipe data_pipe;
+    data_pipe.producer_handle->WriteData(body.data(), &bytes_written,
+                                         MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
+    client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
+
+    ResourceRequestCompletionStatus status;
+    status.error_code = net::OK;
+    client->OnComplete(status);
+  }
+
+  void Clone(mojom::URLLoaderFactoryRequest factory) override { NOTREACHED(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockNetworkURLLoaderFactory);
+};
 
 // Helper simulates a service worker handling fetch events. The response can be
 // customized via RespondWith* functions.
 class Helper : public EmbeddedWorkerTestHelper {
  public:
-  Helper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+  Helper()
+      : EmbeddedWorkerTestHelper(
+            base::FilePath(),
+            base::MakeRefCounted<URLLoaderFactoryGetter>()) {
+    mojom::URLLoaderFactoryPtr mock_loader_factory;
+    mojo::MakeStrongBinding(base::MakeUnique<MockNetworkURLLoaderFactory>(),
+                            MakeRequest(&mock_loader_factory));
+    url_loader_factory_getter()->SetNetworkFactoryForTesting(
+        std::move(mock_loader_factory));
+  }
   ~Helper() override = default;
 
   // Tells this helper to respond to fetch events with the specified blob.
@@ -58,11 +215,18 @@
   }
 
   // Tells this helper to respond to fetch events with network fallback.
-  // i.e.,simulate the service worker not calling respondWith().
+  // i.e., simulate the service worker not calling respondWith().
   void RespondWithFallback() {
     response_mode_ = ResponseMode::kFallbackResponse;
   }
 
+  // Tells this helper to respond to fetch events with
+  // FetchEvent#preloadResponse. See NavigationPreloadLoaderClient's
+  // documentation for details.
+  void RespondWithNavigationPreloadResponse() {
+    response_mode_ = ResponseMode::kNavigationPreloadResponse;
+  }
+
   // Tells this helper to simulate failure to dispatch the fetch event to the
   // service worker.
   void FailToDispatchFetchEvent() {
@@ -131,6 +295,12 @@
         response_callback->OnFallback(base::Time::Now());
         std::move(finish_callback).Run(SERVICE_WORKER_OK, base::Time::Now());
         return;
+      case ResponseMode::kNavigationPreloadResponse:
+        // Deletes itself when done.
+        new NavigationPreloadLoaderClient(std::move(preload_handle),
+                                          std::move(response_callback),
+                                          std::move(finish_callback));
+        return;
       case ResponseMode::kFailFetchEventDispatch:
         // Simulate failure by stopping the worker before the event finishes.
         // This causes ServiceWorkerVersion::StartRequest() to call its error
@@ -172,6 +342,7 @@
     kBlob,
     kStream,
     kFallbackResponse,
+    kNavigationPreloadResponse,
     kFailFetchEventDispatch,
     kEarlyResponse
   };
@@ -191,6 +362,8 @@
   DISALLOW_COPY_AND_ASSIGN(Helper);
 };
 
+}  // namespace
+
 // ServiceWorkerURLLoaderJobTest is for testing the handling of requests
 // by a service worker via ServiceWorkerURLLoaderJob.
 //
@@ -264,6 +437,8 @@
     StartLoaderCallback callback;
     job_ = base::MakeUnique<ServiceWorkerURLLoaderJob>(
         base::BindOnce(&ReceiveStartLoaderCallback, &callback), this, request,
+        make_scoped_refptr<URLLoaderFactoryGetter>(
+            helper_->context()->loader_factory_getter()),
         GetBlobStorageContext());
     job_->ForwardToServiceWorker();
     base::RunLoop().RunUntilIdle();
@@ -542,6 +717,8 @@
   StartLoaderCallback callback;
   auto job = base::MakeUnique<ServiceWorkerURLLoaderJob>(
       base::BindOnce(&ReceiveStartLoaderCallback, &callback), this, request,
+      make_scoped_refptr<URLLoaderFactoryGetter>(
+          helper_->context()->loader_factory_getter()),
       GetBlobStorageContext());
   // Ask the job to fallback to network. In production code,
   // ServiceWorkerControlleeRequestHandler calls FallbackToNetwork() to do this.
@@ -550,4 +727,22 @@
   EXPECT_FALSE(callback);
 }
 
+// Test responding to the fetch event with the navigation preload response.
+TEST_F(ServiceWorkerURLLoaderJobTest, NavigationPreload) {
+  registration_->EnableNavigationPreload(true);
+  helper_->RespondWithNavigationPreloadResponse();
+  JobResult result = TestRequest();
+  ASSERT_EQ(JobResult::kHandledRequest, result);
+  EXPECT_EQ(net::OK, client_.completion_status().error_code);
+  const ResourceResponseHead& info = client_.response_head();
+  EXPECT_EQ(200, info.headers->response_code());
+  ExpectFetchedViaServiceWorker(info);
+
+  std::string response;
+  EXPECT_TRUE(client_.response_body().is_valid());
+  EXPECT_TRUE(mojo::common::BlockingCopyToString(
+      client_.response_body_release(), &response));
+  EXPECT_EQ("this body came from the network", response);
+}
+
 }  // namespace content
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index 82382f38..579df51 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -109,7 +109,10 @@
   CHECK_EQ(result, MOJO_RESULT_OK);
 
   client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
-  client->OnComplete(ResourceRequestCompletionStatus(output_size));
+  ResourceRequestCompletionStatus status(net::OK);
+  status.encoded_data_length = output_size;
+  status.encoded_body_length = output_size;
+  client->OnComplete(status);
 }
 
 void DataAvailable(scoped_refptr<ResourceResponse> headers,
diff --git a/content/child/DEPS b/content/child/DEPS
index 4883d49..2e4293e 100644
--- a/content/child/DEPS
+++ b/content/child/DEPS
@@ -1,8 +1,6 @@
 include_rules = [
   # Allow inclusion of specific components that we depend on.
   # See comment in content/DEPS for which components are allowed.
-  "+components/scheduler/child",
-  "+components/scheduler/common",
   "+components/tracing",
   "+components/variations/child_process_field_trial_syncer.h",
   "+components/webcrypto",
diff --git a/content/child/memory/child_memory_coordinator_impl.cc b/content/child/memory/child_memory_coordinator_impl.cc
index d74be35..ecf9542f 100644
--- a/content/child/memory/child_memory_coordinator_impl.cc
+++ b/content/child/memory/child_memory_coordinator_impl.cc
@@ -57,6 +57,7 @@
 
 ChildMemoryCoordinatorImpl::~ChildMemoryCoordinatorImpl() {
   base::AutoLock lock(*g_lock.Pointer());
+  base::MemoryCoordinatorProxy::SetMemoryCoordinator(nullptr);
   DCHECK(g_child_memory_coordinator == this);
   g_child_memory_coordinator = nullptr;
 }
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 852d066a..12d025b 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -375,9 +375,6 @@
     WebRuntimeFeatures::EnableWebNfc(true);
 #endif
 
-  if (base::FeatureList::IsEnabled(features::kIdleTimeSpellChecking))
-    WebRuntimeFeatures::EnableFeatureFromString("IdleTimeSpellChecking", true);
-
   if (media::GetEffectiveAutoplayPolicy(command_line) !=
       switches::autoplay::kNoUserGestureRequiredPolicy) {
     WebRuntimeFeatures::EnableAutoplayMutedVideos(true);
diff --git a/content/child/service_worker/service_worker_subresource_loader.cc b/content/child/service_worker/service_worker_subresource_loader.cc
index 6197dee..997a4cc 100644
--- a/content/child/service_worker/service_worker_subresource_loader.cc
+++ b/content/child/service_worker/service_worker_subresource_loader.cc
@@ -6,15 +6,12 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/callback.h"
-#include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/child/service_worker/service_worker_event_dispatcher_holder.h"
+#include "content/common/service_worker/service_worker_loader_helpers.h"
 #include "content/common/service_worker/service_worker_types.h"
-#include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/content_features.h"
-#include "net/base/io_buffer.h"
-#include "net/http/http_util.h"
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/platform/WebBlobRegistry.h"
 #include "ui/base/page_transition_types.h"
@@ -75,7 +72,8 @@
 
 void ServiceWorkerSubresourceLoader::StartRequest(
     const ResourceRequest& resource_request) {
-  auto request = CreateFetchRequest(resource_request);
+  std::unique_ptr<ServiceWorkerFetchRequest> request =
+      ServiceWorkerLoaderHelpers::CreateFetchRequest(resource_request);
   DCHECK_EQ(Status::kNotStarted, status_);
   status_ = Status::kStarted;
 
@@ -89,32 +87,6 @@
                  weak_factory_.GetWeakPtr()));
 }
 
-std::unique_ptr<ServiceWorkerFetchRequest>
-ServiceWorkerSubresourceLoader::CreateFetchRequest(
-    const ResourceRequest& request) {
-  std::string blob_uuid;
-  uint64_t blob_size = 0;
-  // TODO(kinuko): Implement request.request_body handling.
-  auto new_request = base::MakeUnique<ServiceWorkerFetchRequest>();
-  new_request->mode = request.fetch_request_mode;
-  new_request->is_main_resource_load =
-      ServiceWorkerUtils::IsMainResourceType(request.resource_type);
-  new_request->request_context_type = request.fetch_request_context_type;
-  new_request->frame_type = request.fetch_frame_type;
-  new_request->url = request.url;
-  new_request->method = request.method;
-  new_request->blob_uuid = blob_uuid;
-  new_request->blob_size = blob_size;
-  new_request->credentials_mode = request.fetch_credentials_mode;
-  new_request->redirect_mode = request.fetch_redirect_mode;
-  new_request->is_reload = ui::PageTransitionCoreTypeIs(
-      request.transition_type, ui::PAGE_TRANSITION_RELOAD);
-  new_request->referrer =
-      Referrer(GURL(request.referrer), request.referrer_policy);
-  new_request->fetch_type = ServiceWorkerFetchType::FETCH;
-  return new_request;
-}
-
 void ServiceWorkerSubresourceLoader::OnFetchEventFinished(
     ServiceWorkerStatusCode status,
     base::Time dispatch_event_time) {
@@ -167,15 +139,18 @@
     const ServiceWorkerResponse& response,
     storage::mojom::BlobPtr body_as_blob,
     blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream) {
-  SaveResponseInfo(response);
-  SaveResponseHeaders(response.status_code, response.status_text,
-                      response.headers);
+  ServiceWorkerLoaderHelpers::SaveResponseInfo(response, &response_head_);
+  ServiceWorkerLoaderHelpers::SaveResponseHeaders(
+      response.status_code, response.status_text, response.headers,
+      &response_head_);
 
   // Handle a stream response body.
   if (!body_as_stream.is_null() && body_as_stream->stream.is_valid()) {
     CommitResponseHeaders();
     url_loader_client_->OnStartLoadingResponseBody(
         std::move(body_as_stream->stream));
+    // TODO(falken): Call CommitCompleted() when stream finished.
+    // See https://crbug.com/758455
     CommitCompleted(net::OK);
     return;
   }
@@ -218,52 +193,13 @@
   CommitCompleted(net::OK);
 }
 
-void ServiceWorkerSubresourceLoader::SaveResponseInfo(
-    const ServiceWorkerResponse& response) {
-  response_head_.was_fetched_via_service_worker = true;
-  response_head_.was_fetched_via_foreign_fetch = false;
-  response_head_.was_fallback_required_by_service_worker = false;
-  response_head_.url_list_via_service_worker = response.url_list;
-  response_head_.response_type_via_service_worker = response.response_type;
-  response_head_.is_in_cache_storage = response.is_in_cache_storage;
-  response_head_.cache_storage_cache_name = response.cache_storage_cache_name;
-  response_head_.cors_exposed_header_names = response.cors_exposed_header_names;
-  response_head_.did_service_worker_navigation_preload = false;
-}
-
-void ServiceWorkerSubresourceLoader::SaveResponseHeaders(
-    int status_code,
-    const std::string& status_text,
-    const ServiceWorkerHeaderMap& headers) {
-  // Build a string instead of using HttpResponseHeaders::AddHeader on
-  // each header, since AddHeader has O(n^2) performance.
-  std::string buf(base::StringPrintf("HTTP/1.1 %d %s\r\n", status_code,
-                                     status_text.c_str()));
-  for (const auto& item : headers) {
-    buf.append(item.first);
-    buf.append(": ");
-    buf.append(item.second);
-    buf.append("\r\n");
-  }
-  buf.append("\r\n");
-
-  response_head_.headers = new net::HttpResponseHeaders(
-      net::HttpUtil::AssembleRawHeaders(buf.c_str(), buf.size()));
-  if (response_head_.mime_type.empty()) {
-    std::string mime_type;
-    response_head_.headers->GetMimeType(&mime_type);
-    if (mime_type.empty())
-      mime_type = "text/plain";
-    response_head_.mime_type = mime_type;
-  }
-}
-
 void ServiceWorkerSubresourceLoader::CommitResponseHeaders() {
   DCHECK_EQ(Status::kStarted, status_);
   status_ = Status::kSentHeader;
   // TODO(kinuko): Fill the ssl_info.
   url_loader_client_->OnReceiveResponse(response_head_,
-                                        base::nullopt /* ssl_info */, nullptr);
+                                        base::nullopt /* ssl_info_ */,
+                                        nullptr /* downloaded_file */);
 }
 
 void ServiceWorkerSubresourceLoader::CommitCompleted(int error_code) {
@@ -279,8 +215,9 @@
   DCHECK_GT(status_, Status::kNotStarted);
   DCHECK_LT(status_, Status::kCompleted);
   if (status_ < Status::kSentHeader) {
-    SaveResponseHeaders(500, "Service Worker Response Error",
-                        ServiceWorkerHeaderMap());
+    ServiceWorkerLoaderHelpers::SaveResponseHeaders(
+        500, "Service Worker Response Error", ServiceWorkerHeaderMap(),
+        &response_head_);
     CommitResponseHeaders();
   }
   CommitCompleted(net::ERR_FAILED);
diff --git a/content/child/service_worker/service_worker_subresource_loader.h b/content/child/service_worker/service_worker_subresource_loader.h
index 732d03c..c313b6b 100644
--- a/content/child/service_worker/service_worker_subresource_loader.h
+++ b/content/child/service_worker/service_worker_subresource_loader.h
@@ -17,7 +17,6 @@
 
 namespace content {
 
-struct ServiceWorkerFetchRequest;
 class ServiceWorkerEventDispatcherHolder;
 class ChildURLLoaderFactoryGetter;
 
@@ -51,8 +50,6 @@
   void DeleteSoon();
 
   void StartRequest(const ResourceRequest& resource_request);
-  std::unique_ptr<ServiceWorkerFetchRequest> CreateFetchRequest(
-      const ResourceRequest& request);
   void OnFetchEventFinished(ServiceWorkerStatusCode status,
                             base::Time dispatch_event_time);
 
@@ -77,14 +74,7 @@
   void SetPriority(net::RequestPriority priority,
                    int intra_priority_value) override;
 
-  // Populates |response_head_| (except for headers) with given |response|.
-  void SaveResponseInfo(const ServiceWorkerResponse& response);
-  // Generates and populates |response_head_.headers|.
-  void SaveResponseHeaders(int status_code,
-                           const std::string& status_text,
-                           const ServiceWorkerHeaderMap& headers);
   // Calls url_loader_client_->OnReceiveResponse() with |response_head_|.
-  // Expected to be called after saving response info/headers.
   void CommitResponseHeaders();
   // Calls url_loader_client_->OnComplete(). Expected to be called after
   // CommitResponseHeaders (i.e. status_ == kSentHeader).
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index fd50ca29..49e792b 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -10,7 +10,6 @@
 #include <memory>
 #include <string>
 #include <utility>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -29,6 +28,7 @@
 #include "content/child/ftp_directory_listing_response_delegate.h"
 #include "content/child/request_extra_data.h"
 #include "content/child/resource_dispatcher.h"
+#include "content/child/scoped_child_process_reference.h"
 #include "content/child/shared_memory_data_consumer_handle.h"
 #include "content/child/sync_load_response.h"
 #include "content/child/web_url_request_util.h"
@@ -93,6 +93,18 @@
 
 using HeadersVector = ResourceDevToolsInfo::HeadersVector;
 
+class KeepAliveHandleWithChildProcessReference {
+ public:
+  explicit KeepAliveHandleWithChildProcessReference(
+      mojom::KeepAliveHandlePtr ptr)
+      : keep_alive_handle_(std::move(ptr)) {}
+  ~KeepAliveHandleWithChildProcessReference() {}
+
+ private:
+  mojom::KeepAliveHandlePtr keep_alive_handle_;
+  ScopedChildProcessReference reference_;
+};
+
 // TODO(estark): Figure out a way for the embedder to provide the
 // security style for a resource. Ideally, the logic for assigning
 // per-resource security styles should live in the same place as the
@@ -370,7 +382,8 @@
   Context(WebURLLoaderImpl* loader,
           ResourceDispatcher* resource_dispatcher,
           scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-          mojom::URLLoaderFactory* factory);
+          mojom::URLLoaderFactory* factory,
+          mojom::KeepAliveHandlePtr keep_alive_handle);
 
   WebURLLoaderClient* client() const { return client_; }
   void set_client(WebURLLoaderClient* client) { client_ = client; }
@@ -425,6 +438,7 @@
   std::unique_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_;
   std::unique_ptr<StreamOverrideParameters> stream_override_;
   std::unique_ptr<SharedMemoryDataConsumerHandle::Writer> body_stream_writer_;
+  std::unique_ptr<KeepAliveHandleWithChildProcessReference> keep_alive_handle_;
   enum DeferState {NOT_DEFERRING, SHOULD_DEFER, DEFERRED_DATA};
   DeferState defers_loading_;
   int request_id_;
@@ -467,20 +481,26 @@
     WebURLLoaderImpl* loader,
     ResourceDispatcher* resource_dispatcher,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    mojom::URLLoaderFactory* url_loader_factory)
+    mojom::URLLoaderFactory* url_loader_factory,
+    mojom::KeepAliveHandlePtr keep_alive_handle_ptr)
     : loader_(loader),
       use_stream_on_response_(false),
       report_raw_headers_(false),
       client_(NULL),
       resource_dispatcher_(resource_dispatcher),
       task_runner_(std::move(task_runner)),
+      keep_alive_handle_(
+          keep_alive_handle_ptr
+              ? base::MakeUnique<KeepAliveHandleWithChildProcessReference>(
+                    std::move(keep_alive_handle_ptr))
+              : nullptr),
       defers_loading_(NOT_DEFERRING),
       request_id_(-1),
       url_loader_factory_(url_loader_factory) {
 #if DCHECK_IS_ON()
   const bool mojo_loading_enabled =
       base::FeatureList::IsEnabled(features::kLoadingWithMojo);
-  DCHECK(url_loader_factory_ || !mojo_loading_enabled);
+  DCHECK(url_loader_factory_ || !mojo_loading_enabled || !resource_dispatcher);
 #endif
 }
 
@@ -1065,10 +1085,21 @@
     ResourceDispatcher* resource_dispatcher,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     mojom::URLLoaderFactory* url_loader_factory)
+    : WebURLLoaderImpl(resource_dispatcher,
+                       std::move(task_runner),
+                       url_loader_factory,
+                       nullptr) {}
+
+WebURLLoaderImpl::WebURLLoaderImpl(
+    ResourceDispatcher* resource_dispatcher,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    mojom::URLLoaderFactory* url_loader_factory,
+    mojom::KeepAliveHandlePtr keep_alive_handle)
     : context_(new Context(this,
                            resource_dispatcher,
                            std::move(task_runner),
-                           url_loader_factory)) {}
+                           url_loader_factory,
+                           std::move(keep_alive_handle))) {}
 
 WebURLLoaderImpl::~WebURLLoaderImpl() {
   Cancel();
diff --git a/content/child/web_url_loader_impl.h b/content/child/web_url_loader_impl.h
index f127b7b..35c5d713 100644
--- a/content/child/web_url_loader_impl.h
+++ b/content/child/web_url_loader_impl.h
@@ -5,10 +5,13 @@
 #ifndef CONTENT_CHILD_WEB_URL_LOADER_IMPL_H_
 #define CONTENT_CHILD_WEB_URL_LOADER_IMPL_H_
 
+#include <vector>
+
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
+#include "content/common/frame.mojom.h"
 #include "content/public/common/resource_response.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "mojo/public/cpp/system/data_pipe.h"
@@ -54,6 +57,12 @@
   WebURLLoaderImpl(ResourceDispatcher* resource_dispatcher,
                    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
                    mojom::URLLoaderFactory* url_loader_factory);
+  // When non-null |keep_alive_handle| is specified, this loader prolongs
+  // this render process's lifetime.
+  WebURLLoaderImpl(ResourceDispatcher* resource_dispatcher,
+                   scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                   mojom::URLLoaderFactory* url_loader_factory,
+                   mojom::KeepAliveHandlePtr keep_alive_handle);
   ~WebURLLoaderImpl() override;
 
   static void PopulateURLResponse(const blink::WebURL& url,
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc
index c456c2b..1cabac2 100644
--- a/content/child/web_url_loader_impl_unittest.cc
+++ b/content/child/web_url_loader_impl_unittest.cc
@@ -130,12 +130,33 @@
   DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcher);
 };
 
+class FakeURLLoaderFactory final : public mojom::URLLoaderFactory {
+ public:
+  FakeURLLoaderFactory() = default;
+  ~FakeURLLoaderFactory() override = default;
+  void CreateLoaderAndStart(mojom::URLLoaderRequest request,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const ResourceRequest& url_request,
+                            mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override {
+    NOTREACHED();
+  }
+
+  void Clone(mojom::URLLoaderFactoryRequest request) override { NOTREACHED(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeURLLoaderFactory);
+};
+
 class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
  public:
   TestWebURLLoaderClient(ResourceDispatcher* dispatcher)
       : loader_(new WebURLLoaderImpl(dispatcher,
                                      base::ThreadTaskRunnerHandle::Get(),
-                                     nullptr)),
+                                     &fake_url_loader_factory_)),
         delete_on_receive_redirect_(false),
         delete_on_receive_response_(false),
         delete_on_receive_data_(false),
@@ -244,6 +265,7 @@
   const blink::WebURLResponse& response() const { return response_; }
 
  private:
+  FakeURLLoaderFactory fake_url_loader_factory_;
   std::unique_ptr<WebURLLoaderImpl> loader_;
 
   bool delete_on_receive_redirect_;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index f8ad84c3..68ee4b7 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -320,6 +320,8 @@
     "service_worker/embedded_worker_start_params.h",
     "service_worker/service_worker_client_info.cc",
     "service_worker/service_worker_client_info.h",
+    "service_worker/service_worker_loader_helpers.cc",
+    "service_worker/service_worker_loader_helpers.h",
     "service_worker/service_worker_messages.h",
     "service_worker/service_worker_provider_host_info.cc",
     "service_worker/service_worker_provider_host_info.h",
diff --git a/content/common/DEPS b/content/common/DEPS
index fcc5c03..3f90093 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -65,6 +65,7 @@
   "+third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerState.h",
   "+third_party/WebKit/public/platform/modules/serviceworker/service_worker_error_type.mojom.h",
   "+third_party/WebKit/public/platform/modules/serviceworker/service_worker_event_status.mojom.h",
+  "+third_party/WebKit/public/platform/modules/serviceworker/service_worker_stream_handle.mojom.h",
   "+third_party/WebKit/public/web/WebAXEnums.h",
   "+third_party/WebKit/public/web/WebDeviceEmulationParams.h",
   "+third_party/WebKit/public/web/WebDragStatus.h",
diff --git a/content/common/dom_storage/dom_storage_map.cc b/content/common/dom_storage/dom_storage_map.cc
index 5ac8bd57..0a6b0176a 100644
--- a/content/common/dom_storage/dom_storage_map.cc
+++ b/content/common/dom_storage/dom_storage_map.cc
@@ -19,12 +19,12 @@
   return (key.length() + value.string().length()) * sizeof(base::char16);
 }
 
-size_t size_of_item(const base::string16& key, const size_t value) {
+size_t size_in_storage(const base::string16& key, const size_t value) {
   return key.length() * sizeof(base::char16) + value;
 }
 
-size_t size_of_item(const base::string16& key,
-                    const base::NullableString16& value) {
+size_t size_in_storage(const base::string16& key,
+                       const base::NullableString16& value) {
   // Null value indicates deletion. So, key size is not counted.
   return value.is_null() ? 0 : size_in_memory(key, value);
 }
@@ -34,8 +34,8 @@
 DOMStorageMap::DOMStorageMap(size_t quota) : DOMStorageMap(quota, false) {}
 
 DOMStorageMap::DOMStorageMap(size_t quota, bool has_only_keys)
-    : bytes_used_(0),
-      memory_usage_(0),
+    : storage_used_(0),
+      memory_used_(0),
       quota_(quota),
       has_only_keys_(has_only_keys) {
   ResetKeyIterator();
@@ -74,12 +74,12 @@
     const base::string16& key, const base::string16& value,
     base::NullableString16* old_value) {
   if (has_only_keys_) {
-    size_t unused;
     size_t value_size = value.length() * sizeof(base::char16);
-    return SetItemInternal<KeysMap>(&keys_only_, key, value_size, &unused);
+    return SetItemInternal<KeysMap>(&keys_only_, key, value_size, nullptr);
   } else {
     base::NullableString16 new_value(value, false);
-    *old_value = base::NullableString16();
+    if (old_value)
+      *old_value = base::NullableString16();
     return SetItemInternal<DOMStorageValuesMap>(&keys_values_, key, new_value,
                                                 old_value);
   }
@@ -89,13 +89,12 @@
     const base::string16& key,
     base::string16* old_value) {
   if (has_only_keys_) {
-    size_t unused;
-    return RemoveItemInternal<KeysMap>(&keys_only_, key, &unused);
+    return RemoveItemInternal<KeysMap>(&keys_only_, key, nullptr);
   } else {
     base::NullableString16 nullable_old;
-    bool success = RemoveItemInternal<DOMStorageValuesMap>(&keys_values_, key,
-                                                           &nullable_old);
-    if (success)
+    bool success = RemoveItemInternal<DOMStorageValuesMap>(
+        &keys_values_, key, old_value ? &nullable_old : nullptr);
+    if (success && old_value)
       *old_value = nullable_old.string();
     return success;
   }
@@ -118,22 +117,24 @@
   // Note: A pre-existing file may be over the quota budget.
   DCHECK(!has_only_keys_);
   keys_values_.swap(*values);
-  bytes_used_ = CountBytes(keys_values_);
+  storage_used_ = CountBytes(keys_values_);
+  memory_used_ = storage_used_;
   ResetKeyIterator();
 }
 
-void DOMStorageMap::TakeKeysFrom(const DOMStorageValuesMap* values) {
+void DOMStorageMap::TakeKeysFrom(const DOMStorageValuesMap& values) {
   // Note: A pre-existing file may be over the quota budget.
   DCHECK(has_only_keys_);
   keys_only_.clear();
-  memory_usage_ = 0;
-  for (const auto& item : *values) {
+  memory_used_ = 0;
+  storage_used_ = 0;
+  for (const auto& item : values) {
     keys_only_[item.first] =
         item.second.string().length() * sizeof(base::char16);
     // Do not count size of values for memory usage.
-    memory_usage_ += size_in_memory(item.first, 0 /* unused */);
+    memory_used_ += size_in_memory(item.first, 0 /* unused */);
+    storage_used_ += size_in_storage(item.first, item.second);
   }
-  bytes_used_ = CountBytes(*values);
   ResetKeyIterator();
 }
 
@@ -141,8 +142,8 @@
   DOMStorageMap* copy = new DOMStorageMap(quota_, has_only_keys_);
   copy->keys_values_ = keys_values_;
   copy->keys_only_ = keys_only_;
-  copy->bytes_used_ = bytes_used_;
-  copy->memory_usage_ = memory_usage_;
+  copy->storage_used_ = storage_used_;
+  copy->memory_used_ = memory_used_;
   copy->ResetKeyIterator();
   return copy;
 }
@@ -160,35 +161,36 @@
 
   size_t count = 0;
   for (const auto& pair : values)
-    count += size_of_item(pair.first, pair.second);
+    count += size_in_storage(pair.first, pair.second);
   return count;
 }
 
 template <typename MapType>
 bool DOMStorageMap::SetItemInternal(MapType* map_type,
                                     const base::string16& key,
-                                    typename MapType::mapped_type value,
+                                    const typename MapType::mapped_type& value,
                                     typename MapType::mapped_type* old_value) {
   const auto found = map_type->find(key);
   size_t old_item_size = 0;
   size_t old_item_memory = 0;
   if (found != map_type->end()) {
-    *old_value = found->second;
-    old_item_size = size_of_item(key, *old_value);
-    old_item_memory = size_in_memory(key, *old_value);
+    old_item_size = size_in_storage(key, found->second);
+    old_item_memory = size_in_memory(key, found->second);
+    if (old_value)
+      *old_value = found->second;
   }
-  size_t new_item_size = size_of_item(key, value);
-  size_t new_bytes_used = bytes_used_ - old_item_size + new_item_size;
+  size_t new_item_size = size_in_storage(key, value);
+  size_t new_storage_used = storage_used_ - old_item_size + new_item_size;
 
   // Only check quota if the size is increasing, this allows
   // shrinking changes to pre-existing files that are over budget.
-  if (new_item_size > old_item_size && new_bytes_used > quota_)
+  if (new_item_size > old_item_size && new_storage_used > quota_)
     return false;
 
   (*map_type)[key] = value;
   ResetKeyIterator();
-  bytes_used_ = new_bytes_used;
-  memory_usage_ = memory_usage_ + size_in_memory(key, value) - old_item_memory;
+  storage_used_ = new_storage_used;
+  memory_used_ = memory_used_ + size_in_memory(key, value) - old_item_memory;
   return true;
 }
 
@@ -200,11 +202,12 @@
   const auto found = map_type->find(key);
   if (found == map_type->end())
     return false;
-  *old_value = found->second;
+  storage_used_ -= size_in_storage(key, found->second);
+  memory_used_ -= size_in_memory(key, found->second);
+  if (old_value)
+    *old_value = found->second;
   map_type->erase(found);
   ResetKeyIterator();
-  bytes_used_ -= size_of_item(key, *old_value);
-  memory_usage_ -= size_in_memory(key, *old_value);
   return true;
 }
 
diff --git a/content/common/dom_storage/dom_storage_map.h b/content/common/dom_storage/dom_storage_map.h
index 4ac2190..7c154bc 100644
--- a/content/common/dom_storage/dom_storage_map.h
+++ b/content/common/dom_storage/dom_storage_map.h
@@ -30,9 +30,9 @@
   unsigned Length() const;
   base::NullableString16 Key(unsigned index);
 
-  // Sets and removes items from the storage. |old_value| is only valid if
-  // |has_only_keys| is false. |old_value| is not accessed or modified when
-  // |has_only_keys|.
+  // Sets and removes items from the storage. Old value is wriiten into
+  // |old_value| if it's not null and |has_only_keys| is false. |old_value| is
+  // not accessed or modified when |has_only_keys|.
   bool SetItem(const base::string16& key, const base::string16& value,
                base::NullableString16* old_value);
   bool RemoveItem(const base::string16& key, base::string16* old_value);
@@ -52,14 +52,15 @@
 
   // Stores the keys and sizes of values from |map| to |keys_only_|. Use only
   // when |has_only_keys| is true. This method does not do quota checking.
-  void TakeKeysFrom(const DOMStorageValuesMap* map);
+  void TakeKeysFrom(const DOMStorageValuesMap& map);
 
   // Creates a new instance of DOMStorageMap containing
   // a deep copy of the map.
   DOMStorageMap* DeepCopy() const;
 
-  size_t bytes_used() const { return bytes_used_; }
-  size_t memory_usage() const { return memory_usage_; }
+  const DOMStorageValuesMap& keys_values() const { return keys_values_; }
+  size_t storage_used() const { return storage_used_; }
+  size_t memory_used() const { return memory_used_; }
   size_t quota() const { return quota_; }
   void set_quota(size_t quota) { quota_ = quota; }
   bool has_only_keys() const { return has_only_keys_; }
@@ -77,7 +78,7 @@
   template <typename MapType>
   bool SetItemInternal(MapType* map_type,
                        const base::string16& key,
-                       typename MapType::mapped_type value,
+                       const typename MapType::mapped_type& value,
                        typename MapType::mapped_type* old_value);
   template <typename MapType>
   bool RemoveItemInternal(MapType* map_type,
@@ -94,8 +95,8 @@
   DOMStorageValuesMap::const_iterator keys_values_iterator_;
   KeysMap::const_iterator keys_only_iterator_;
   unsigned last_key_index_;
-  size_t bytes_used_;
-  size_t memory_usage_;
+  size_t storage_used_;
+  size_t memory_used_;
   size_t quota_;
   const bool has_only_keys_;
 };
diff --git a/content/common/dom_storage/dom_storage_map_unittest.cc b/content/common/dom_storage/dom_storage_map_unittest.cc
index 90a51f5..bad1d7d 100644
--- a/content/common/dom_storage/dom_storage_map_unittest.cc
+++ b/content/common/dom_storage/dom_storage_map_unittest.cc
@@ -47,13 +47,13 @@
   EXPECT_TRUE(map->Key(100).is_null());
   if (!has_only_keys)
     EXPECT_TRUE(map->GetItem(kKey).is_null());
-  EXPECT_FALSE(map->RemoveItem(kKey, &old_value));
-  EXPECT_EQ(0u, map->bytes_used());
+  EXPECT_FALSE(map->RemoveItem(kKey, nullptr));
+  EXPECT_EQ(0u, map->storage_used());
   copy = map->DeepCopy();
   EXPECT_EQ(0u, copy->Length());
-  EXPECT_EQ(0u, copy->bytes_used());
+  EXPECT_EQ(0u, copy->storage_used());
   if (has_only_keys)
-    map->TakeKeysFrom(&swap);
+    map->TakeKeysFrom(swap);
   else
     map->SwapValues(&swap);
   EXPECT_TRUE(swap.empty());
@@ -69,25 +69,25 @@
     EXPECT_EQ(kValue, map->GetItem(kKey).string());
     EXPECT_TRUE(map->GetItem(kKey2).is_null());
   }
-  EXPECT_EQ(kItemBytes, map->bytes_used());
+  EXPECT_EQ(kItemBytes, map->storage_used());
   EXPECT_TRUE(map->RemoveItem(kKey, &old_value));
   if (!has_only_keys)
     EXPECT_EQ(kValue, old_value);
   old_value.clear();
-  EXPECT_EQ(0u, map->bytes_used());
+  EXPECT_EQ(0u, map->storage_used());
 
-  EXPECT_TRUE(map->SetItem(kKey, kValue, &old_nullable_value));
-  EXPECT_TRUE(map->SetItem(kKey2, kValue, &old_nullable_value));
-  EXPECT_EQ(kItemBytes + kKey2Bytes + kValueBytes, map->bytes_used());
+  EXPECT_TRUE(map->SetItem(kKey, kValue, nullptr));
+  EXPECT_TRUE(map->SetItem(kKey2, kValue, nullptr));
+  EXPECT_EQ(kItemBytes + kKey2Bytes + kValueBytes, map->storage_used());
   EXPECT_TRUE(map->SetItem(kKey2, kValue2, &old_nullable_value));
   if (!has_only_keys)
     EXPECT_EQ(kValue, old_nullable_value.string());
-  EXPECT_EQ(kItemBytes + kItem2Bytes, map->bytes_used());
+  EXPECT_EQ(kItemBytes + kItem2Bytes, map->storage_used());
   EXPECT_EQ(2u, map->Length());
   EXPECT_EQ(kKey, map->Key(0).string());
   EXPECT_EQ(kKey2, map->Key(1).string());
   EXPECT_EQ(kKey, map->Key(0).string());
-  EXPECT_EQ(kItemBytes + kItem2Bytes, map->bytes_used());
+  EXPECT_EQ(kItemBytes + kItem2Bytes, map->storage_used());
 
   copy = map->DeepCopy();
   EXPECT_EQ(2u, copy->Length());
@@ -98,14 +98,14 @@
   EXPECT_EQ(kKey, copy->Key(0).string());
   EXPECT_EQ(kKey2, copy->Key(1).string());
   EXPECT_TRUE(copy->Key(2).is_null());
-  EXPECT_EQ(kItemBytes + kItem2Bytes, copy->bytes_used());
+  EXPECT_EQ(kItemBytes + kItem2Bytes, copy->storage_used());
 
   if (has_only_keys)
-    map->TakeKeysFrom(&swap);
+    map->TakeKeysFrom(swap);
   else
     map->SwapValues(&swap);
   EXPECT_EQ(0u, map->Length());
-  EXPECT_EQ(0u, map->bytes_used());
+  EXPECT_EQ(0u, map->storage_used());
 }
 
 TEST_P(DOMStorageMapParamTest, EnforcesQuota) {
@@ -122,17 +122,17 @@
   const size_t kQuota = 50;
 
   scoped_refptr<DOMStorageMap> map(new DOMStorageMap(kQuota, has_only_keys));
-  EXPECT_TRUE(map->SetItem(kKey, kValue, &old_nullable_value));
-  EXPECT_FALSE(map->SetItem(kKey2, kValue, &old_nullable_value));
+  EXPECT_TRUE(map->SetItem(kKey, kValue, nullptr));
+  EXPECT_FALSE(map->SetItem(kKey2, kValue, nullptr));
   if (has_only_keys)
     EXPECT_EQ(kValueSize, map->keys_only_[kKey]);
   else
     EXPECT_EQ(kValue, map->keys_values_[kKey].string());
   EXPECT_EQ(1u, map->Length());
 
-  EXPECT_TRUE(map->RemoveItem(kKey, &old_value));
+  EXPECT_TRUE(map->RemoveItem(kKey, nullptr));
   EXPECT_EQ(0u, map->Length());
-  EXPECT_TRUE(map->SetItem(kKey2, kValue, &old_nullable_value));
+  EXPECT_TRUE(map->SetItem(kKey2, kValue, nullptr));
   EXPECT_EQ(1u, map->Length());
 
   // Verify that the TakeKeysFrom method does not do quota checking.
@@ -140,17 +140,16 @@
   swap[kKey] = base::NullableString16(kValue, false);
   swap[kKey2] = base::NullableString16(kValue, false);
   if (has_only_keys)
-    map->TakeKeysFrom(&swap);
+    map->TakeKeysFrom(swap);
   else
     map->SwapValues(&swap);
-  EXPECT_GT(map->bytes_used(), kQuota);
+  EXPECT_GT(map->storage_used(), kQuota);
 
   // When overbudget, a new value of greater size than the existing value can
   // not be set, but a new value of lesser or equal size can be set.
-  EXPECT_TRUE(map->SetItem(kKey, kValue, &old_nullable_value));
-  EXPECT_FALSE(
-      map->SetItem(kKey, base::string16(kValue + kValue), &old_nullable_value));
-  EXPECT_TRUE(map->SetItem(kKey, base::string16(), &old_nullable_value));
+  EXPECT_TRUE(map->SetItem(kKey, kValue, nullptr));
+  EXPECT_FALSE(map->SetItem(kKey, base::string16(kValue + kValue), nullptr));
+  EXPECT_TRUE(map->SetItem(kKey, base::string16(), nullptr));
   if (has_only_keys)
     EXPECT_EQ(0u, map->keys_only_[kKey]);
   else
@@ -171,19 +170,19 @@
   scoped_refptr<DOMStorageMap> map(
       new DOMStorageMap(1024 /* quota */, has_only_keys));
 
-  EXPECT_TRUE(map->SetItem(kKey, kValue, &old_nullable_value));
-  EXPECT_TRUE(map->SetItem(kKey2, kValue, &old_nullable_value));
+  EXPECT_TRUE(map->SetItem(kKey, kValue, nullptr));
+  EXPECT_TRUE(map->SetItem(kKey2, kValue, nullptr));
   if (has_only_keys) {
-    EXPECT_EQ(kKeySize + kKey2Size + 2 * kValueSize, map->memory_usage());
+    EXPECT_EQ(kKeySize + kKey2Size + 2 * kValueSize, map->memory_used());
   } else {
-    EXPECT_EQ(map->bytes_used(), map->memory_usage());
+    EXPECT_EQ(map->storage_used(), map->memory_used());
   }
 
-  EXPECT_TRUE(map->RemoveItem(kKey, &old_value));
+  EXPECT_TRUE(map->RemoveItem(kKey, nullptr));
   if (has_only_keys) {
-    EXPECT_EQ(kKey2Size + kValueSize, map->memory_usage());
+    EXPECT_EQ(kKey2Size + kValueSize, map->memory_used());
   } else {
-    EXPECT_EQ(map->bytes_used(), map->memory_usage());
+    EXPECT_EQ(map->storage_used(), map->memory_used());
   }
 }
 
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 6130377..3cc68cc 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -92,6 +92,10 @@
   int64 cloned_session_storage_namespace_id;
 };
 
+// An opaque handle that keeps alive the associated render process even after
+// the frame is detached. Used by resource requests with "keepalive" specified.
+interface KeepAliveHandle {};
+
 // Implemented by the frame server (i.e. the browser process). For messages that
 // must be associated with the IPC channel.
 interface FrameHost {
@@ -100,4 +104,7 @@
   // be created.
   [Sync] CreateNewWindow(CreateNewWindowParams params)
       => (CreateNewWindowReply reply);
+
+  // Creates and returns a KeepAliveHandle.
+  IssueKeepAliveHandle(KeepAliveHandle& keep_alive_handle);
 };
diff --git a/content/common/media/media_stream.mojom b/content/common/media/media_stream.mojom
index 84238f7..359a0094 100644
--- a/content/common/media/media_stream.mojom
+++ b/content/common/media/media_stream.mojom
@@ -6,12 +6,12 @@
 
 import "url/mojo/origin.mojom";
 
-// TODO(c.padhi): Add typemapping for StreamDeviceInfo,
+// TODO(c.padhi): Add typemapping for MediaStreamDevice,
 // see https://crbug.com/742682.
-// Native struct content::StreamDeviceInfo.
-// (see content/common/media/media_stream_options.h)
+// Native struct content::MediaStreamDevice.
+// (see content/public/common/media_stream_request.h)
 [Native]
-struct StreamDeviceInfo;
+struct MediaStreamDevice;
 
 // Types of media streams (see content/public/common/media_stream_request.h).
 enum MediaStreamType {
@@ -63,8 +63,8 @@
 interface MediaStreamDispatcher {
   // Informs the renderer that browser has generated a stream successfully.
   OnStreamGenerated(int32 request_id, string label,
-                    array<StreamDeviceInfo> audio_array,
-                    array<StreamDeviceInfo> video_array);
+                    array<MediaStreamDevice> audio_devices,
+                    array<MediaStreamDevice> video_devices);
 
   // Informs the renderer that browser has failed to generate a stream.
   OnStreamGenerationFailed(int32 request_id, MediaStreamRequestResult result);
@@ -72,14 +72,14 @@
   // TODO(wjia): should DeviceOpen* methods be merged with
   // StreamGenerat* ones?
   // Informs the renderer that browser has opened a device successfully.
-  OnDeviceOpened(int32 request_id, string label, StreamDeviceInfo device_info);
+  OnDeviceOpened(int32 request_id, string label, MediaStreamDevice device);
 
   // Informs the renderer that browser has failed to open a device.
   OnDeviceOpenFailed(int32 request_id);
 
   // The browser reports that a media device has been stopped. Stopping was
   // triggered from the browser process.
-  OnDeviceStopped(string label, StreamDeviceInfo device_info);
+  OnDeviceStopped(string label, MediaStreamDevice device);
 };
 
 // Per-process browser-side interface that is used by the renderer process to
diff --git a/content/common/media/media_stream.typemap b/content/common/media/media_stream.typemap
index 6b7dc4e..e5c030d 100644
--- a/content/common/media/media_stream.typemap
+++ b/content/common/media/media_stream.typemap
@@ -23,9 +23,9 @@
 ]
 
 type_mappings = [
+  "content.mojom.MediaStreamDevice=content::MediaStreamDevice",
   "content.mojom.MediaStreamRequestResult=content::MediaStreamRequestResult",
   "content.mojom.MediaStreamType=content::MediaStreamType",
   "content.mojom.StreamControls=content::StreamControls",
-  "content.mojom.StreamDeviceInfo=content::StreamDeviceInfo",
   "content.mojom.TrackControls=content::TrackControls",
 ]
diff --git a/content/common/media/media_stream_param_traits.h b/content/common/media/media_stream_param_traits.h
index 190bc2df..dcc50242 100644
--- a/content/common/media/media_stream_param_traits.h
+++ b/content/common/media/media_stream_param_traits.h
@@ -6,7 +6,7 @@
 // Multiply-included message file, hence no include guard.
 
 #include "content/common/content_export.h"
-#include "content/common/media/media_stream_options.h"
+#include "content/public/common/media_stream_request.h"
 #include "ipc/ipc_message_macros.h"
 #include "media/base/ipc/media_param_traits.h"
 #include "media/capture/ipc/capture_param_traits.h"
@@ -20,14 +20,14 @@
 IPC_ENUM_TRAITS_MAX_VALUE(media::VideoFacingMode,
                           media::NUM_MEDIA_VIDEO_FACING_MODES - 1)
 
-IPC_STRUCT_TRAITS_BEGIN(content::StreamDeviceInfo)
-  IPC_STRUCT_TRAITS_MEMBER(device.type)
-  IPC_STRUCT_TRAITS_MEMBER(device.id)
-  IPC_STRUCT_TRAITS_MEMBER(device.video_facing)
-  IPC_STRUCT_TRAITS_MEMBER(device.matched_output_device_id)
-  IPC_STRUCT_TRAITS_MEMBER(device.name)
-  IPC_STRUCT_TRAITS_MEMBER(device.input)
-  IPC_STRUCT_TRAITS_MEMBER(device.matched_output)
-  IPC_STRUCT_TRAITS_MEMBER(device.camera_calibration)
+IPC_STRUCT_TRAITS_BEGIN(content::MediaStreamDevice)
+  IPC_STRUCT_TRAITS_MEMBER(type)
+  IPC_STRUCT_TRAITS_MEMBER(id)
+  IPC_STRUCT_TRAITS_MEMBER(video_facing)
+  IPC_STRUCT_TRAITS_MEMBER(matched_output_device_id)
+  IPC_STRUCT_TRAITS_MEMBER(name)
+  IPC_STRUCT_TRAITS_MEMBER(input)
+  IPC_STRUCT_TRAITS_MEMBER(matched_output)
   IPC_STRUCT_TRAITS_MEMBER(session_id)
+  IPC_STRUCT_TRAITS_MEMBER(camera_calibration)
 IPC_STRUCT_TRAITS_END()
diff --git a/content/common/sandbox_linux/bpf_renderer_policy_linux.cc b/content/common/sandbox_linux/bpf_renderer_policy_linux.cc
index 5f76e35b..c2b7e82 100644
--- a/content/common/sandbox_linux/bpf_renderer_policy_linux.cc
+++ b/content/common/sandbox_linux/bpf_renderer_policy_linux.cc
@@ -100,8 +100,8 @@
     case __NR_sched_setscheduler:
       return sandbox::RestrictSchedTarget(GetPolicyPid(), sysno);
     case __NR_prlimit64:
-      // See crbug.com/662450.
-      return sandbox::RestrictPrlimitToGetrlimit(GetPolicyPid());
+      // See crbug.com/662450 and setrlimit comment above.
+      return sandbox::RestrictPrlimit(GetPolicyPid());
     default:
       // Default on the content baseline policy.
       return SandboxBPFBasePolicy::EvaluateSyscall(sysno);
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc
new file mode 100644
index 0000000..93acc54
--- /dev/null
+++ b/content/common/service_worker/service_worker_loader_helpers.cc
@@ -0,0 +1,87 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/service_worker/service_worker_loader_helpers.h"
+
+#include "base/strings/stringprintf.h"
+#include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/common/resource_request.h"
+#include "content/public/common/resource_response.h"
+#include "net/http/http_util.h"
+
+namespace content {
+
+// static
+std::unique_ptr<ServiceWorkerFetchRequest>
+ServiceWorkerLoaderHelpers::CreateFetchRequest(const ResourceRequest& request) {
+  std::string blob_uuid;
+  uint64_t blob_size = 0;
+  // TODO(kinuko): Implement request.request_body handling.
+  DCHECK(!request.request_body);
+  std::unique_ptr<ServiceWorkerFetchRequest> new_request =
+      base::MakeUnique<ServiceWorkerFetchRequest>();
+  new_request->mode = request.fetch_request_mode;
+  new_request->is_main_resource_load =
+      ServiceWorkerUtils::IsMainResourceType(request.resource_type);
+  new_request->request_context_type = request.fetch_request_context_type;
+  new_request->frame_type = request.fetch_frame_type;
+  new_request->url = request.url;
+  new_request->method = request.method;
+  new_request->blob_uuid = blob_uuid;
+  new_request->blob_size = blob_size;
+  new_request->credentials_mode = request.fetch_credentials_mode;
+  new_request->redirect_mode = request.fetch_redirect_mode;
+  new_request->is_reload = ui::PageTransitionCoreTypeIs(
+      request.transition_type, ui::PAGE_TRANSITION_RELOAD);
+  new_request->referrer =
+      Referrer(GURL(request.referrer), request.referrer_policy);
+  new_request->fetch_type = ServiceWorkerFetchType::FETCH;
+  return new_request;
+}
+
+// static
+void ServiceWorkerLoaderHelpers::SaveResponseHeaders(
+    const int status_code,
+    const std::string& status_text,
+    const ServiceWorkerHeaderMap& headers,
+    ResourceResponseHead* out_head) {
+  // Build a string instead of using HttpResponseHeaders::AddHeader on
+  // each header, since AddHeader has O(n^2) performance.
+  std::string buf(base::StringPrintf("HTTP/1.1 %d %s\r\n", status_code,
+                                     status_text.c_str()));
+  for (const auto& item : headers) {
+    buf.append(item.first);
+    buf.append(": ");
+    buf.append(item.second);
+    buf.append("\r\n");
+  }
+  buf.append("\r\n");
+
+  out_head->headers = new net::HttpResponseHeaders(
+      net::HttpUtil::AssembleRawHeaders(buf.c_str(), buf.size()));
+  if (out_head->mime_type.empty()) {
+    std::string mime_type;
+    out_head->headers->GetMimeType(&mime_type);
+    if (mime_type.empty())
+      mime_type = "text/plain";
+    out_head->mime_type = mime_type;
+  }
+}
+
+// static
+void ServiceWorkerLoaderHelpers::SaveResponseInfo(
+    const ServiceWorkerResponse& response,
+    ResourceResponseHead* out_head) {
+  out_head->was_fetched_via_service_worker = true;
+  out_head->was_fetched_via_foreign_fetch = false;
+  out_head->was_fallback_required_by_service_worker = false;
+  out_head->url_list_via_service_worker = response.url_list;
+  out_head->response_type_via_service_worker = response.response_type;
+  out_head->is_in_cache_storage = response.is_in_cache_storage;
+  out_head->cache_storage_cache_name = response.cache_storage_cache_name;
+  out_head->cors_exposed_header_names = response.cors_exposed_header_names;
+  out_head->did_service_worker_navigation_preload = false;
+}
+
+}  // namespace content
diff --git a/content/common/service_worker/service_worker_loader_helpers.h b/content/common/service_worker/service_worker_loader_helpers.h
new file mode 100644
index 0000000..9ec0a3e
--- /dev/null
+++ b/content/common/service_worker/service_worker_loader_helpers.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
+#define CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
+
+#include "content/common/service_worker/service_worker_types.h"
+
+namespace content {
+
+struct ResourceRequest;
+struct ResourceResponseHead;
+
+// Helper functions for service worker classes that use URLLoader
+//(e.g., ServiceWorkerURLLoaderJob and ServiceWorkerSubresourceLoader).
+class ServiceWorkerLoaderHelpers {
+ public:
+  static std::unique_ptr<ServiceWorkerFetchRequest> CreateFetchRequest(
+      const ResourceRequest& request);
+
+  // Populates |out_head->headers| with the given |status_code|, |status_text|,
+  // and |headers|.
+  static void SaveResponseHeaders(const int status_code,
+                                  const std::string& status_text,
+                                  const ServiceWorkerHeaderMap& headers,
+                                  ResourceResponseHead* out_head);
+  // Populates |out_head| (except for headers) with given |response|.
+  static void SaveResponseInfo(const ServiceWorkerResponse& response,
+                               ResourceResponseHead* out_head);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_SERVICE_WORKER_SERVICE_WORKER_LOADER_HELPERS_H_
diff --git a/content/network/cache_url_loader.cc b/content/network/cache_url_loader.cc
index 129dd202..1ea0622 100644
--- a/content/network/cache_url_loader.cc
+++ b/content/network/cache_url_loader.cc
@@ -61,7 +61,10 @@
         mojo::common::BlockingCopyFromString(data_, data_pipe.producer_handle));
 
     client_->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
-    client_->OnComplete(ResourceRequestCompletionStatus(data_.size()));
+    ResourceRequestCompletionStatus status(net::OK);
+    status.encoded_data_length = data_.size();
+    status.encoded_body_length = data_.size();
+    client_->OnComplete(status);
 
     // So we don't delete |this| in the constructor.
     base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
diff --git a/content/network/cookie_manager_impl_unittest.cc b/content/network/cookie_manager_impl_unittest.cc
index 596243c..a019e269 100644
--- a/content/network/cookie_manager_impl_unittest.cc
+++ b/content/network/cookie_manager_impl_unittest.cc
@@ -152,34 +152,36 @@
     // Set a couple of cookies for tests to play with.
     bool result;
     result = SetCanonicalCookie(
-        net::CanonicalCookie("A", "B", "foo_host", "/", base::Time(),
-                             base::Time(), base::Time(), false, false,
-                             net::CookieSameSite::NO_RESTRICTION,
-                             net::COOKIE_PRIORITY_MEDIUM),
+        net::CanonicalCookie(
+            "A", "B", "foo_host", "/", base::Time(), base::Time(), base::Time(),
+            /*secure=*/false, /*httponly=*/false,
+            net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
         true, true);
     DCHECK(result);
 
     result = SetCanonicalCookie(
-        net::CanonicalCookie("C", "D", "foo_host2", "/with/path", base::Time(),
-                             base::Time(), base::Time(), false, false,
-                             net::CookieSameSite::NO_RESTRICTION,
-                             net::COOKIE_PRIORITY_MEDIUM),
+        net::CanonicalCookie(
+            "C", "D", "foo_host2", "/with/path", base::Time(), base::Time(),
+            base::Time(), /*secure=*/false, /*httponly=*/false,
+            net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
         true, true);
     DCHECK(result);
 
     result = SetCanonicalCookie(
-        net::CanonicalCookie("Secure", "E", "foo_host", "/with/path",
-                             base::Time(), base::Time(), base::Time(), true,
-                             false, net::CookieSameSite::NO_RESTRICTION,
-                             net::COOKIE_PRIORITY_MEDIUM),
+        net::CanonicalCookie(
+            "Secure", "E", "foo_host", "/with/path", base::Time(), base::Time(),
+            base::Time(), /*secure=*/true,
+            /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+            net::COOKIE_PRIORITY_MEDIUM),
         true, true);
     DCHECK(result);
 
     result = SetCanonicalCookie(
-        net::CanonicalCookie("HttpOnly", "F", "foo_host", "/with/path",
-                             base::Time(), base::Time(), base::Time(), false,
-                             true, net::CookieSameSite::NO_RESTRICTION,
-                             net::COOKIE_PRIORITY_MEDIUM),
+        net::CanonicalCookie(
+            "HttpOnly", "F", "foo_host", "/with/path", base::Time(),
+            base::Time(), base::Time(), /*secure=*/false,
+            /*httponly=*/true, net::CookieSameSite::NO_RESTRICTION,
+            net::COOKIE_PRIORITY_MEDIUM),
         true, true);
     DCHECK(result);
   }
@@ -319,12 +321,149 @@
   EXPECT_EQ("E", cookies[1].Value());
 }
 
+TEST_F(CookieManagerImplTest, GetCookieListHttpOnly) {
+  // Clean out the cookies.
+  mojom::CookieDeletionFilter filter;
+  EXPECT_EQ(4u, service_wrapper()->DeleteCookies(filter));
+
+  // Create an httponly and a non-httponly cookie.
+  bool result;
+  result = SetCanonicalCookie(
+      net::CanonicalCookie(
+          "A", "B", "foo_host", "/", base::Time(), base::Time(), base::Time(),
+          /*secure=*/false, /*httponly=*/true,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+      true, true);
+  ASSERT_TRUE(result);
+  result = SetCanonicalCookie(
+      net::CanonicalCookie(
+          "C", "D", "foo_host", "/", base::Time(), base::Time(), base::Time(),
+          /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+      true, true);
+  ASSERT_TRUE(result);
+
+  // Retrieve without httponly cookies (default)
+  net::CookieOptions options;
+  EXPECT_TRUE(options.exclude_httponly());
+  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host/with/path"), options);
+  EXPECT_EQ(1u, cookies.size());
+  EXPECT_EQ("C", cookies[0].Name());
+
+  // Retrieve with httponly cookies.
+  options.set_include_httponly();
+  cookies = service_wrapper()->GetCookieList(GURL("https://foo_host/with/path"),
+                                             options);
+  EXPECT_EQ(2u, cookies.size());
+  std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
+
+  EXPECT_EQ("A", cookies[0].Name());
+  EXPECT_EQ("C", cookies[1].Name());
+}
+
+TEST_F(CookieManagerImplTest, GetCookieListSameSite) {
+  // Clean out the cookies.
+  mojom::CookieDeletionFilter filter;
+  EXPECT_EQ(4u, service_wrapper()->DeleteCookies(filter));
+
+  // Create an unrestricted, a lax, and a strict cookie.
+  bool result;
+  result = SetCanonicalCookie(
+      net::CanonicalCookie(
+          "A", "B", "foo_host", "/", base::Time(), base::Time(), base::Time(),
+          /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+      true, true);
+  ASSERT_TRUE(result);
+  result = SetCanonicalCookie(
+      net::CanonicalCookie("C", "D", "foo_host", "/", base::Time(),
+                           base::Time(), base::Time(), /*secure=*/false,
+                           /*httponly=*/false, net::CookieSameSite::LAX_MODE,
+                           net::COOKIE_PRIORITY_MEDIUM),
+      true, true);
+  ASSERT_TRUE(result);
+  result = SetCanonicalCookie(
+      net::CanonicalCookie("E", "F", "foo_host", "/", base::Time(),
+                           base::Time(), base::Time(), /*secure=*/false,
+                           /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
+                           net::COOKIE_PRIORITY_MEDIUM),
+      true, true);
+  ASSERT_TRUE(result);
+
+  // Retrieve only unrestricted cookies.
+  net::CookieOptions options;
+  EXPECT_EQ(net::CookieOptions::SameSiteCookieMode::DO_NOT_INCLUDE,
+            options.same_site_cookie_mode());
+  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host/with/path"), options);
+  EXPECT_EQ(1u, cookies.size());
+  EXPECT_EQ("A", cookies[0].Name());
+
+  // Retrieve unrestricted and lax cookies.
+  options.set_same_site_cookie_mode(
+      net::CookieOptions::SameSiteCookieMode::INCLUDE_LAX);
+  cookies = service_wrapper()->GetCookieList(GURL("https://foo_host/with/path"),
+                                             options);
+  EXPECT_EQ(2u, cookies.size());
+  std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
+  EXPECT_EQ("A", cookies[0].Name());
+  EXPECT_EQ("C", cookies[1].Name());
+
+  // Retrieve everything.
+  options.set_same_site_cookie_mode(
+      net::CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
+  cookies = service_wrapper()->GetCookieList(GURL("https://foo_host/with/path"),
+                                             options);
+  EXPECT_EQ(3u, cookies.size());
+  std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
+  EXPECT_EQ("A", cookies[0].Name());
+  EXPECT_EQ("C", cookies[1].Name());
+  EXPECT_EQ("E", cookies[2].Name());
+}
+
+TEST_F(CookieManagerImplTest, GetCookieListAccessTime) {
+  // Clean out the cookies and set a new, clean cookie.
+  mojom::CookieDeletionFilter filter;
+  EXPECT_EQ(4u, service_wrapper()->DeleteCookies(filter));
+  bool result;
+  result = SetCanonicalCookie(
+      net::CanonicalCookie(
+          "A", "B", "foo_host", "/", base::Time(), base::Time(), base::Time(),
+          /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+      true, true);
+  ASSERT_TRUE(result);
+
+  // Get the cookie without updating the access time and check
+  // the access time is null.
+  net::CookieOptions options;
+  options.set_do_not_update_access_time();
+  std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
+      GURL("https://foo_host/with/path"), options);
+  ASSERT_EQ(1u, cookies.size());
+  EXPECT_EQ("A", cookies[0].Name());
+  EXPECT_TRUE(cookies[0].LastAccessDate().is_null());
+
+  // Get the cookie updating the access time and check
+  // that it's a valid value.
+  base::Time start(base::Time::Now());
+  options.set_update_access_time();
+  cookies = service_wrapper()->GetCookieList(GURL("https://foo_host/with/path"),
+                                             options);
+  ASSERT_EQ(1u, cookies.size());
+  EXPECT_EQ("A", cookies[0].Name());
+  EXPECT_FALSE(cookies[0].LastAccessDate().is_null());
+  EXPECT_GE(cookies[0].LastAccessDate(), start);
+  EXPECT_LE(cookies[0].LastAccessDate(), base::Time::Now());
+}
+
 TEST_F(CookieManagerImplTest, SetExtraCookie) {
   EXPECT_TRUE(service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie("X", "Y", "new_host", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "X", "Y", "new_host", "/", base::Time(), base::Time(), base::Time(),
+          /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       false, false));
 
   std::vector<net::CanonicalCookie> cookies =
@@ -353,7 +492,7 @@
   base::Time yesterday = base::Time::Now() - base::TimeDelta::FromDays(1);
   EXPECT_TRUE(service_wrapper()->SetCanonicalCookie(
       net::CanonicalCookie("A", "E", "foo_host", "/", base::Time(), yesterday,
-                           base::Time(), false, false,
+                           base::Time(), /*secure=*/false, /*httponly=*/false,
                            net::CookieSameSite::NO_RESTRICTION,
                            net::COOKIE_PRIORITY_MEDIUM),
       false, false));
@@ -376,10 +515,10 @@
 
 TEST_F(CookieManagerImplTest, ConfirmSecureSetFails) {
   EXPECT_FALSE(service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie("N", "O", "foo_host", "/", base::Time(),
-                           base::Time(), base::Time(), true, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "N", "O", "foo_host", "/", base::Time(), base::Time(), base::Time(),
+          /*secure=*/true, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       false, false));
   std::vector<net::CanonicalCookie> cookies =
       service_wrapper()->GetAllCookies();
@@ -389,10 +528,10 @@
 
 TEST_F(CookieManagerImplTest, ConfirmHttpOnlySetFails) {
   EXPECT_FALSE(service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie("N", "O", "foo_host", "/", base::Time(),
-                           base::Time(), base::Time(), false, true,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "N", "O", "foo_host", "/", base::Time(), base::Time(), base::Time(),
+          /*secure=*/false, /*httponly=*/true,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       false, false));
   std::vector<net::CanonicalCookie> cookies =
       service_wrapper()->GetAllCookies();
@@ -402,10 +541,11 @@
 
 TEST_F(CookieManagerImplTest, ConfirmHttpOnlyOverwriteFails) {
   EXPECT_FALSE(service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie("HttpOnly", "Nope", "foo_host", "/with/path",
-                           base::Time(), base::Time(), base::Time(), false,
-                           true, net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "HttpOnly", "Nope", "foo_host", "/with/path", base::Time(),
+          base::Time(), base::Time(), /*secure=*/false,
+          /*httponly=*/true, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       false, false));
 
   std::vector<net::CanonicalCookie> cookies =
@@ -434,21 +574,21 @@
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A1", "val", "foo_host", "/", now - base::TimeDelta::FromMinutes(60),
-          base::Time(), base::Time(), false, false,
+          base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
           net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A2", "val", "foo_host", "/", now - base::TimeDelta::FromMinutes(120),
-          base::Time(), base::Time(), false, false,
+          base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
           net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A3", "val", "foo_host", "/", now - base::TimeDelta::FromMinutes(180),
-          base::Time(), base::Time(), false, false,
+          base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
           net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
@@ -469,24 +609,24 @@
 
   // Create three cookies and delete the middle one.
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A1", "val", "foo_host1", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A1", "val", "foo_host1", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A2", "val", "foo_host2", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A2", "val", "foo_host2", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A3", "val", "foo_host3", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A3", "val", "foo_host3", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   filter.excluding_domains = std::vector<std::string>();
@@ -506,24 +646,24 @@
 
   // Create three cookies and delete the middle one.
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A1", "val", "foo_host1", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A1", "val", "foo_host1", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A2", "val", "foo_host2", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A2", "val", "foo_host2", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A3", "val", "foo_host3", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A3", "val", "foo_host3", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   filter.including_domains = std::vector<std::string>();
@@ -545,24 +685,25 @@
 
   // Create three cookies and delete the middle one.
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A1", "val", "foo_host", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A1", "val", "foo_host", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie("A2", "val", "foo_host", "/", base::Time(),
                            now + base::TimeDelta::FromDays(1), base::Time(),
-                           false, false, net::CookieSameSite::NO_RESTRICTION,
+                           /*secure=*/false, /*httponly=*/false,
+                           net::CookieSameSite::NO_RESTRICTION,
                            net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   EXPECT_TRUE(SetCanonicalCookie(
-      net::CanonicalCookie("A3", "val", "foo_host", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "A3", "val", "foo_host", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   filter.session_control =
@@ -608,47 +749,52 @@
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A1", "val", "nope.com", "/", now - base::TimeDelta::FromDays(3),
-          now + base::TimeDelta::FromDays(3), base::Time(), false, false,
-          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+          now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   // Too old cookie.
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A2", "val", "nope.com", "/", now - base::TimeDelta::FromDays(5),
-          now + base::TimeDelta::FromDays(3), base::Time(), false, false,
-          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+          now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   // Too young cookie.
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A3", "val", "nope.com", "/", now - base::TimeDelta::FromDays(1),
-          now + base::TimeDelta::FromDays(3), base::Time(), false, false,
-          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+          now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   // Not in including_domains.
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A4", "val", "other.com", "/", now - base::TimeDelta::FromDays(3),
-          now + base::TimeDelta::FromDays(3), base::Time(), false, false,
-          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+          now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   // In excluding_domains.
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A5", "val", "no.com", "/", now - base::TimeDelta::FromDays(3),
-          now + base::TimeDelta::FromDays(3), base::Time(), false, false,
-          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
+          now + base::TimeDelta::FromDays(3), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   // Session
   EXPECT_TRUE(SetCanonicalCookie(
       net::CanonicalCookie(
           "A6", "val", "nope.com", "/", now - base::TimeDelta::FromDays(3),
-          base::Time(), base::Time(), false, false,
+          base::Time(), base::Time(), /*secure=*/false, /*httponly=*/false,
           net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
@@ -732,10 +878,11 @@
   // Set a cookie that doesn't match the above notification request in name
   // and confirm it doesn't produce a notification.
   service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie("DifferentName", "val", notification_url.host(), "/",
-                           base::Time(), base::Time(), base::Time(), false,
-                           false, net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "DifferentName", "val", notification_url.host(), "/", base::Time(),
+          base::Time(), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true);
   base::RunLoop().RunUntilIdle();
   notification_impl.GetCurrentNotifications(&notifications);
@@ -745,10 +892,11 @@
   // Set a cookie that doesn't match the above notification request in url
   // and confirm it doesn't produce a notification.
   service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie(notification_name, "val", "www.other.host", "/",
-                           base::Time(), base::Time(), base::Time(), false,
-                           false, net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          notification_name, "val", "www.other.host", "/", base::Time(),
+          base::Time(), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true);
 
   base::RunLoop().RunUntilIdle();
@@ -758,10 +906,11 @@
 
   // Insert a cookie that does match.
   service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie(notification_name, "val", notification_url.host(),
-                           "/", base::Time(), base::Time(), base::Time(), false,
-                           false, net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          notification_name, "val", notification_url.host(), "/", base::Time(),
+          base::Time(), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true);
 
   // Expect asynchrony
@@ -818,10 +967,11 @@
 
   // Add a cookie and receive a notification on both interfaces.
   service_wrapper()->SetCanonicalCookie(
-      net::CanonicalCookie(notification_name, "val", notification_url.host(),
-                           "/", base::Time(), base::Time(), base::Time(), false,
-                           false, net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          notification_name, "val", notification_url.host(), "/", base::Time(),
+          base::Time(), base::Time(), /*secure=*/false,
+          /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
+          net::COOKIE_PRIORITY_MEDIUM),
       true, true);
 
   std::vector<CookieChangeNotificationImpl::Notification> notifications;
@@ -880,10 +1030,10 @@
   // Set a cookie on the new interface and make sure it's visible on the
   // old one.
   EXPECT_TRUE(new_wrapper.SetCanonicalCookie(
-      net::CanonicalCookie("X", "Y", "www.other.host", "/", base::Time(),
-                           base::Time(), base::Time(), false, false,
-                           net::CookieSameSite::NO_RESTRICTION,
-                           net::COOKIE_PRIORITY_MEDIUM),
+      net::CanonicalCookie(
+          "X", "Y", "www.other.host", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/false, /*httponly=*/false,
+          net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_MEDIUM),
       true, true));
 
   std::vector<net::CanonicalCookie> cookies = service_wrapper()->GetCookieList(
diff --git a/content/network/network_context.cc b/content/network/network_context.cc
index c2198b1..7135e42 100644
--- a/content/network/network_context.cc
+++ b/content/network/network_context.cc
@@ -5,9 +5,13 @@
 #include "content/network/network_context.h"
 
 #include "base/command_line.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
 #include "components/network_session_configurator/browser/network_session_configurator.h"
 #include "components/network_session_configurator/common/network_switches.h"
@@ -143,6 +147,11 @@
     : network_service_(network_service),
       params_(std::move(params)),
       binding_(this, std::move(request)) {
+  if (params_ && params_->http_cache_path) {
+    // Only sample 0.1% of NetworkContexts that get created.
+    if (base::RandUint64() % 1000 == 0)
+      disk_checker_ = base::MakeUnique<DiskChecker>(*params_->http_cache_path);
+  }
   network_service_->RegisterNetworkContext(this);
   ApplyContextParamsToBuilder(builder.get(), params_.get(), network_service);
   owned_url_request_context_ = builder->Build();
@@ -230,4 +239,28 @@
     delete this;
 }
 
+NetworkContext::DiskChecker::DiskChecker(const base::FilePath& cache_path)
+    : cache_path_(cache_path) {
+  timer_.Start(FROM_HERE, base::TimeDelta::FromHours(24),
+               base::Bind(&DiskChecker::CheckDiskSize, base::Unretained(this)));
+
+  // Check disk size at startup, hopefully before the HTTPCache has been cleared
+  // from the previous run.
+  CheckDiskSize();
+}
+
+void NetworkContext::DiskChecker::CheckDiskSize() {
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+      base::Bind(&DiskChecker::CheckDiskSizeOnBackgroundThread, cache_path_));
+}
+
+void NetworkContext::DiskChecker::CheckDiskSizeOnBackgroundThread(
+    const base::FilePath& cache_path) {
+  int64_t size = base::ComputeDirectorySize(cache_path);
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Net.DiskCache.Size", size / 1024 / 1024);
+}
+
+NetworkContext::DiskChecker::~DiskChecker() = default;
+
 }  // namespace content
diff --git a/content/network/network_context.h b/content/network/network_context.h
index 66aeda8..d93be78 100644
--- a/content/network/network_context.h
+++ b/content/network/network_context.h
@@ -11,6 +11,7 @@
 #include <set>
 
 #include "base/macros.h"
+#include "base/timer/timer.h"
 #include "content/common/content_export.h"
 #include "content/network/cookie_manager_impl.h"
 #include "content/public/common/network_service.mojom.h"
@@ -66,6 +67,8 @@
 
   net::URLRequestContext* url_request_context() { return url_request_context_; }
 
+  NetworkServiceImpl* network_service() { return network_service_; }
+
   // These are called by individual url loaders as they are being created and
   // destroyed.
   void RegisterURLLoader(URLLoaderImpl* url_loader);
@@ -115,6 +118,24 @@
 
   std::unique_ptr<CookieManagerImpl> cookie_manager_;
 
+  // Temporary class to help diagnose the impact of https://crbug.com/711579.
+  // Every 24-hours, measures the size of the network cache and emits an UMA
+  // metric.
+  class DiskChecker {
+   public:
+    explicit DiskChecker(const base::FilePath& cache_path);
+    ~DiskChecker();
+
+   private:
+    void CheckDiskSize();
+    static void CheckDiskSizeOnBackgroundThread(
+        const base::FilePath& cache_path);
+    base::RepeatingTimer timer_;
+    base::FilePath cache_path_;
+    DISALLOW_COPY_AND_ASSIGN(DiskChecker);
+  };
+  std::unique_ptr<DiskChecker> disk_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(NetworkContext);
 };
 
diff --git a/content/network/network_service_impl.cc b/content/network/network_service_impl.cc
index 01890e7..02ace04 100644
--- a/content/network/network_service_impl.cc
+++ b/content/network/network_service_impl.cc
@@ -126,6 +126,22 @@
   }
 }
 
+void NetworkServiceImpl::SetRawHeadersAccess(uint32_t process_id, bool allow) {
+  DCHECK(process_id);
+  if (allow)
+    processes_with_raw_headers_access_.insert(process_id);
+  else
+    processes_with_raw_headers_access_.erase(process_id);
+}
+
+bool NetworkServiceImpl::HasRawHeadersAccess(uint32_t process_id) const {
+  // Allow raw headers for browser-initiated requests.
+  if (!process_id)
+    return true;
+  return processes_with_raw_headers_access_.find(process_id) !=
+         processes_with_raw_headers_access_.end();
+}
+
 void NetworkServiceImpl::OnBindInterface(
     const service_manager::BindSourceInfo& source_info,
     const std::string& interface_name,
diff --git a/content/network/network_service_impl.h b/content/network/network_service_impl.h
index 7ec0ef5..78f6ea9 100644
--- a/content/network/network_service_impl.h
+++ b/content/network/network_service_impl.h
@@ -49,8 +49,10 @@
   void CreateNetworkContext(mojom::NetworkContextRequest request,
                             mojom::NetworkContextParamsPtr params) override;
   void DisableQuic() override;
+  void SetRawHeadersAccess(uint32_t process_id, bool allow) override;
 
   bool quic_disabled() const { return quic_disabled_; }
+  bool HasRawHeadersAccess(uint32_t process_id) const;
 
  private:
   class MojoNetLog;
@@ -75,6 +77,7 @@
   // NetworkContexts share global state with the NetworkService, so must be
   // destroyed first.
   std::set<NetworkContext*> network_contexts_;
+  std::set<uint32_t> processes_with_raw_headers_access_;
 
   bool quic_disabled_ = false;
 
diff --git a/content/network/network_service_unittest.cc b/content/network/network_service_unittest.cc
index a7043c6d..ce367d6 100644
--- a/content/network/network_service_unittest.cc
+++ b/content/network/network_service_unittest.cc
@@ -129,31 +129,30 @@
     request.url = url;
     request.method = "GET";
     request.request_initiator = url::Origin();
-    StartLoadingURL(request);
-    client_.RunUntilComplete();
+    StartLoadingURL(request, 0);
+    client_->RunUntilComplete();
   }
 
-  void StartLoadingURL(const ResourceRequest& request) {
-    mojom::NetworkServicePtr network_service;
-    connector()->BindInterface(mojom::kNetworkServiceName, &network_service);
-
+  void StartLoadingURL(const ResourceRequest& request, uint32_t process_id) {
+    client_.reset(new TestURLLoaderClient());
     mojom::NetworkContextParamsPtr context_params =
         mojom::NetworkContextParams::New();
-    network_service->CreateNetworkContext(mojo::MakeRequest(&network_context_),
-                                          std::move(context_params));
+    network_service_->CreateNetworkContext(mojo::MakeRequest(&network_context_),
+                                           std::move(context_params));
     mojom::URLLoaderFactoryPtr loader_factory;
     network_context_->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory),
-                                             0);
+                                             process_id);
 
     loader_factory->CreateLoaderAndStart(
         mojo::MakeRequest(&loader_), 1, 1, mojom::kURLLoadOptionNone, request,
-        client_.CreateInterfacePtr(),
+        client_->CreateInterfacePtr(),
         net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
   }
 
   net::EmbeddedTestServer* test_server() { return &test_server_; }
-  TestURLLoaderClient* client() { return &client_; }
+  TestURLLoaderClient* client() { return client_.get(); }
   mojom::URLLoader* loader() { return loader_.get(); }
+  mojom::NetworkService* service() { return network_service_.get(); }
 
  private:
   std::unique_ptr<service_manager::Service> CreateService() override {
@@ -165,10 +164,12 @@
     test_server_.AddDefaultHandlers(content_test_data);
     ASSERT_TRUE(test_server_.Start());
     service_manager::test::ServiceTest::SetUp();
+    connector()->BindInterface(mojom::kNetworkServiceName, &network_service_);
   }
 
   net::EmbeddedTestServer test_server_;
-  TestURLLoaderClient client_;
+  std::unique_ptr<TestURLLoaderClient> client_;
+  mojom::NetworkServicePtr network_service_;
   mojom::NetworkContextPtr network_context_;
   mojom::URLLoaderPtr loader_;
 
@@ -188,7 +189,7 @@
   request.url = test_server()->GetURL("/server-redirect?/echo");
   request.method = "GET";
   request.request_initiator = url::Origin();
-  StartLoadingURL(request);
+  StartLoadingURL(request, 0);
   client()->RunUntilRedirectReceived();
   EXPECT_TRUE(client()->has_received_redirect());
   EXPECT_TRUE(!client()->response_head().devtools_info);
@@ -203,7 +204,7 @@
   request.method = "GET";
   request.report_raw_headers = true;
   request.request_initiator = url::Origin();
-  StartLoadingURL(request);
+  StartLoadingURL(request, 0);
   client()->RunUntilRedirectReceived();
   EXPECT_TRUE(client()->has_received_redirect());
   {
@@ -239,6 +240,34 @@
   }
 }
 
+TEST_F(NetworkServiceTestWithService, RawRequestAccessControl) {
+  const uint32_t process_id = 42;
+  ResourceRequest request;
+  request.url = test_server()->GetURL("/nocache.html");
+  request.method = "GET";
+  request.report_raw_headers = true;
+  request.request_initiator = url::Origin();
+
+  StartLoadingURL(request, process_id);
+  client()->RunUntilComplete();
+  EXPECT_FALSE(client()->response_head().devtools_info);
+  service()->SetRawHeadersAccess(process_id, true);
+  StartLoadingURL(request, process_id);
+  client()->RunUntilComplete();
+  {
+    scoped_refptr<ResourceDevToolsInfo> devtools_info =
+        client()->response_head().devtools_info;
+    ASSERT_TRUE(devtools_info);
+    EXPECT_EQ(200, devtools_info->http_status_code);
+    EXPECT_EQ("OK", devtools_info->http_status_text);
+  }
+
+  service()->SetRawHeadersAccess(process_id, false);
+  StartLoadingURL(request, process_id);
+  client()->RunUntilComplete();
+  EXPECT_FALSE(client()->response_head().devtools_info.get());
+}
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/network/network_service_url_loader_factory_impl.cc b/content/network/network_service_url_loader_factory_impl.cc
index 7624b6c..16d7ff9 100644
--- a/content/network/network_service_url_loader_factory_impl.cc
+++ b/content/network/network_service_url_loader_factory_impl.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "content/network/network_context.h"
+#include "content/network/network_service_impl.h"
 #include "content/network/url_loader_impl.h"
 #include "content/public/common/resource_request.h"
 
@@ -29,8 +30,16 @@
     const ResourceRequest& url_request,
     mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+  bool report_raw_headers = false;
+  if (url_request.report_raw_headers) {
+    const NetworkServiceImpl* service = context_->network_service();
+    report_raw_headers = service && service->HasRawHeadersAccess(process_id_);
+    if (!report_raw_headers)
+      DLOG(ERROR) << "Denying raw headers request by process " << process_id_;
+  }
   new URLLoaderImpl(
-      context_, std::move(request), options, url_request, std::move(client),
+      context_, std::move(request), options, url_request, report_raw_headers,
+      std::move(client),
       static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation));
 }
 
diff --git a/content/network/url_loader_impl.cc b/content/network/url_loader_impl.cc
index c6f6a6cf..942a88ec 100644
--- a/content/network/url_loader_impl.cc
+++ b/content/network/url_loader_impl.cc
@@ -163,6 +163,7 @@
     mojom::URLLoaderRequest url_loader_request,
     int32_t options,
     const ResourceRequest& request,
+    bool report_raw_headers,
     mojom::URLLoaderClientPtr url_loader_client,
     const net::NetworkTrafficAnnotationTag& traffic_annotation)
     : context_(context),
@@ -174,11 +175,8 @@
                                mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       peer_closed_handle_watcher_(FROM_HERE,
                                   mojo::SimpleWatcher::ArmingPolicy::MANUAL),
-      report_raw_headers_(false),
+      report_raw_headers_(report_raw_headers),
       weak_ptr_factory_(this) {
-  // TODO(caseq): Make sure the client renderer actually has premissions to
-  // get raw headers (i.e. has DevTools attached).
-  report_raw_headers_ = request.report_raw_headers;
   context_->RegisterURLLoader(this);
   binding_.set_connection_error_handler(base::BindOnce(
       &URLLoaderImpl::OnConnectionError, base::Unretained(this)));
diff --git a/content/network/url_loader_impl.h b/content/network/url_loader_impl.h
index c4e0bc5..9b01b32 100644
--- a/content/network/url_loader_impl.h
+++ b/content/network/url_loader_impl.h
@@ -39,6 +39,7 @@
                 mojom::URLLoaderRequest url_loader_request,
                 int32_t options,
                 const ResourceRequest& request,
+                bool report_raw_headers,
                 mojom::URLLoaderClientPtr url_loader_client,
                 const net::NetworkTrafficAnnotationTag& traffic_annotation);
   ~URLLoaderImpl() override;
diff --git a/content/network/url_loader_unittest.cc b/content/network/url_loader_unittest.cc
index 0e4aa6d..e855505d 100644
--- a/content/network/url_loader_unittest.cc
+++ b/content/network/url_loader_unittest.cc
@@ -164,7 +164,7 @@
       options |= mojom::kURLLoadOptionSniffMimeType;
 
     URLLoaderImpl loader_impl(context(), mojo::MakeRequest(&loader), options,
-                              request, client_.CreateInterfacePtr(),
+                              request, false, client_.CreateInterfacePtr(),
                               TRAFFIC_ANNOTATION_FOR_TESTS);
 
     client_.RunUntilComplete();
@@ -375,7 +375,7 @@
   // don't hold on to a pointer to it.
   base::WeakPtr<URLLoaderImpl> loader_impl =
       (new URLLoaderImpl(context(), mojo::MakeRequest(&loader), 0, request,
-                         client()->CreateInterfacePtr(),
+                         false, client()->CreateInterfacePtr(),
                          TRAFFIC_ANNOTATION_FOR_TESTS))
           ->GetWeakPtrForTests();
 
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 8d00be85..43676ef 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/android/config.gni")
 import("//build/config/android/rules.gni")
+import("//device/vr/features/features.gni")
 
 android_aidl("common_aidl") {
   interface_file = "java/src/org/chromium/content/common/common.aidl"
@@ -63,6 +64,10 @@
     "//ui/gfx/geometry/mojo:mojo_java",
   ]
 
+  if (enable_vr) {
+    deps += [ "//device/vr:java" ]
+  }
+
   srcjar_deps = [
     ":common_aidl",
     ":is_ready_to_pay_service_aidl",
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/OWNERS b/content/public/android/java/src/org/chromium/content/browser/accessibility/OWNERS
index c30be28..ef109d4 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/OWNERS
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/OWNERS
@@ -1,9 +1,4 @@
-# Preferred revewers for browser accessibility classes.
-dmazzoni@chromium.org
-plundblad@chromium.org
-
-# Preferred reviewer for accessibility injector.
-dtrainor@chromium.org
+file://ui/accessibility/OWNERS
 
 # TEAM: chromium-accessibility@chromium.org
 # COMPONENT: UI>Accessibility
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/OWNERS b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/OWNERS
new file mode 100644
index 0000000..53f1d6e2
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/OWNERS
@@ -0,0 +1,5 @@
+file://content/public/android/java/src/org/chromium/content/browser/accessibility/OWNERS
+
+# TEAM: chromium-accessibility@chromium.org
+# COMPONENT: UI>Accessibility
+# OS: Android
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index dc9c9a3aa..b19955c2 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -350,6 +350,11 @@
   //    - there was an external renderer connected to a shared worker in this
   //      process, and now there is none
   //    - a new worker finished being created in this process.
+  //  - Keepalive request (if the KeepAliveRendererForKeepaliveRequests
+  //    feature is enabled):
+  //    When a fetch request with keepalive flag
+  //    (https://fetch.spec.whatwg.org/#request-keepalive-flag) specified is
+  //    pending, it wishes the renderer process to be kept alive.
   virtual void IncrementKeepAliveRefCount() = 0;
   virtual void DecrementKeepAliveRefCount() = 0;
 
diff --git a/content/public/browser/service_worker_context.h b/content/public/browser/service_worker_context.h
index 1371beb..dd3b3b26 100644
--- a/content/public/browser/service_worker_context.h
+++ b/content/public/browser/service_worker_context.h
@@ -7,6 +7,7 @@
 
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/callback_forward.h"
 #include "content/public/browser/service_worker_usage_info.h"
@@ -40,14 +41,17 @@
   NUM_TYPES
 };
 
-// Represents the per-StoragePartition ServiceWorker data.
+// Represents the per-StoragePartition service worker data.
+//
+// Implemented by ServiceWorkerContextWrapper (for both its pure virtual
+// functions and its non-virtual functions).
 class ServiceWorkerContext {
  public:
   // https://rawgithub.com/slightlyoff/ServiceWorker/master/spec/service_worker/index.html#url-scope:
   // roughly, must be of the form "<origin>/<path>/*".
   using Scope = GURL;
 
-  using ResultCallback = base::Callback<void(bool success)>;
+  using ResultCallback = base::OnceCallback<void(bool success)>;
 
   using GetUsageInfoCallback = base::Callback<void(
       const std::vector<ServiceWorkerUsageInfo>& usage_info)>;
@@ -89,14 +93,27 @@
   //  * |script_url| is on a different origin from |pattern|
   //  * Fetching |script_url| fails.
   //  * |script_url| fails to parse or its top-level execution fails.
-  //    TODO: The error message for this needs to be available to developers.
   //  * Something unexpected goes wrong, like a renderer crash or a full disk.
   //
   // This function can be called from any thread, but the callback will always
   // be called on the UI thread.
   virtual void RegisterServiceWorker(const Scope& pattern,
                                      const GURL& script_url,
-                                     const ResultCallback& callback) = 0;
+                                     ResultCallback callback) = 0;
+
+  // Equivalent to calling navigator.serviceWorker.unregister(pattern) from a
+  // renderer, except that |pattern| is an absolute URL instead of relative to
+  // some current origin.  |callback| is passed true when the JS promise is
+  // fulfilled or false when the JS promise is rejected.
+  //
+  // Unregistration can fail if:
+  //  * No Service Worker was registered for |pattern|.
+  //  * Something unexpected goes wrong, like a renderer crash.
+  //
+  // This function can be called from any thread, but the callback will always
+  // be called on the UI thread.
+  virtual void UnregisterServiceWorker(const Scope& pattern,
+                                       ResultCallback callback) = 0;
 
   // Mechanism for embedder to increment/decrement ref count of a service
   // worker.
@@ -112,31 +129,11 @@
                                        const std::string& request_uuid) = 0;
   virtual bool FinishedExternalRequest(int64_t service_worker_version_id,
                                        const std::string& request_uuid) = 0;
-
-  // Starts the active worker of the registration whose scope is |pattern|.
-  // |info_callback| is passed the worker's render process id and thread id.
-  //
-  // Must be called on IO thread.
-  virtual void StartActiveWorkerForPattern(
-      const GURL& pattern,
-      StartActiveWorkerCallback info_callback,
-      base::OnceClosure failure_callback) = 0;
-
-  // Equivalent to calling navigator.serviceWorker.unregister(pattern) from a
-  // renderer, except that |pattern| is an absolute URL instead of relative to
-  // some current origin.  |callback| is passed true when the JS promise is
-  // fulfilled or false when the JS promise is rejected.
-  //
-  // Unregistration can fail if:
-  //  * No Service Worker was registered for |pattern|.
-  //  * Something unexpected goes wrong, like a renderer crash.
-  //
-  // This function can be called from any thread, but the callback will always
-  // be called on the UI thread.
-  virtual void UnregisterServiceWorker(const Scope& pattern,
-                                       const ResultCallback& callback) = 0;
-
-  // Methods used in response to browsing data and quota manager requests.
+  // Returns the pending external request count for the worker with the
+  // specified |origin| via |callback|.
+  virtual void CountExternalRequestsForTest(
+      const GURL& origin,
+      const CountExternalRequestsCallback& callback) = 0;
 
   // Must be called from the IO thread.
   virtual void GetAllOriginsInfo(const GetUsageInfoCallback& callback) = 0;
@@ -144,7 +141,7 @@
   // This function can be called from any thread, but the callback will always
   // be called on the IO thread.
   virtual void DeleteForOrigin(const GURL& origin_url,
-                               const ResultCallback& callback) = 0;
+                               ResultCallback callback) = 0;
 
   // Returns ServiceWorkerCapability describing existence and properties of a
   // Service Worker registration matching |url|. Found service worker
@@ -162,17 +159,6 @@
       const GURL& other_url,
       const CheckHasServiceWorkerCallback& callback) = 0;
 
-  // Returns the pending external request count for the worker with the
-  // specified |origin| via |callback|.
-  virtual void CountExternalRequestsForTest(
-      const GURL& origin,
-      const CountExternalRequestsCallback& callback) = 0;
-
-  // Stops all running workers on the given |origin|.
-  //
-  // This function can be called from any thread.
-  virtual void StopAllServiceWorkersForOrigin(const GURL& origin) = 0;
-
   // Stops all running service workers and unregisters all service worker
   // registrations. This method is used in LayoutTests to make sure that the
   // existing service worker will not affect the succeeding tests.
@@ -181,6 +167,15 @@
   // be called on the UI thread.
   virtual void ClearAllServiceWorkersForTest(const base::Closure& callback) = 0;
 
+  // Starts the active worker of the registration whose scope is |pattern|.
+  // |info_callback| is passed the worker's render process id and thread id.
+  //
+  // Must be called on IO thread.
+  virtual void StartActiveWorkerForPattern(
+      const GURL& pattern,
+      StartActiveWorkerCallback info_callback,
+      base::OnceClosure failure_callback) = 0;
+
   // Starts the service worker for |document_url|. Called when a navigation to
   // that URL is predicted to occur soon. Must be called from the UI thread. The
   // |callback| will always be called on the UI thread.
@@ -188,6 +183,11 @@
       const GURL& document_url,
       const StartServiceWorkerForNavigationHintCallback& callback) = 0;
 
+  // Stops all running workers on the given |origin|.
+  //
+  // This function can be called from any thread.
+  virtual void StopAllServiceWorkersForOrigin(const GURL& origin) = 0;
+
  protected:
   ServiceWorkerContext() {}
   virtual ~ServiceWorkerContext() {}
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index ddaf66425..fcf923f 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -241,8 +241,12 @@
   // See also GetVisibleURL above, which may differ from this URL.
   virtual const GURL& GetLastCommittedURL() const = 0;
 
-  // Return the currently active RenderProcessHost and RenderViewHost. Each of
-  // these may change over time.
+  // Returns the main frame's process.  This may change over time (e.g. if the
+  // main frame is navigated to another origin).
+  // DEPRECATED: Explicitly specify which frame's process is needed, by instead
+  // calling something like web_contents->GetMainFrame()->GetProcess() or
+  // web_contents->GetFocusedFrame()->GetProcess().
+  // TODO(https://crbug.com/666525): Remove this method when possible.
   virtual RenderProcessHost* GetRenderProcessHost() const = 0;
 
   // Returns the main frame for the currently active view.
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index e1d04ce..a82bca1 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -116,13 +116,6 @@
 const base::Feature kHeapCompaction{"HeapCompaction",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables Blink's idle time spell checker.
-// Design: https://goo.gl/zONC3v
-// Note: The feature is implemented in Blink, and is independent to the
-// ENABLE_SPELLCHECK build flag defined in components/spellcheck.
-const base::Feature kIdleTimeSpellChecking{"IdleTimeSpellChecking",
-                                           base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Enable lazy initialization of the media controls.
 const base::Feature kLazyInitializeMediaControls{
     "LazyInitializeMediaControls", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -132,8 +125,14 @@
                                   base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Use Mojo IPC for resource loading.
-const base::Feature kLoadingWithMojo{"LoadingWithMojo",
-                                     base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kLoadingWithMojo {
+  "LoadingWithMojo",
+#if defined(OS_ANDROID)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#else
+      base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
 
 // Enables the old algorithm for processing audio constraints in getUserMedia().
 const base::Feature kMediaStreamOldAudioConstraints{
@@ -168,8 +167,14 @@
 
 // Enables/disables hardware video encode acceleration using Mojo (falls back).
 // TODO(mcasas): remove after https://crbug.com/736517 is closed.
-const base::Feature kMojoVideoEncodeAccelerator{
-    "MojoVideoEncodeAccelerator", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kMojoVideoEncodeAccelerator {
+  "MojoVideoEncodeAccelerator",
+#if defined(OS_MACOSX)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
 
 // ES6 Modules.
 const base::Feature kModuleScripts{"ModuleScripts",
@@ -280,12 +285,6 @@
 const base::Feature kSkipCompositingSmallScrollers{
     "SkipCompositingSmallScrollers", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// An experiment to reduce the soft tile memory limit on low-end android
-// devices.
-const base::Feature kReducedSoftTileMemoryLimitOnLowEndAndroid{
-    "ReducedSoftTileMemoryLimitOnLowEndAndroid",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Paint invalidation based on slimming paint. See https://goo.gl/eQczQW
 const base::Feature kSlimmingPaintInvalidation{
     "SlimmingPaintInvalidation", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -403,6 +402,9 @@
 const base::Feature kImageCaptureAPI{"ImageCaptureAPI",
                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kKeepAliveRendererForKeepaliveRequests{
+    "KeepAliveRendererForKeepaliveRequests", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables WebVR experimental rendering optimizations.
 const base::Feature kWebVRExperimentalRendering{
     "WebVRExperimentalRendering", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 68dc1aa..a34e0c7 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -29,8 +29,6 @@
 CONTENT_EXPORT extern const base::Feature kCompositeOpaqueFixedPosition;
 CONTENT_EXPORT extern const base::Feature kCompositeOpaqueScrollers;
 CONTENT_EXPORT extern const base::Feature kCompositorTouchAction;
-CONTENT_EXPORT extern const base::Feature
-    kReducedSoftTileMemoryLimitOnLowEndAndroid;
 CONTENT_EXPORT extern const base::Feature kExpensiveBackgroundTimerThrottling;
 CONTENT_EXPORT extern const base::Feature kFeaturePolicy;
 CONTENT_EXPORT extern const base::Feature kFetchKeepaliveTimeoutSetting;
@@ -40,8 +38,9 @@
 CONTENT_EXPORT extern const base::Feature kGamepadExtensions;
 CONTENT_EXPORT extern const base::Feature kGuestViewCrossProcessFrames;
 CONTENT_EXPORT extern const base::Feature kHeapCompaction;
-CONTENT_EXPORT extern const base::Feature kIdleTimeSpellChecking;
 CONTENT_EXPORT extern const base::Feature kImageCaptureAPI;
+CONTENT_EXPORT extern const base::Feature
+    kKeepAliveRendererForKeepaliveRequests;
 CONTENT_EXPORT extern const base::Feature kLazyInitializeMediaControls;
 CONTENT_EXPORT extern const base::Feature kLazyParseCSS;
 CONTENT_EXPORT extern const base::Feature kLoadingWithMojo;
diff --git a/content/public/common/cookie_manager.mojom b/content/public/common/cookie_manager.mojom
index 4440fe9..79a87f8 100644
--- a/content/public/common/cookie_manager.mojom
+++ b/content/public/common/cookie_manager.mojom
@@ -33,6 +33,8 @@
   bool exclude_httponly = true;
   CookieSameSiteFilter cookie_same_site_filter = DO_NOT_INCLUDE;
   bool update_access_time = true;
+  // TODO(rdsmith): Remove this element from the mojo structure?  It's only
+  // used in the underlying net:: structure in CanonicalCookie::Create().
   mojo.common.mojom.Time? server_time;
 };
 
diff --git a/content/public/common/cookie_manager_traits.cc b/content/public/common/cookie_manager_traits.cc
index 1224451b0..bf22337 100644
--- a/content/public/common/cookie_manager_traits.cc
+++ b/content/public/common/cookie_manager_traits.cc
@@ -111,10 +111,17 @@
     cookie_options->set_exclude_httponly();
   else
     cookie_options->set_include_httponly();
+
+  net::CookieOptions::SameSiteCookieMode same_site_cookie_mode;
+  if (!mojo_options.ReadCookieSameSiteFilter(&same_site_cookie_mode))
+    return false;
+  cookie_options->set_same_site_cookie_mode(same_site_cookie_mode);
+
   if (mojo_options.update_access_time())
     cookie_options->set_update_access_time();
   else
     cookie_options->set_do_not_update_access_time();
+
   base::Optional<base::Time> optional_server_time;
   if (!mojo_options.ReadServerTime(&optional_server_time))
     return false;
diff --git a/content/public/common/media_stream_request.cc b/content/public/common/media_stream_request.cc
index 10fe904..cd181b9 100644
--- a/content/public/common/media_stream_request.cc
+++ b/content/public/common/media_stream_request.cc
@@ -90,22 +90,6 @@
   return IsEqual(other_device) && session_id == other_device.session_id;
 }
 
-MediaStreamDevices::MediaStreamDevices() {}
-
-MediaStreamDevices::MediaStreamDevices(size_t count,
-                                       const MediaStreamDevice& value)
-    : std::vector<MediaStreamDevice>(count, value) {
-}
-
-const MediaStreamDevice* MediaStreamDevices::FindById(
-    const std::string& device_id) const {
-  for (const_iterator iter = begin(); iter != end(); ++iter) {
-    if (iter->id == device_id)
-      return &(*iter);
-  }
-  return NULL;
-}
-
 MediaStreamRequest::MediaStreamRequest(
     int render_process_id,
     int render_frame_id,
diff --git a/content/public/common/media_stream_request.h b/content/public/common/media_stream_request.h
index a9ea751..56a48d9 100644
--- a/content/public/common/media_stream_request.h
+++ b/content/public/common/media_stream_request.h
@@ -146,18 +146,7 @@
   base::Optional<CameraCalibration> camera_calibration;
 };
 
-class CONTENT_EXPORT MediaStreamDevices
-    : public std::vector<MediaStreamDevice> {
- public:
-  MediaStreamDevices();
-  MediaStreamDevices(size_t count, const MediaStreamDevice& value);
-
-  // Looks for a MediaStreamDevice based on its ID.
-  // Returns NULL if not found.
-  const MediaStreamDevice* FindById(const std::string& device_id) const;
-};
-
-typedef std::map<MediaStreamType, MediaStreamDevices> MediaStreamDeviceMap;
+using MediaStreamDevices = std::vector<MediaStreamDevice>;
 
 // Represents a request for media streams (audio/video).
 // TODO(vrk): Decouple MediaStreamDevice from this header file so that
@@ -241,11 +230,10 @@
 };
 
 // Callback used return results of media access requests.
-typedef base::Callback<void(const MediaStreamDevices& devices,
-                            content::MediaStreamRequestResult result,
-                            std::unique_ptr<MediaStreamUI> ui)>
-    MediaResponseCallback;
-
+using MediaResponseCallback =
+    base::Callback<void(const MediaStreamDevices& devices,
+                        MediaStreamRequestResult result,
+                        std::unique_ptr<MediaStreamUI> ui)>;
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_COMMON_MEDIA_STREAM_REQUEST_H_
diff --git a/content/public/common/network_service.mojom b/content/public/common/network_service.mojom
index 6b44a26..93a2a46c 100644
--- a/content/public/common/network_service.mojom
+++ b/content/public/common/network_service.mojom
@@ -71,4 +71,10 @@
   // Disables QUIC for the NetworkService. Affects all existing NetworkContexts,
   // and all new ones that are created. Once called, QUIC cannot be re-enabled.
   DisableQuic();
+
+  // Specifies whether requests for raw headers coming through URLLoaderFactory
+  // associated with the specified process will be granted. Granting such a
+  // permission increases risks in case the child process becomes compromised,
+  // so this should be done only in specific cases (e.g. DevTools attached).
+  SetRawHeadersAccess(uint32 process_id, bool allow);
 };
diff --git a/content/public/common/resource_request_completion_status.cc b/content/public/common/resource_request_completion_status.cc
index 2056851..26ad6ac 100644
--- a/content/public/common/resource_request_completion_status.cc
+++ b/content/public/common/resource_request_completion_status.cc
@@ -8,16 +8,13 @@
 
 namespace content {
 
-ResourceRequestCompletionStatus::ResourceRequestCompletionStatus() {}
+ResourceRequestCompletionStatus::ResourceRequestCompletionStatus() = default;
 ResourceRequestCompletionStatus::ResourceRequestCompletionStatus(
     const ResourceRequestCompletionStatus& status) = default;
 
-ResourceRequestCompletionStatus::ResourceRequestCompletionStatus(int64_t length)
-    : error_code(net::OK),
-      completion_time(base::TimeTicks::Now()),
-      encoded_data_length(length),
-      encoded_body_length(length) {}
+ResourceRequestCompletionStatus::ResourceRequestCompletionStatus(int error_code)
+    : error_code(error_code), completion_time(base::TimeTicks::Now()) {}
 
-ResourceRequestCompletionStatus::~ResourceRequestCompletionStatus() {}
+ResourceRequestCompletionStatus::~ResourceRequestCompletionStatus() = default;
 
 }  // namespace content
diff --git a/content/public/common/resource_request_completion_status.h b/content/public/common/resource_request_completion_status.h
index 376e8c2..a19fb24e 100644
--- a/content/public/common/resource_request_completion_status.h
+++ b/content/public/common/resource_request_completion_status.h
@@ -17,9 +17,11 @@
   ResourceRequestCompletionStatus();
   ResourceRequestCompletionStatus(
       const ResourceRequestCompletionStatus& status);
-  explicit ResourceRequestCompletionStatus(int64_t length);
-  // Sets error_code to net::OK, completition_time to base::TimeTicks::Now(),
-  // and encoded_data_length = encoded_body_length = |length|;
+
+  // Sets |error_code| to |error_code| and |completion_time| to
+  // base::TimeTicks::Now().
+  explicit ResourceRequestCompletionStatus(int error_code);
+
   ~ResourceRequestCompletionStatus();
 
   // The error code.
diff --git a/content/public/renderer/resource_fetcher.h b/content/public/renderer/resource_fetcher.h
index 9cd98c2..5d479a1 100644
--- a/content/public/renderer/resource_fetcher.h
+++ b/content/public/renderer/resource_fetcher.h
@@ -39,8 +39,9 @@
 
   // This will be called asynchronously after the URL has been fetched,
   // successfully or not.  If there is a failure, response and data will both be
-  // empty.  |response| and |data| are both valid until the URLFetcher instance
-  // is destroyed.
+  // empty.  |response| and |data| are both valid until the ResourceFetcher
+  // instance is destroyed.  The callback will not be called if ResourceFetcher
+  // instance is destroyed before complication or cancellation.
   using Callback =
       base::OnceCallback<void(const blink::WebURLResponse& response,
                               const std::string& data)>;
@@ -58,12 +59,6 @@
   virtual void SetHeader(const std::string& header,
                          const std::string& value) = 0;
 
-  // DEPRECATED: Starts the request using the specified frame.  Calls |callback|
-  // when done.
-  virtual void Start(blink::WebLocalFrame* frame,
-                     blink::WebURLRequest::RequestContext request_context,
-                     Callback callback) = 0;
-
   // Starts the request using the specified frame.  Calls |callback| when
   // done.
   virtual void Start(
@@ -78,7 +73,9 @@
   // timeout.  Must be called after a request is started.
   virtual void SetTimeout(const base::TimeDelta& timeout) = 0;
 
-  // Manually cancel the request.
+  // DEPRECATED: Manually cancel the request.  Calls |callback| with a null
+  // WebURLResponse.  New code should not use this method, but just destruct the
+  // instance to abort.
   virtual void Cancel() = 0;
 };
 
diff --git a/content/public/test/DEPS b/content/public/test/DEPS
index 4a4474aa..a093d9c 100644
--- a/content/public/test/DEPS
+++ b/content/public/test/DEPS
@@ -12,10 +12,6 @@
 # Ensure we don't leak internal content headers through public headers.
 specific_include_rules = {
   ".*\.(cc|mm)": [
-    # Allow inclusion of specific components that we depend on.
-    # See comment in content/DEPS for which components are allowed.
-    "+components/scheduler/renderer",
-
     # Testing utilities can access anything in content/
     "+content",
     "+gin/v8_initializer.h",
diff --git a/content/public/test/mock_service_worker_context.cc b/content/public/test/mock_service_worker_context.cc
index a086d8d0..fb7e0a0d 100644
--- a/content/public/test/mock_service_worker_context.cc
+++ b/content/public/test/mock_service_worker_context.cc
@@ -12,11 +12,32 @@
 MockServiceWorkerContext::MockServiceWorkerContext() {}
 MockServiceWorkerContext::~MockServiceWorkerContext() {}
 
+void MockServiceWorkerContext::RegisterServiceWorker(const GURL& pattern,
+                                                     const GURL& script_url,
+                                                     ResultCallback callback) {
+  NOTREACHED();
+}
+void MockServiceWorkerContext::UnregisterServiceWorker(
+    const GURL& pattern,
+    ResultCallback callback) {
+  NOTREACHED();
+}
+void MockServiceWorkerContext::CountExternalRequestsForTest(
+    const GURL& url,
+    const CountExternalRequestsCallback& callback) {
+  NOTREACHED();
+}
+
+void MockServiceWorkerContext::DeleteForOrigin(const GURL& origin,
+                                               ResultCallback callback) {
+  NOTREACHED();
+}
+
 void MockServiceWorkerContext::StartActiveWorkerForPattern(
     const GURL& pattern,
     ServiceWorkerContext::StartActiveWorkerCallback info_callback,
     base::OnceClosure failure_callback) {
-  NOTREACHED() << "No mock for StartActiveWorkerForPattern";
+  NOTREACHED();
 }
 
 }  // namespace content
diff --git a/content/public/test/mock_service_worker_context.h b/content/public/test/mock_service_worker_context.h
index 90c8cbe2..e4d57df0 100644
--- a/content/public/test/mock_service_worker_context.h
+++ b/content/public/test/mock_service_worker_context.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_PUBLIC_TEST_MOCK_SERVICE_WORKER_CONTEXT_H_
 #define CONTENT_PUBLIC_TEST_MOCK_SERVICE_WORKER_CONTEXT_H_
 
+#include <string>
+
 #include "base/callback_forward.h"
 #include "content/public/browser/service_worker_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -21,43 +23,37 @@
   MockServiceWorkerContext();
   virtual ~MockServiceWorkerContext();
 
+  // Some functions cannot be mocked because they use OnceCallback which is not
+  // copyable.
   MOCK_METHOD1(AddObserver, void(ServiceWorkerContextObserver*));
   MOCK_METHOD1(RemoveObserver, void(ServiceWorkerContextObserver*));
-  MOCK_METHOD3(RegisterServiceWorker,
-               void(const ServiceWorkerContext::Scope&,
-                    const GURL&,
-                    const ServiceWorkerContext::ResultCallback&));
+  void RegisterServiceWorker(const GURL& pattern,
+                             const GURL& script_url,
+                             ResultCallback callback) override;
+  void UnregisterServiceWorker(const GURL& pattern,
+                               ResultCallback callback) override;
   MOCK_METHOD2(StartingExternalRequest, bool(int64_t, const std::string&));
   MOCK_METHOD2(FinishedExternalRequest, bool(int64_t, const std::string&));
-
-  // StartActiveWorkerForPattern cannot be mocked because OnceClosure is not
-  // copyable.
-  void StartActiveWorkerForPattern(
-      const GURL& pattern,
-      ServiceWorkerContext::StartActiveWorkerCallback info_callback,
-      base::OnceClosure failure_callback) override;
-
-  MOCK_METHOD2(UnregisterServiceWorker,
-               void(const ServiceWorkerContext::Scope&,
-                    const ServiceWorkerContext::ResultCallback&));
+  void CountExternalRequestsForTest(
+      const GURL& url,
+      const CountExternalRequestsCallback& callback) override;
   MOCK_METHOD1(GetAllOriginsInfo,
                void(const ServiceWorkerContext::GetUsageInfoCallback&));
-  MOCK_METHOD2(DeleteForOrigin,
-               void(const GURL&, const ServiceWorkerContext::ResultCallback&));
+  void DeleteForOrigin(const GURL& origin, ResultCallback callback) override;
   MOCK_METHOD3(
       CheckHasServiceWorker,
       void(const GURL&,
            const GURL&,
            const ServiceWorkerContext::CheckHasServiceWorkerCallback&));
-  MOCK_METHOD2(
-      CountExternalRequestsForTest,
-      void(const GURL&,
-           const ServiceWorkerContext::CountExternalRequestsCallback&));
-  MOCK_METHOD1(StopAllServiceWorkersForOrigin, void(const GURL&));
   MOCK_METHOD1(ClearAllServiceWorkersForTest, void(const base::Closure&));
+  void StartActiveWorkerForPattern(
+      const GURL& pattern,
+      ServiceWorkerContext::StartActiveWorkerCallback info_callback,
+      base::OnceClosure failure_callback) override;
   MOCK_METHOD2(StartServiceWorkerForNavigationHint,
                void(const GURL&,
                     const StartServiceWorkerForNavigationHintCallback&));
+  MOCK_METHOD1(StopAllServiceWorkersForOrigin, void(const GURL&));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockServiceWorkerContext);
diff --git a/content/renderer/DEPS b/content/renderer/DEPS
index d69b153..0b51146 100644
--- a/content/renderer/DEPS
+++ b/content/renderer/DEPS
@@ -5,7 +5,6 @@
   "+components/metrics",
   "+components/metrics:single_sample_metrics",
   "+components/payments",
-  "+components/scheduler",
   "+components/url_formatter",
   "+components/viz/client",
   "+components/viz/common",
diff --git a/content/renderer/accessibility/blink_ax_enum_conversion.cc b/content/renderer/accessibility/blink_ax_enum_conversion.cc
index b990bc7..aecb796da 100644
--- a/content/renderer/accessibility/blink_ax_enum_conversion.cc
+++ b/content/renderer/accessibility/blink_ax_enum_conversion.cc
@@ -392,6 +392,8 @@
       return ui::AX_DEFAULT_ACTION_VERB_CHECK;
     case blink::WebAXDefaultActionVerb::kClick:
       return ui::AX_DEFAULT_ACTION_VERB_CLICK;
+    case blink::WebAXDefaultActionVerb::kClickAncestor:
+      return ui::AX_DEFAULT_ACTION_VERB_CLICK_ANCESTOR;
     case blink::WebAXDefaultActionVerb::kJump:
       return ui::AX_DEFAULT_ACTION_VERB_JUMP;
     case blink::WebAXDefaultActionVerb::kOpen:
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
index cf39923..cd5c880 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -299,13 +299,16 @@
     embed_render_pass->has_transparent_background = false;
 
     // The RenderPass has a single SurfaceDrawQuad (and SharedQuadState for it).
+    bool are_contents_opaque =
+        !frame.render_pass_list.back()->has_transparent_background;
     auto* shared_quad_state =
         embed_render_pass->CreateAndAppendSharedQuadState();
     auto* surface_quad =
         embed_render_pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
     shared_quad_state->SetAll(
         child_transform, gfx::Rect(child_size), gfx::Rect(child_size),
-        gfx::Rect() /* clip_rect */, false /* is_clipped */, 1.f /* opacity */,
+        gfx::Rect() /* clip_rect */, false /* is_clipped */,
+        are_contents_opaque /* are_contents_opaque */, 1.f /* opacity */,
         SkBlendMode::kSrcOver, 0 /* sorting_context_id */);
     surface_quad->SetNew(
         shared_quad_state, gfx::Rect(child_size), gfx::Rect(child_size),
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index b9c91d0f3..167d10462 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -338,19 +338,18 @@
       viz::SurfaceInfo surface_info(
           viz::SurfaceId(frame_sink_id_, local_surface_id_),
           device_scale_factor,
-          gfx::ScaleToCeiledSize(view_rect_.size(), device_scale_factor));
+          gfx::ScaleToCeiledSize(view_rect.size(), device_scale_factor));
       compositing_helper_->SetPrimarySurfaceInfo(surface_info);
     }
   }
 
   view_rect_ = view_rect;
 
-  if (!attached())
-    return;
-
-  // Let the browser know about the updated view rect.
-  BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateGeometry(
-      browser_plugin_instance_id_, view_rect_, local_surface_id_));
+  if (attached()) {
+    // Let the browser know about the updated view rect.
+    BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_UpdateGeometry(
+        browser_plugin_instance_id_, view_rect_, local_surface_id_));
+  }
 
   if (rect_size_changed && delegate_)
     delegate_->DidResizeElement(view_rect_.size());
diff --git a/content/renderer/dom_automation_controller.cc b/content/renderer/dom_automation_controller.cc
index e3d3504..4f02ed6 100644
--- a/content/renderer/dom_automation_controller.cc
+++ b/content/renderer/dom_automation_controller.cc
@@ -50,10 +50,7 @@
     v8::Isolate* isolate) {
   return gin::Wrappable<DomAutomationController>::GetObjectTemplateBuilder(
              isolate)
-      .SetMethod("send", &DomAutomationController::SendMsg)
-      .SetMethod("setAutomationId", &DomAutomationController::SetAutomationId)
-      .SetMethod("sendJSON", &DomAutomationController::SendJSON)
-      .SetMethod("sendWithId", &DomAutomationController::SendWithId);
+      .SetMethod("send", &DomAutomationController::SendMsg);
 }
 
 void DomAutomationController::OnDestruct() {}
@@ -106,32 +103,7 @@
   if (!value || !serializer.Serialize(*value))
     return false;
 
-  bool succeeded = Send(new FrameHostMsg_DomOperationResponse(
-      routing_id(), json));
-
-  return succeeded;
-}
-
-bool DomAutomationController::SendJSON(const std::string& json) {
-  if (!render_frame())
-    return false;
-
-  bool result = Send(new FrameHostMsg_DomOperationResponse(
-      routing_id(), json));
-
-  return result;
-}
-
-bool DomAutomationController::SendWithId(int automation_id,
-                                         const std::string& str) {
-  if (!render_frame())
-    return false;
-  return Send(
-      new FrameHostMsg_DomOperationResponse(routing_id(), str));
-}
-
-bool DomAutomationController::SetAutomationId(int automation_id) {
-  return true;
+  return Send(new FrameHostMsg_DomOperationResponse(routing_id(), json));
 }
 
 }  // namespace content
diff --git a/content/renderer/dom_automation_controller.h b/content/renderer/dom_automation_controller.h
index 0db719f5..11f72b77 100644
--- a/content/renderer/dom_automation_controller.h
+++ b/content/renderer/dom_automation_controller.h
@@ -11,68 +11,6 @@
 #include "content/public/renderer/render_frame_observer.h"
 #include "gin/wrappable.h"
 
-/* DomAutomationController class:
-   Bound to Javascript window.domAutomationController object.
-   At the very basic, this object makes any native value (string, numbers,
-   boolean) from javascript available to the automation host in Cpp.
-   Any renderer implementation that is built with this binding will allow the
-   above facility.
-   The intended use of this object is to expose the DOM Objects and their
-   attributes to the automation host.
-
-   A typical usage would be like following (JS code):
-
-   var object = document.getElementById('some_id');
-   window.domAutomationController.send(object.nodeName); // get the tag name
-
-   For the exact mode of usage,
-   refer AutomationProxyTest.*DomAutomationController tests.
-
-   The class provides a single send method that can send variety of native
-   javascript values. (NPString, Number(double), Boolean)
-
-   The actual communication occurs in the following manner:
-
-    TEST            MASTER          RENDERER
-              (1)             (3)
-   |AProxy| ----->|AProvider|----->|RenderView|------|
-      /\                |               |            |
-      |                 |               |            |
-      |(6)              |(2)            |(0)         |(4)
-      |                 |               \/           |
-      |                 |-------->|DAController|<----|
-      |                                 |
-      |                                 |(5)
-      |-------|WebContentsImpl|<--------|
-
-
-   Legends:
-   - AProxy = AutomationProxy
-   - AProvider = AutomationProvider
-   - DAController = DomAutomationController
-
-   (0) Initialization step where DAController is bound to the renderer
-       and the view_id of the renderer is supplied to the DAController for
-       routing message in (5).
-   (1) A 'javascript:' url is sent from the test process to master as an IPC
-       message. A unique routing id is generated at this stage (automation_id_)
-   (2) The automation_id_ of step (1) is supplied to DAController by calling
-       the bound method setAutomationId(). This is required for routing message
-       in (6).
-   (3) The 'javascript:' url is sent for execution by calling into
-       Browser::LoadURL()
-   (4) A callback is generated as a result of domAutomationController.send()
-       into Cpp. The supplied value is received as a result of this callback.
-   (5) The value received in (4) is sent to the master along with the
-       stored automation_id_ as an IPC message. The frame_'s RenderFrameImpl is
-       used to route the message. (IPC messages, ViewHostMsg_*DomAutomation* )
-   (6) The value and the automation_id_ is extracted out of the message received
-       in (5). This value is relayed to AProxy using another IPC message.
-       automation_id_ is used to route the message.
-       (IPC messages, AutomationMsg_Dom*Response)
-
-*/
-
 namespace blink {
 class WebLocalFrame;
 }
@@ -85,6 +23,15 @@
 
 class RenderFrame;
 
+// Provides implementation of window.domAutomationController javascript object.
+// Javascript can call domAutomationController.send(...) to send arbitrary data
+// to the browser.  On the browser side, the data is received via one of the
+// following:
+// - Product code:
+//   - Explicit handlers of FrameHostMsg_DomOperationResponse IPC
+// - Test code:
+//   - DOMMessageQueue class
+//   - ExecuteScriptAndExtractInt/Bool/String functions
 class DomAutomationController : public gin::Wrappable<DomAutomationController>,
                                 public RenderFrameObserver {
  public:
@@ -98,15 +45,6 @@
   // argument at all is ignored.
   bool SendMsg(const gin::Arguments& args);
 
-  // Makes the renderer send a javascript value to the app.
-  // The value should be properly formed JSON.
-  bool SendJSON(const std::string& json);
-
-  // Sends a string with a provided Automation Id.
-  bool SendWithId(int automation_id, const std::string& str);
-
-  bool SetAutomationId(int automation_id);
-
  private:
   explicit DomAutomationController(RenderFrame* render_view);
   ~DomAutomationController() override;
diff --git a/content/renderer/dom_storage/dom_storage_cached_area.cc b/content/renderer/dom_storage/dom_storage_cached_area.cc
index 12480ea8c..8721c94 100644
--- a/content/renderer/dom_storage/dom_storage_cached_area.cc
+++ b/content/renderer/dom_storage/dom_storage_cached_area.cc
@@ -8,6 +8,7 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "content/common/dom_storage/dom_storage_map.h"
 #include "content/renderer/dom_storage/dom_storage_proxy.h"
 
@@ -54,8 +55,17 @@
 
   PrimeIfNeeded(connection_id);
   base::NullableString16 old_value;
+#if !defined(OS_ANDROID)
+  if (!map_->SetItem(key, value, nullptr))
+    return false;
+#else
+  // The old value is only used on Android when the cache stores only the keys.
+  // Do not send old value on other platforms.
+  // TODO(ssid): Clear this value when values are stored in the browser cache on
+  // Android, crbug.com/743187.
   if (!map_->SetItem(key, value, &old_value))
     return false;
+#endif  // !defined(OS_ANDROID)
 
   // Ignore mutations to 'key' until OnSetItemComplete.
   ignore_key_mutations_[key]++;
@@ -70,8 +80,15 @@
                                       const GURL& page_url) {
   PrimeIfNeeded(connection_id);
   base::string16 old_value;
+#if !defined(OS_ANDROID)
+  if (!map_->RemoveItem(key, nullptr))
+    return;
+#else
+  // The old value is only used on Android when the cache stores only the keys.
+  // Do not send old value on other platforms.
   if (!map_->RemoveItem(key, &old_value))
     return;
+#endif
 
   // Ignore mutations to 'key' until OnRemoveItemComplete.
   ignore_key_mutations_[key]++;
@@ -112,8 +129,7 @@
     while (iter != ignore_key_mutations_.end()) {
       base::NullableString16 value = old->GetItem(iter->first);
       if (!value.is_null()) {
-        base::NullableString16 unused;
-        map_->SetItem(iter->first, value.string(), &unused);
+        map_->SetItem(iter->first, value.string(), nullptr);
       }
       ++iter;
     }
@@ -126,17 +142,15 @@
 
   if (new_value.is_null()) {
     // It's a remove item event.
-    base::string16 unused;
-    map_->RemoveItem(key.string(), &unused);
+    map_->RemoveItem(key.string(), nullptr);
     return;
   }
 
   // It's a set item event.
   // We turn off quota checking here to accomodate the over budget
   // allowance that's provided in the browser process.
-  base::NullableString16 unused;
   map_->set_quota(std::numeric_limits<int32_t>::max());
-  map_->SetItem(key.string(), new_value.string(), &unused);
+  map_->SetItem(key.string(), new_value.string(), nullptr);
   map_->set_quota(kPerStorageAreaQuota);
 }
 
@@ -165,7 +179,7 @@
   map_ = new DOMStorageMap(kPerStorageAreaQuota);
   map_->SwapValues(&values);
 
-  size_t local_storage_size_kb = map_->bytes_used() / 1024;
+  size_t local_storage_size_kb = map_->storage_used() / 1024;
   // Track localStorage size, from 0-6MB. Note that the maximum size should be
   // 5MB, but we add some slop since we want to make sure the max size is always
   // above what we see in practice, since histograms can't change.
diff --git a/content/renderer/dom_storage/local_storage_cached_area.cc b/content/renderer/dom_storage/local_storage_cached_area.cc
index ecf4f0b..f933c1a 100644
--- a/content/renderer/dom_storage/local_storage_cached_area.cc
+++ b/content/renderer/dom_storage/local_storage_cached_area.cc
@@ -110,8 +110,7 @@
     return false;
 
   EnsureLoaded();
-  base::NullableString16 unused;
-  if (!map_->SetItem(key, value, &unused))
+  if (!map_->SetItem(key, value, nullptr))
     return false;
 
   // Ignore mutations to |key| until OnSetItemComplete.
@@ -127,8 +126,7 @@
                                         const GURL& page_url,
                                         const std::string& storage_area_id) {
   EnsureLoaded();
-  base::string16 unused;
-  if (!map_->RemoveItem(key, &unused))
+  if (!map_->RemoveItem(key, nullptr))
     return;
 
   // Ignore mutations to |key| until OnRemoveItemComplete.
@@ -249,10 +247,8 @@
     // remove it from our cache if we haven't already changed it and are waiting
     // for the confirmation callback. In the latter case, we won't do anything
     // because ignore_key_mutations_ won't be updated until the callback runs.
-    if (ignore_key_mutations_.find(key_string) == ignore_key_mutations_.end()) {
-      base::string16 unused;
-      map_->RemoveItem(key_string, &unused);
-    }
+    if (ignore_key_mutations_.find(key_string) == ignore_key_mutations_.end())
+      map_->RemoveItem(key_string, nullptr);
   }
 
   blink::WebStorageEventDispatcher::DispatchLocalStorageEvent(
@@ -279,10 +275,8 @@
     auto iter = ignore_key_mutations_.begin();
     while (iter != ignore_key_mutations_.end()) {
       base::NullableString16 value = old->GetItem(iter->first);
-      if (!value.is_null()) {
-        base::NullableString16 unused;
-        map_->SetItem(iter->first, value.string(), &unused);
-      }
+      if (!value.is_null())
+        map_->SetItem(iter->first, value.string(), nullptr);
       ++iter;
     }
   }
@@ -316,9 +310,8 @@
     if (ignore_key_mutations_.find(key_string) == ignore_key_mutations_.end()) {
       // We turn off quota checking here to accomodate the over budget allowance
       // that's provided in the browser process.
-      base::NullableString16 unused;
       map_->set_quota(std::numeric_limits<int32_t>::max());
-      map_->SetItem(key_string, new_value_string, &unused);
+      map_->SetItem(key_string, new_value_string, nullptr);
       map_->set_quota(kPerStorageAreaQuota);
     }
   }
@@ -355,7 +348,7 @@
   base::TimeDelta time_to_prime = base::TimeTicks::Now() - before;
   UMA_HISTOGRAM_TIMES("LocalStorage.MojoTimeToPrime", time_to_prime);
 
-  size_t local_storage_size_kb = map_->bytes_used() / 1024;
+  size_t local_storage_size_kb = map_->storage_used() / 1024;
   // Track localStorage size, from 0-6MB. Note that the maximum size should be
   // 5MB, but we add some slop since we want to make sure the max size is always
   // above what we see in practice, since histograms can't change.
diff --git a/content/renderer/fetchers/resource_fetcher_browsertest.cc b/content/renderer/fetchers/resource_fetcher_browsertest.cc
index 12ebc41..78070886 100644
--- a/content/renderer/fetchers/resource_fetcher_browsertest.cc
+++ b/content/renderer/fetchers/resource_fetcher_browsertest.cc
@@ -14,16 +14,19 @@
 #include "build/build_config.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
 using blink::WebURLRequest;
@@ -148,7 +151,10 @@
     std::unique_ptr<FetcherDelegate> delegate(new FetcherDelegate);
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
 
     delegate->WaitForResponse();
 
@@ -166,7 +172,10 @@
     std::unique_ptr<FetcherDelegate> delegate(new FetcherDelegate);
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
 
     delegate->WaitForResponse();
 
@@ -184,7 +193,10 @@
     std::unique_ptr<FetcherDelegate> delegate(new FetcherDelegate);
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
 
     delegate->WaitForResponse();
 
@@ -201,7 +213,10 @@
     std::unique_ptr<FetcherDelegate> delegate(new FetcherDelegate);
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
 
     delegate->WaitForResponse();
 
@@ -220,7 +235,10 @@
     std::unique_ptr<FetcherDelegate> delegate(new FetcherDelegate);
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
     fetcher->SetTimeout(base::TimeDelta());
 
     delegate->WaitForResponse();
@@ -240,7 +258,10 @@
     std::unique_ptr<EvilFetcherDelegate> delegate(new EvilFetcherDelegate);
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
     fetcher->SetTimeout(base::TimeDelta());
     delegate->SetFetcher(fetcher.release());
 
@@ -259,7 +280,10 @@
     fetcher->SetMethod("POST");
     fetcher->SetBody(kBody);
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
 
     delegate->WaitForResponse();
     ASSERT_TRUE(delegate->completed());
@@ -277,7 +301,10 @@
     std::unique_ptr<ResourceFetcher> fetcher(ResourceFetcher::Create(url));
     fetcher->SetHeader("header", kHeader);
     fetcher->Start(frame, WebURLRequest::kRequestContextInternal,
-                   delegate->NewCallback());
+                   RenderFrame::FromWebFrame(frame)
+                       ->GetDefaultURLLoaderFactoryGetter()
+                       ->GetNetworkLoaderFactory(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS, delegate->NewCallback());
 
     delegate->WaitForResponse();
     ASSERT_TRUE(delegate->completed());
diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc
index 2acdc44..719db25c 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -57,7 +57,10 @@
         maximum_download_size_(maximum_download_size),
         callback_(std::move(callback)) {}
 
-  ~ClientImpl() override {}
+  ~ClientImpl() override {
+    callback_ = Callback();
+    Cancel();
+  }
 
   void Start(const ResourceRequest& request,
              mojom::URLLoaderFactory* url_loader_factory,
@@ -78,12 +81,8 @@
 
   void Cancel() {
     ClearReceivedDataToFail();
-
-    // Close will invoke OnComplete() eventually.
+    completed_ = true;
     Close();
-
-    // Reset |loader_| to avoid unexpected other callbacks invocations.
-    loader_.reset();
   }
 
   bool IsActive() const {
@@ -209,6 +208,10 @@
     ReadDataPipe();
   }
   void OnComplete(const ResourceRequestCompletionStatus& status) override {
+    // When Cancel() sets |complete_|, OnComplete() may be called.
+    if (completed_)
+      return;
+
     DCHECK(IsActive()) << "status: " << static_cast<int>(status_);
     if (status.error_code != net::OK) {
       ClearReceivedDataToFail();
@@ -253,8 +256,7 @@
 }
 
 ResourceFetcherImpl::~ResourceFetcherImpl() {
-  if (client_->IsActive())
-    client_->Cancel();
+  client_.reset();
 }
 
 void ResourceFetcherImpl::SetMethod(const std::string& method) {
@@ -283,40 +285,6 @@
 void ResourceFetcherImpl::Start(
     blink::WebLocalFrame* frame,
     blink::WebURLRequest::RequestContext request_context,
-    Callback callback) {
-  static const net::NetworkTrafficAnnotationTag annotation_tag =
-      net::DefineNetworkTrafficAnnotation("content_resource_fetcher", R"(
-    semantics {
-      sender: "content ResourceFetcher"
-      description:
-        "Chrome content API initiated request, which includes network error "
-        "pages and mojo internal component downloader."
-      trigger:
-        "Showing network error pages, or needs to download mojo component."
-      data: "Anything the initiator wants."
-      destination: OTHER
-    }
-    policy {
-      cookies_allowed: YES
-      cookies_store: "user"
-      setting: "These requests cannot be disabled in settings."
-      policy_exception_justification:
-        "Not implemented. Without these requests, Chrome will not work."
-    })");
-
-  mojom::URLLoaderFactory* url_loader_factory =
-      RenderFrame::FromWebFrame(frame)
-          ->GetDefaultURLLoaderFactoryGetter()
-          ->GetNetworkLoaderFactory();
-  DCHECK(url_loader_factory);
-
-  Start(frame, request_context, url_loader_factory, annotation_tag,
-        std::move(callback), kDefaultMaximumDownloadSize);
-}
-
-void ResourceFetcherImpl::Start(
-    blink::WebLocalFrame* frame,
-    blink::WebURLRequest::RequestContext request_context,
     mojom::URLLoaderFactory* url_loader_factory,
     const net::NetworkTrafficAnnotationTag& annotation_tag,
     Callback callback,
diff --git a/content/renderer/fetchers/resource_fetcher_impl.h b/content/renderer/fetchers/resource_fetcher_impl.h
index c9002c3c..7ae48cb 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.h
+++ b/content/renderer/fetchers/resource_fetcher_impl.h
@@ -34,9 +34,6 @@
   void SetHeader(const std::string& header, const std::string& value) override;
   void Start(blink::WebLocalFrame* frame,
              blink::WebURLRequest::RequestContext request_context,
-             Callback callback) override;
-  void Start(blink::WebLocalFrame* frame,
-             blink::WebURLRequest::RequestContext request_context,
              mojom::URLLoaderFactory* url_loader_factory,
              const net::NetworkTrafficAnnotationTag& annotation_tag,
              Callback callback,
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index 820ffab..26e9ee4 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -558,14 +558,19 @@
   chrome->Set(gin::StringToV8(isolate, "gpuBenchmarking"), controller.ToV8());
 }
 
-GpuBenchmarking::GpuBenchmarking(RenderFrameImpl* frame) {
-  frame->GetRemoteInterfaces()->GetInterface(
-      mojo::MakeRequest(&input_injector_));
-}
+GpuBenchmarking::GpuBenchmarking(RenderFrameImpl* frame)
+    : render_frame_(frame) {}
 
 GpuBenchmarking::~GpuBenchmarking() {
 }
 
+void GpuBenchmarking::EnsureRemoteInterface() {
+  if (!input_injector_) {
+    render_frame_->GetRemoteInterfaces()->GetInterface(
+        mojo::MakeRequest(&input_injector_));
+  }
+}
+
 gin::ObjectTemplateBuilder GpuBenchmarking::GetObjectTemplateBuilder(
     v8::Isolate* isolate) {
   return gin::Wrappable<GpuBenchmarking>::GetObjectTemplateBuilder(isolate)
@@ -698,6 +703,7 @@
     return false;
   }
 
+  EnsureRemoteInterface();
   return BeginSmoothScroll(args->isolate(), input_injector_, pixels_to_scroll,
                            callback, gesture_source_type, direction,
                            speed_in_pixels_s, true, start_x, start_y);
@@ -726,6 +732,7 @@
     return false;
   }
 
+  EnsureRemoteInterface();
   return BeginSmoothDrag(args->isolate(), input_injector_, start_x, start_y,
                          end_x, end_y, callback, gesture_source_type,
                          speed_in_pixels_s);
@@ -755,6 +762,7 @@
     return false;
   }
 
+  EnsureRemoteInterface();
   return BeginSmoothScroll(
       args->isolate(), input_injector_, -pixels_to_scroll, callback,
       1,  // TOUCH_INPUT
@@ -824,6 +832,7 @@
     gesture_params.distances.push_back(distance);
     gesture_params.distances.push_back(-distance + overscroll);
   }
+  EnsureRemoteInterface();
   input_injector_->QueueSyntheticSmoothScroll(
       gesture_params, base::BindOnce(&OnSyntheticGestureCompleted,
                                      base::RetainedRef(callback_and_context)));
@@ -866,6 +875,7 @@
   scoped_refptr<CallbackAndContext> callback_and_context =
       new CallbackAndContext(args->isolate(), callback,
                              context.web_frame()->MainWorldScriptContext());
+  EnsureRemoteInterface();
   input_injector_->QueueSyntheticPinch(
       gesture_params, base::BindOnce(&OnSyntheticGestureCompleted,
                                      base::RetainedRef(callback_and_context)));
@@ -966,6 +976,7 @@
   scoped_refptr<CallbackAndContext> callback_and_context =
       new CallbackAndContext(args->isolate(), callback,
                              context.web_frame()->MainWorldScriptContext());
+  EnsureRemoteInterface();
   input_injector_->QueueSyntheticTap(
       gesture_params, base::BindOnce(&OnSyntheticGestureCompleted,
                                      base::RetainedRef(callback_and_context)));
@@ -1006,6 +1017,7 @@
   scoped_refptr<CallbackAndContext> callback_and_context =
       new CallbackAndContext(args->isolate(), callback,
                              context.web_frame()->MainWorldScriptContext());
+  EnsureRemoteInterface();
   input_injector_->QueueSyntheticPointerAction(
       actions_parser.gesture_params(),
       base::BindOnce(&OnSyntheticGestureCompleted,
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.h b/content/renderer/gpu/gpu_benchmarking_extension.h
index 8d03051f..ae06dd0 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.h
+++ b/content/renderer/gpu/gpu_benchmarking_extension.h
@@ -31,6 +31,7 @@
  private:
   explicit GpuBenchmarking(RenderFrameImpl* frame);
   ~GpuBenchmarking() override;
+  void EnsureRemoteInterface();
 
   // gin::Wrappable.
   gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
@@ -64,6 +65,7 @@
   bool HasGpuProcess();
   void GetGpuDriverBugWorkarounds(gin::Arguments* args);
 
+  RenderFrameImpl* render_frame_;
   mojom::InputInjectorPtr input_injector_;
   DISALLOW_COPY_AND_ASSIGN(GpuBenchmarking);
 };
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index d397a43..6413419 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -501,21 +501,10 @@
   // Memory policy on Android WebView does not depend on whether device is
   // low end, so always use default policy.
   if (using_low_memory_policy && !using_synchronous_compositor) {
-    // |using_low_memory_policy| includes both 1GB and 512MB devices. We'd like
-    // the change of the following percentage to be applied only to 512MB
-    // devices.
-    if (base::SysInfo::AmountOfPhysicalMemoryMB() <= 512 &&
-        base::FeatureList::IsEnabled(
-            features::kReducedSoftTileMemoryLimitOnLowEndAndroid)) {
-      // The soft tile memroy limit is computed by multiplying hard limit (8MB)
-      // with this percentage. Seeting this to 13% makes the soft limit ~1MB.
-      settings.max_memory_for_prepaint_percentage = 13;
-    } else {
-      // On low-end we want to be very carefull about killing other
-      // apps. So initially we use 50% more memory to avoid flickering
-      // or raster-on-demand.
-      settings.max_memory_for_prepaint_percentage = 67;
-    }
+    // On low-end we want to be very carefull about killing other
+    // apps. So initially we use 50% more memory to avoid flickering
+    // or raster-on-demand.
+    settings.max_memory_for_prepaint_percentage = 67;
   } else {
     // On other devices we have increased memory excessively to avoid
     // raster-on-demand already, so now we reserve 50% _only_ to avoid
@@ -548,15 +537,13 @@
   }
 
   // On desktop, if there's over 4GB of memory on the machine, increase the
-  // image decode budget to 256MB for both gpu and software.
+  // working set size to 256MB for both gpu and software.
   const int kImageDecodeMemoryThresholdMB = 4 * 1024;
   if (base::SysInfo::AmountOfPhysicalMemoryMB() >=
       kImageDecodeMemoryThresholdMB) {
-    settings.decoded_image_cache_budget_bytes = 256 * 1024 * 1024;
     settings.decoded_image_working_set_budget_bytes = 256 * 1024 * 1024;
   } else {
-    // These are the defaults, but recorded here as well.
-    settings.decoded_image_cache_budget_bytes = 128 * 1024 * 1024;
+    // This is the default, but recorded here as well.
     settings.decoded_image_working_set_budget_bytes = 128 * 1024 * 1024;
   }
 #endif  // defined(OS_ANDROID)
@@ -571,11 +558,6 @@
         !using_synchronous_compositor) {
       settings.preferred_tile_format = viz::RGBA_4444;
     }
-
-    // When running on a low end device, we limit cached bytes to 512KB.
-    // This allows pages which are light on images to stay in cache, but
-    // prevents most long-term caching.
-    settings.decoded_image_cache_budget_bytes = 512 * 1024;
   }
 
   if (cmd.HasSwitch(switches::kEnableLowResTiling))
diff --git a/content/renderer/image_capture/OWNERS b/content/renderer/image_capture/OWNERS
index 6cc0c4e..57aa41f 100644
--- a/content/renderer/image_capture/OWNERS
+++ b/content/renderer/image_capture/OWNERS
@@ -2,3 +2,4 @@
 reillyg@chromium.org
 
 # COMPONENT: Blink>ImageCapture
+# TEAM: media-dev@chromium.org
diff --git a/content/renderer/media/media_stream_dispatcher.cc b/content/renderer/media/media_stream_dispatcher.cc
index 39ec6a3..b83c2a2 100644
--- a/content/renderer/media/media_stream_dispatcher.cc
+++ b/content/renderer/media/media_stream_dispatcher.cc
@@ -19,12 +19,12 @@
 
 namespace {
 
-bool RemoveStreamDeviceFromArray(const StreamDeviceInfo device_info,
-                                 StreamDeviceInfoArray* array) {
-  for (StreamDeviceInfoArray::iterator device_it = array->begin();
-       device_it != array->end(); ++device_it) {
-    if (StreamDeviceInfo::IsEqual(*device_it, device_info)) {
-      array->erase(device_it);
+bool RemoveStreamDeviceFromArray(const MediaStreamDevice& device,
+                                 MediaStreamDevices* devices) {
+  for (MediaStreamDevices::iterator device_it = devices->begin();
+       device_it != devices->end(); ++device_it) {
+    if (device_it->IsSameDevice(device)) {
+      devices->erase(device_it);
       return true;
     }
   }
@@ -60,8 +60,8 @@
   Stream() {}
   ~Stream() {}
   base::WeakPtr<MediaStreamDispatcherEventHandler> handler;
-  StreamDeviceInfoArray audio_array;
-  StreamDeviceInfoArray video_array;
+  MediaStreamDevices audio_devices;
+  MediaStreamDevices video_devices;
 };
 
 MediaStreamDispatcher::MediaStreamDispatcher(RenderFrame* render_frame)
@@ -108,22 +108,21 @@
   }
 }
 
-void MediaStreamDispatcher::StopStreamDevice(
-    const StreamDeviceInfo& device_info) {
-  DVLOG(1) << __func__ << " device_id= " << device_info.device.id;
+void MediaStreamDispatcher::StopStreamDevice(const MediaStreamDevice& device) {
+  DVLOG(1) << __func__ << " device_id= " << device.id;
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  // Remove |device_info| from all streams in |label_stream_map_|.
+  // Remove |device| from all streams in |label_stream_map_|.
   bool device_found = false;
   LabelStreamMap::iterator stream_it = label_stream_map_.begin();
   while (stream_it != label_stream_map_.end()) {
-    StreamDeviceInfoArray& audio_array = stream_it->second.audio_array;
-    StreamDeviceInfoArray& video_array = stream_it->second.video_array;
+    MediaStreamDevices& audio_devices = stream_it->second.audio_devices;
+    MediaStreamDevices& video_devices = stream_it->second.video_devices;
 
-    if (RemoveStreamDeviceFromArray(device_info, &audio_array) ||
-        RemoveStreamDeviceFromArray(device_info, &video_array)) {
+    if (RemoveStreamDeviceFromArray(device, &audio_devices) ||
+        RemoveStreamDeviceFromArray(device, &video_devices)) {
       device_found = true;
-      if (audio_array.empty() && video_array.empty()) {
+      if (audio_devices.empty() && video_devices.empty()) {
         label_stream_map_.erase(stream_it++);
         continue;
       }
@@ -132,8 +131,7 @@
   }
   DCHECK(device_found);
 
-  GetMediaStreamDispatcherHost()->StopStreamDevice(routing_id(),
-                                                   device_info.device.id);
+  GetMediaStreamDispatcherHost()->StopStreamDevice(routing_id(), device.id);
 }
 
 void MediaStreamDispatcher::OpenDevice(
@@ -182,14 +180,9 @@
 MediaStreamDevices MediaStreamDispatcher::GetNonScreenCaptureDevices() {
   MediaStreamDevices video_devices;
   for (const auto& stream_it : label_stream_map_) {
-    for (const auto& video_device_info : stream_it.second.video_array) {
-      if (!IsScreenCaptureMediaType(video_device_info.device.type)) {
-        // TODO(c.padhi): Remove this when |video_device_info|'s type is changed
-        // to MediaStreamDevice, see https://crbug.com/760493.
-        MediaStreamDevice video_device = video_device_info.device;
-        video_device.session_id = video_device_info.session_id;
+    for (const auto& video_device : stream_it.second.video_devices) {
+      if (!IsScreenCaptureMediaType(video_device.type))
         video_devices.push_back(video_device);
-      }
     }
   }
   return video_devices;
@@ -208,8 +201,8 @@
 void MediaStreamDispatcher::OnStreamGenerated(
     int32_t request_id,
     const std::string& label,
-    const StreamDeviceInfoArray& audio_array,
-    const StreamDeviceInfoArray& video_array) {
+    const MediaStreamDevices& audio_devices,
+    const MediaStreamDevices& video_devices) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   for (auto it = requests_.begin(); it != requests_.end(); ++it) {
@@ -218,12 +211,12 @@
       continue;
     Stream new_stream;
     new_stream.handler = request.handler;
-    new_stream.audio_array = audio_array;
-    new_stream.video_array = video_array;
+    new_stream.audio_devices = audio_devices;
+    new_stream.video_devices = video_devices;
     label_stream_map_[label] = new_stream;
     if (request.handler.get()) {
-      request.handler->OnStreamGenerated(request.request_id, label, audio_array,
-                                         video_array);
+      request.handler->OnStreamGenerated(request.request_id, label,
+                                         audio_devices, video_devices);
       DVLOG(1) << __func__ << " request_id=" << request.request_id
                << " label=" << label;
     }
@@ -250,10 +243,9 @@
   }
 }
 
-void MediaStreamDispatcher::OnDeviceOpened(
-    int32_t request_id,
-    const std::string& label,
-    const StreamDeviceInfo& device_info) {
+void MediaStreamDispatcher::OnDeviceOpened(int32_t request_id,
+                                           const std::string& label,
+                                           const MediaStreamDevice& device) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   for (auto it = requests_.begin(); it != requests_.end(); ++it) {
@@ -262,16 +254,16 @@
       continue;
     Stream new_stream;
     new_stream.handler = request.handler;
-    if (IsAudioInputMediaType(device_info.device.type))
-      new_stream.audio_array.push_back(device_info);
-    else if (IsVideoMediaType(device_info.device.type))
-      new_stream.video_array.push_back(device_info);
+    if (IsAudioInputMediaType(device.type))
+      new_stream.audio_devices.push_back(device);
+    else if (IsVideoMediaType(device.type))
+      new_stream.video_devices.push_back(device);
     else
       NOTREACHED();
 
     label_stream_map_[label] = new_stream;
     if (request.handler.get()) {
-      request.handler->OnDeviceOpened(request.request_id, label, device_info);
+      request.handler->OnDeviceOpened(request.request_id, label, device);
       DVLOG(1) << __func__ << " request_id=" << request.request_id
                << " label=" << label;
     }
@@ -296,11 +288,9 @@
   }
 }
 
-void MediaStreamDispatcher::OnDeviceStopped(
-    const std::string& label,
-    const StreamDeviceInfo& device_info) {
-  DVLOG(1) << __func__ << " label=" << label
-           << " device_id=" << device_info.device.id;
+void MediaStreamDispatcher::OnDeviceStopped(const std::string& label,
+                                            const MediaStreamDevice& device) {
+  DVLOG(1) << __func__ << " label=" << label << " device_id=" << device.id;
   DCHECK(thread_checker_.CalledOnValidThread());
 
   LabelStreamMap::iterator it = label_stream_map_.find(label);
@@ -310,13 +300,13 @@
     return;
   }
   Stream* stream = &it->second;
-  if (IsAudioInputMediaType(device_info.device.type))
-    RemoveStreamDeviceFromArray(device_info, &stream->audio_array);
+  if (IsAudioInputMediaType(device.type))
+    RemoveStreamDeviceFromArray(device, &stream->audio_devices);
   else
-    RemoveStreamDeviceFromArray(device_info, &stream->video_array);
+    RemoveStreamDeviceFromArray(device, &stream->video_devices);
 
   if (stream->handler.get())
-    stream->handler->OnDeviceStopped(label, device_info);
+    stream->handler->OnDeviceStopped(label, device);
 
   // |it| could have already been invalidated in the function call above. So we
   // need to check if |label| is still in |label_stream_map_| again.
@@ -327,7 +317,7 @@
   if (it == label_stream_map_.end())
     return;
   stream = &it->second;
-  if (stream->audio_array.empty() && stream->video_array.empty())
+  if (stream->audio_devices.empty() && stream->video_devices.empty())
     label_stream_map_.erase(it);
 }
 
@@ -353,10 +343,10 @@
 
   LabelStreamMap::iterator it = label_stream_map_.find(label);
   if (it == label_stream_map_.end() ||
-      it->second.audio_array.size() <= static_cast<size_t>(index)) {
-    return StreamDeviceInfo::kNoId;
+      it->second.audio_devices.size() <= static_cast<size_t>(index)) {
+    return MediaStreamDevice::kNoId;
   }
-  return it->second.audio_array[index].session_id;
+  return it->second.audio_devices[index].session_id;
 }
 
 bool MediaStreamDispatcher::IsStream(const std::string& label) {
@@ -371,10 +361,10 @@
 
   LabelStreamMap::iterator it = label_stream_map_.find(label);
   if (it == label_stream_map_.end() ||
-      it->second.video_array.size() <= static_cast<size_t>(index)) {
-    return StreamDeviceInfo::kNoId;
+      it->second.video_devices.size() <= static_cast<size_t>(index)) {
+    return MediaStreamDevice::kNoId;
   }
-  return it->second.video_array[index].session_id;
+  return it->second.video_devices[index].session_id;
 }
 
 }  // namespace content
diff --git a/content/renderer/media/media_stream_dispatcher.h b/content/renderer/media/media_stream_dispatcher.h
index b7ad1c9..3a763b7 100644
--- a/content/renderer/media/media_stream_dispatcher.h
+++ b/content/renderer/media/media_stream_dispatcher.h
@@ -17,7 +17,7 @@
 #include "base/threading/thread_checker.h"
 #include "content/common/content_export.h"
 #include "content/common/media/media_stream.mojom.h"
-#include "content/common/media/media_stream_options.h"
+#include "content/public/common/media_stream_request.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
@@ -58,7 +58,7 @@
       const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler);
 
   // Stop a started device that has been requested by calling GenerateStream.
-  virtual void StopStreamDevice(const StreamDeviceInfo& device_info);
+  virtual void StopStreamDevice(const MediaStreamDevice& device);
 
   // Request to open a device.
   void OpenDevice(
@@ -117,16 +117,16 @@
   // mojom::MediaStreamDispatcher implementation.
   void OnStreamGenerated(int32_t request_id,
                          const std::string& label,
-                         const StreamDeviceInfoArray& audio_array,
-                         const StreamDeviceInfoArray& video_array) override;
+                         const MediaStreamDevices& audio_devices,
+                         const MediaStreamDevices& video_devices) override;
   void OnStreamGenerationFailed(int32_t request_id,
                                 MediaStreamRequestResult result) override;
   void OnDeviceOpened(int32_t request_id,
                       const std::string& label,
-                      const StreamDeviceInfo& device_info) override;
+                      const MediaStreamDevice& device) override;
   void OnDeviceOpenFailed(int32_t request_id) override;
   void OnDeviceStopped(const std::string& label,
-                       const StreamDeviceInfo& device_info) override;
+                       const MediaStreamDevice& device) override;
 
   void BindMediaStreamDispatcherRequest(
       mojom::MediaStreamDispatcherRequest request);
diff --git a/content/renderer/media/media_stream_dispatcher_eventhandler.h b/content/renderer/media/media_stream_dispatcher_eventhandler.h
index 7029bcb6..f5b663e 100644
--- a/content/renderer/media/media_stream_dispatcher_eventhandler.h
+++ b/content/renderer/media/media_stream_dispatcher_eventhandler.h
@@ -8,35 +8,31 @@
 #include <string>
 
 #include "content/common/content_export.h"
-#include "content/common/media/media_stream_options.h"
+#include "content/public/common/media_stream_request.h"
 
 namespace content {
 
 class CONTENT_EXPORT MediaStreamDispatcherEventHandler {
  public:
   // A new media stream have been created.
-  virtual void OnStreamGenerated(
-      int request_id,
-      const std::string& label,
-      const StreamDeviceInfoArray& audio_device_array,
-      const StreamDeviceInfoArray& video_device_array) = 0;
+  virtual void OnStreamGenerated(int request_id,
+                                 const std::string& label,
+                                 const MediaStreamDevices& audio_devices,
+                                 const MediaStreamDevices& video_devices) = 0;
 
   // Creation of a new media stream failed. The user might have denied access
   // to the requested devices or no device is available.
-  virtual void OnStreamGenerationFailed(
-      int request_id,
-      content::MediaStreamRequestResult result) = 0;
+  virtual void OnStreamGenerationFailed(int request_id,
+                                        MediaStreamRequestResult result) = 0;
 
   // A device has been stopped in the browser processes.
-  virtual void OnDeviceStopped(
-      const std::string& label,
-      const StreamDeviceInfo& device_info) = 0;
+  virtual void OnDeviceStopped(const std::string& label,
+                               const MediaStreamDevice& device) = 0;
 
   // A device has been opened.
-  virtual void OnDeviceOpened(
-      int request_id,
-      const std::string& label,
-      const StreamDeviceInfo& device_info) = 0;
+  virtual void OnDeviceOpened(int request_id,
+                              const std::string& label,
+                              const MediaStreamDevice& device) = 0;
 
   // Failed to open the device.
   virtual void OnDeviceOpenFailed(int request_id) = 0;
diff --git a/content/renderer/media/media_stream_dispatcher_unittest.cc b/content/renderer/media/media_stream_dispatcher_unittest.cc
index 9651761f..88c7fd3 100644
--- a/content/renderer/media/media_stream_dispatcher_unittest.cc
+++ b/content/renderer/media/media_stream_dispatcher_unittest.cc
@@ -33,20 +33,19 @@
  public:
   MockMediaStreamDispatcherEventHandler() : request_id_(-1) {}
 
-  void OnStreamGenerated(
-      int request_id,
-      const std::string& label,
-      const StreamDeviceInfoArray& audio_device_array,
-      const StreamDeviceInfoArray& video_device_array) override {
+  void OnStreamGenerated(int request_id,
+                         const std::string& label,
+                         const MediaStreamDevices& audio_devices,
+                         const MediaStreamDevices& video_devices) override {
     request_id_ = request_id;
     label_ = label;
-    if (audio_device_array.size()) {
-      DCHECK(audio_device_array.size() == 1);
-      audio_device_ = audio_device_array[0];
+    if (audio_devices.size()) {
+      DCHECK(audio_devices.size() == 1);
+      audio_device_ = audio_devices[0];
     }
-    if (video_device_array.size()) {
-      DCHECK(video_device_array.size() == 1);
-      video_device_ = video_device_array[0];
+    if (video_devices.size()) {
+      DCHECK(video_devices.size() == 1);
+      video_device_ = video_devices[0];
     }
   }
 
@@ -56,19 +55,17 @@
   }
 
   void OnDeviceStopped(const std::string& label,
-                       const StreamDeviceInfo& device_info) override {
+                       const MediaStreamDevice& device) override {
     device_stopped_label_ = label;
-    if (IsVideoMediaType(device_info.device.type)) {
-      EXPECT_TRUE(StreamDeviceInfo::IsEqual(video_device_, device_info));
-    }
-    if (IsAudioInputMediaType(device_info.device.type)) {
-      EXPECT_TRUE(StreamDeviceInfo::IsEqual(audio_device_, device_info));
-    }
+    if (IsVideoMediaType(device.type))
+      EXPECT_TRUE(device.IsSameDevice(video_device_));
+    if (IsAudioInputMediaType(device.type))
+      EXPECT_TRUE(device.IsSameDevice(audio_device_));
   }
 
   void OnDeviceOpened(int request_id,
                       const std::string& label,
-                      const StreamDeviceInfo& video_device) override {
+                      const MediaStreamDevice& device) override {
     request_id_ = request_id;
     label_ = label;
   }
@@ -79,15 +76,15 @@
     request_id_ = -1;
     label_.clear();
     device_stopped_label_.clear();
-    audio_device_ = StreamDeviceInfo();
-    video_device_ = StreamDeviceInfo();
+    audio_device_ = MediaStreamDevice();
+    video_device_ = MediaStreamDevice();
   }
 
   int request_id_;
   std::string label_;
   std::string device_stopped_label_;
-  StreamDeviceInfo audio_device_;
-  StreamDeviceInfo video_device_;
+  MediaStreamDevice audio_device_;
+  MediaStreamDevice video_device_;
 };
 
 class MediaStreamDispatcherTest : public ::testing::Test {
@@ -116,29 +113,28 @@
   // |ipc_id| must be the the id returned by GenerateStream.
   std::string CompleteGenerateStream(int ipc_id,
                                      int request_id) {
-    StreamDeviceInfoArray audio_device_array(controls_.audio.requested ? 1 : 0);
+    MediaStreamDevices audio_devices(controls_.audio.requested ? 1 : 0);
     if (controls_.audio.requested) {
-      StreamDeviceInfo audio_device_info;
-      audio_device_info.device.name = "Microphone";
-      audio_device_info.device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
-      audio_device_info.session_id = kAudioSessionId;
-      audio_device_array[0] = audio_device_info;
+      MediaStreamDevice audio_device;
+      audio_device.name = "Microphone";
+      audio_device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
+      audio_device.session_id = kAudioSessionId;
+      audio_devices[0] = audio_device;
     }
 
-    StreamDeviceInfoArray video_device_array(controls_.video.requested ? 1 : 0);
+    MediaStreamDevices video_devices(controls_.video.requested ? 1 : 0);
     if (controls_.video.requested) {
-      StreamDeviceInfo video_device_info;
-      video_device_info.device.name = "Camera";
-      video_device_info.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
-      video_device_info.session_id = kVideoSessionId;
-      video_device_array[0] = video_device_info;
+      MediaStreamDevice video_device;
+      video_device.name = "Camera";
+      video_device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
+      video_device.session_id = kVideoSessionId;
+      video_devices[0] = video_device;
     }
 
     std::string label = "stream" + base::IntToString(ipc_id);
 
     handler_->ResetStoredParameters();
-    dispatcher_->OnStreamGenerated(ipc_id, label, audio_device_array,
-                                   video_device_array);
+    dispatcher_->OnStreamGenerated(ipc_id, label, audio_devices, video_devices);
 
     EXPECT_EQ(handler_->request_id_, request_id);
     EXPECT_EQ(handler_->label_, label);
@@ -177,53 +173,43 @@
   // Stop the actual audio device and verify that there is no valid
   // |session_id|.
   dispatcher_->StopStreamDevice(handler_->audio_device_);
-  EXPECT_EQ(dispatcher_->audio_session_id(label1, 0),
-            StreamDeviceInfo::kNoId);
-  EXPECT_EQ(dispatcher_->audio_session_id(label2, 0),
-            StreamDeviceInfo::kNoId);
+  EXPECT_EQ(dispatcher_->audio_session_id(label1, 0), MediaStreamDevice::kNoId);
+  EXPECT_EQ(dispatcher_->audio_session_id(label2, 0), MediaStreamDevice::kNoId);
 
   // Stop the actual video device and verify that there is no valid
   // |session_id|.
   dispatcher_->StopStreamDevice(handler_->video_device_);
-  EXPECT_EQ(dispatcher_->video_session_id(label1, 0),
-            StreamDeviceInfo::kNoId);
-  EXPECT_EQ(dispatcher_->video_session_id(label2, 0),
-            StreamDeviceInfo::kNoId);
+  EXPECT_EQ(dispatcher_->video_session_id(label1, 0), MediaStreamDevice::kNoId);
+  EXPECT_EQ(dispatcher_->video_session_id(label2, 0), MediaStreamDevice::kNoId);
 }
 
 TEST_F(MediaStreamDispatcherTest, BasicVideoDevice) {
-  StreamDeviceInfoArray video_device_array(1);
-  StreamDeviceInfo video_device_info;
-  video_device_info.device.name = "Camera";
-  video_device_info.device.id = "device_path";
-  video_device_info.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
-  video_device_info.session_id = kVideoSessionId;
-  video_device_array[0] = video_device_info;
+  MediaStreamDevice video_device;
+  video_device.name = "Camera";
+  video_device.id = "device_path";
+  video_device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
+  video_device.session_id = kVideoSessionId;
 
   EXPECT_EQ(dispatcher_->requests_.size(), size_t(0));
   EXPECT_EQ(dispatcher_->label_stream_map_.size(), size_t(0));
 
   int ipc_request_id1 = dispatcher_->next_ipc_id_;
-  dispatcher_->OpenDevice(kRequestId1, handler_->AsWeakPtr(),
-                          video_device_info.device.id,
+  dispatcher_->OpenDevice(kRequestId1, handler_->AsWeakPtr(), video_device.id,
                           MEDIA_DEVICE_VIDEO_CAPTURE, security_origin_);
   int ipc_request_id2 = dispatcher_->next_ipc_id_;
   EXPECT_NE(ipc_request_id1, ipc_request_id2);
-  dispatcher_->OpenDevice(kRequestId2, handler_->AsWeakPtr(),
-                          video_device_info.device.id,
+  dispatcher_->OpenDevice(kRequestId2, handler_->AsWeakPtr(), video_device.id,
                           MEDIA_DEVICE_VIDEO_CAPTURE, security_origin_);
   EXPECT_EQ(dispatcher_->requests_.size(), size_t(2));
 
   // Complete the OpenDevice of request 1.
   std::string stream_label1 = std::string("stream1");
-  dispatcher_->OnDeviceOpened(ipc_request_id1, stream_label1,
-                              video_device_info);
+  dispatcher_->OnDeviceOpened(ipc_request_id1, stream_label1, video_device);
   EXPECT_EQ(handler_->request_id_, kRequestId1);
 
   // Complete the OpenDevice of request 2.
   std::string stream_label2 = std::string("stream2");
-  dispatcher_->OnDeviceOpened(ipc_request_id2, stream_label2,
-                              video_device_info);
+  dispatcher_->OnDeviceOpened(ipc_request_id2, stream_label2, video_device);
   EXPECT_EQ(handler_->request_id_, kRequestId2);
 
   EXPECT_EQ(dispatcher_->requests_.size(), size_t(0));
@@ -236,12 +222,12 @@
   // Close the device from request 2.
   dispatcher_->CloseDevice(stream_label2);
   EXPECT_EQ(dispatcher_->video_session_id(stream_label2, 0),
-            StreamDeviceInfo::kNoId);
+            MediaStreamDevice::kNoId);
 
   // Close the device from request 1.
   dispatcher_->CloseDevice(stream_label1);
   EXPECT_EQ(dispatcher_->video_session_id(stream_label1, 0),
-            StreamDeviceInfo::kNoId);
+            MediaStreamDevice::kNoId);
   EXPECT_EQ(dispatcher_->label_stream_map_.size(), size_t(0));
 
   // Verify that the request have been completed.
@@ -262,24 +248,24 @@
   // Create a new stream.
   ipc_request_id1 = GenerateStream(kRequestId1);
 
-  StreamDeviceInfoArray audio_device_array(1);
-  StreamDeviceInfo audio_device_info;
-  audio_device_info.device.name = "Microphone";
-  audio_device_info.device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
-  audio_device_info.session_id = kAudioSessionId;
-  audio_device_array[0] = audio_device_info;
+  MediaStreamDevices audio_devices(1);
+  MediaStreamDevice audio_device;
+  audio_device.name = "Microphone";
+  audio_device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
+  audio_device.session_id = kAudioSessionId;
+  audio_devices[0] = audio_device;
 
-  StreamDeviceInfoArray video_device_array(1);
-  StreamDeviceInfo video_device_info;
-  video_device_info.device.name = "Camera";
-  video_device_info.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
-  video_device_info.session_id = kVideoSessionId;
-  video_device_array[0] = video_device_info;
+  MediaStreamDevices video_devices(1);
+  MediaStreamDevice video_device;
+  video_device.name = "Camera";
+  video_device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
+  video_device.session_id = kVideoSessionId;
+  video_devices[0] = video_device;
 
   // Complete the creation of stream1.
   std::string stream_label1 = std::string("stream1");
-  dispatcher_->OnStreamGenerated(ipc_request_id1, stream_label1,
-                                 audio_device_array, video_device_array);
+  dispatcher_->OnStreamGenerated(ipc_request_id1, stream_label1, audio_devices,
+                                 video_devices);
   EXPECT_EQ(handler_->request_id_, kRequestId1);
   EXPECT_EQ(handler_->label_, stream_label1);
   EXPECT_EQ(dispatcher_->video_session_id(stream_label1, 0), kVideoSessionId);
@@ -294,23 +280,23 @@
   EXPECT_EQ(1u, dispatcher_->requests_.size());
 
   // Complete the creation of stream1.
-  StreamDeviceInfo audio_device_info;
-  audio_device_info.device.name = "Microphone";
-  audio_device_info.device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
-  audio_device_info.session_id = kAudioSessionId;
-  StreamDeviceInfoArray audio_device_array(1);
-  audio_device_array[0] = audio_device_info;
+  MediaStreamDevice audio_device;
+  audio_device.name = "Microphone";
+  audio_device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
+  audio_device.session_id = kAudioSessionId;
+  MediaStreamDevices audio_devices(1);
+  audio_devices[0] = audio_device;
 
-  StreamDeviceInfo video_device_info;
-  video_device_info.device.name = "Camera";
-  video_device_info.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
-  video_device_info.session_id = kVideoSessionId;
-  StreamDeviceInfoArray video_device_array(1);
-  video_device_array[0] = video_device_info;
+  MediaStreamDevice video_device;
+  video_device.name = "Camera";
+  video_device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
+  video_device.session_id = kVideoSessionId;
+  MediaStreamDevices video_devices(1);
+  video_devices[0] = video_device;
 
   std::string stream_label1 = "stream1";
-  dispatcher_->OnStreamGenerated(ipc_request_id1, stream_label1,
-                                 audio_device_array, video_device_array);
+  dispatcher_->OnStreamGenerated(ipc_request_id1, stream_label1, audio_devices,
+                                 video_devices);
   EXPECT_EQ(handler_->request_id_, kRequestId1);
   EXPECT_EQ(handler_->label_, stream_label1);
   EXPECT_EQ(0u, dispatcher_->requests_.size());
@@ -327,47 +313,42 @@
   // Verify that MediaStreamDispatcherEventHandler::OnDeviceStopped has been
   // called.
   EXPECT_EQ(label, handler_->device_stopped_label_);
-  EXPECT_EQ(dispatcher_->video_session_id(label, 0),
-            StreamDeviceInfo::kNoId);
+  EXPECT_EQ(dispatcher_->video_session_id(label, 0), MediaStreamDevice::kNoId);
 }
 
 TEST_F(MediaStreamDispatcherTest, GetNonScreenCaptureDevices) {
-  StreamDeviceInfo video_device_info;
-  video_device_info.device.name = "Camera";
-  video_device_info.device.id = "device_path";
-  video_device_info.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
-  video_device_info.session_id = kVideoSessionId;
+  MediaStreamDevice video_device;
+  video_device.name = "Camera";
+  video_device.id = "device_path";
+  video_device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
+  video_device.session_id = kVideoSessionId;
 
-  StreamDeviceInfo screen_device_info;
-  screen_device_info.device.name = "Screen";
-  screen_device_info.device.id = "screen_capture";
-  screen_device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
-  screen_device_info.session_id = kScreenSessionId;
+  MediaStreamDevice screen_device;
+  screen_device.name = "Screen";
+  screen_device.id = "screen_capture";
+  screen_device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
+  screen_device.session_id = kScreenSessionId;
 
   EXPECT_EQ(dispatcher_->requests_.size(), 0u);
   EXPECT_EQ(dispatcher_->label_stream_map_.size(), 0u);
 
   int ipc_request_id1 = dispatcher_->next_ipc_id_;
-  dispatcher_->OpenDevice(kRequestId1, handler_->AsWeakPtr(),
-                          video_device_info.device.id,
+  dispatcher_->OpenDevice(kRequestId1, handler_->AsWeakPtr(), video_device.id,
                           MEDIA_DEVICE_VIDEO_CAPTURE, security_origin_);
   int ipc_request_id2 = dispatcher_->next_ipc_id_;
   EXPECT_NE(ipc_request_id1, ipc_request_id2);
-  dispatcher_->OpenDevice(kRequestId2, handler_->AsWeakPtr(),
-                          screen_device_info.device.id,
+  dispatcher_->OpenDevice(kRequestId2, handler_->AsWeakPtr(), screen_device.id,
                           MEDIA_DESKTOP_VIDEO_CAPTURE, security_origin_);
   EXPECT_EQ(dispatcher_->requests_.size(), 2u);
 
   // Complete the OpenDevice of request 1.
   std::string stream_label1 = std::string("stream1");
-  dispatcher_->OnDeviceOpened(ipc_request_id1, stream_label1,
-                              video_device_info);
+  dispatcher_->OnDeviceOpened(ipc_request_id1, stream_label1, video_device);
   EXPECT_EQ(handler_->request_id_, kRequestId1);
 
   // Complete the OpenDevice of request 2.
   std::string stream_label2 = std::string("stream2");
-  dispatcher_->OnDeviceOpened(ipc_request_id2, stream_label2,
-                              screen_device_info);
+  dispatcher_->OnDeviceOpened(ipc_request_id2, stream_label2, screen_device);
   EXPECT_EQ(handler_->request_id_, kRequestId2);
 
   EXPECT_EQ(dispatcher_->requests_.size(), 0u);
@@ -380,12 +361,12 @@
   // Close the device from request 2.
   dispatcher_->CloseDevice(stream_label2);
   EXPECT_EQ(dispatcher_->video_session_id(stream_label2, 0),
-            StreamDeviceInfo::kNoId);
+            MediaStreamDevice::kNoId);
 
   // Close the device from request 1.
   dispatcher_->CloseDevice(stream_label1);
   EXPECT_EQ(dispatcher_->video_session_id(stream_label1, 0),
-            StreamDeviceInfo::kNoId);
+            MediaStreamDevice::kNoId);
 
   // Verify that the request have been completed.
   EXPECT_EQ(dispatcher_->label_stream_map_.size(), 0u);
diff --git a/content/renderer/media/mock_media_stream_dispatcher.cc b/content/renderer/media/mock_media_stream_dispatcher.cc
index 6d6ff0cd..e2fd636b 100644
--- a/content/renderer/media/mock_media_stream_dispatcher.cc
+++ b/content/renderer/media/mock_media_stream_dispatcher.cc
@@ -5,7 +5,6 @@
 #include "content/renderer/media/mock_media_stream_dispatcher.h"
 
 #include "base/strings/string_number_conversions.h"
-#include "content/public/common/media_stream_request.h"
 #include "media/base/audio_parameters.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -16,7 +15,7 @@
 namespace content {
 
 MockMediaStreamDispatcher::MockMediaStreamDispatcher()
-    : MediaStreamDispatcher(NULL),
+    : MediaStreamDispatcher(nullptr),
       audio_input_request_id_(-1),
       request_stream_counter_(0),
       stop_audio_device_counter_(0),
@@ -37,11 +36,11 @@
   audio_input_request_id_ = request_id;
 
   stream_label_ = "local_stream" + base::IntToString(request_id);
-  audio_input_array_.clear();
-  video_array_.clear();
+  audio_devices_.clear();
+  video_devices_.clear();
 
   if (controls.audio.requested) {
-    AddAudioInputDeviceToArray(false, controls.audio.device_id);
+    AddAudioDeviceToArray(false, controls.audio.device_id);
   }
   if (controls.video.requested) {
     AddVideoDeviceToArray(true, controls.video.device_id);
@@ -56,12 +55,12 @@
 }
 
 void MockMediaStreamDispatcher::StopStreamDevice(
-    const StreamDeviceInfo& device_info) {
-  if (IsAudioInputMediaType(device_info.device.type)) {
+    const MediaStreamDevice& device) {
+  if (IsAudioInputMediaType(device.type)) {
     ++stop_audio_device_counter_;
     return;
   }
-  if (IsVideoMediaType(device_info.device.type)) {
+  if (IsVideoMediaType(device.type)) {
     ++stop_video_device_counter_;
     return;
   }
@@ -82,37 +81,37 @@
   return -1;
 }
 
-void MockMediaStreamDispatcher::AddAudioInputDeviceToArray(
+void MockMediaStreamDispatcher::AddAudioDeviceToArray(
     bool matched_output,
     const std::string& device_id) {
-  StreamDeviceInfo audio;
-  audio.device.id = test_same_id_ ? "test_id" : device_id;
-  audio.device.id = audio.device.id + base::IntToString(session_id_);
-  audio.device.name = "microphone";
-  audio.device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
-  audio.device.video_facing = media::MEDIA_VIDEO_FACING_NONE;
+  MediaStreamDevice audio_device;
+  audio_device.id =
+      (test_same_id_ ? "test_id" : device_id) + base::IntToString(session_id_);
+  audio_device.name = "microphone";
+  audio_device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
+  audio_device.video_facing = media::MEDIA_VIDEO_FACING_NONE;
   if (matched_output) {
-    audio.device.matched_output_device_id =
+    audio_device.matched_output_device_id =
         kAudioOutputDeviceIdPrefix + base::IntToString(session_id_);
   }
-  audio.session_id = session_id_;
-  audio.device.input = media::AudioParameters::UnavailableDeviceParams();
-  audio_input_array_.push_back(audio);
+  audio_device.session_id = session_id_;
+  audio_device.input = media::AudioParameters::UnavailableDeviceParams();
+  audio_devices_.push_back(audio_device);
 }
 
 void MockMediaStreamDispatcher::AddVideoDeviceToArray(
     bool facing_user,
     const std::string& device_id) {
-  StreamDeviceInfo video;
-  video.device.id = test_same_id_ ? "test_id" : device_id;
-  video.device.id = video.device.id + base::IntToString(session_id_);
-  video.device.name = "usb video camera";
-  video.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
-  video.device.video_facing = facing_user
+  MediaStreamDevice video_device;
+  video_device.id =
+      (test_same_id_ ? "test_id" : device_id) + base::IntToString(session_id_);
+  video_device.name = "usb video camera";
+  video_device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
+  video_device.video_facing = facing_user
                                   ? media::MEDIA_VIDEO_FACING_USER
                                   : media::MEDIA_VIDEO_FACING_ENVIRONMENT;
-  video.session_id = session_id_;
-  video_array_.push_back(video);
+  video_device.session_id = session_id_;
+  video_devices_.push_back(video_device);
 }
 
 }  // namespace content
diff --git a/content/renderer/media/mock_media_stream_dispatcher.h b/content/renderer/media/mock_media_stream_dispatcher.h
index f84df36..f8610747 100644
--- a/content/renderer/media/mock_media_stream_dispatcher.h
+++ b/content/renderer/media/mock_media_stream_dispatcher.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "content/public/common/media_stream_request.h"
 #include "content/renderer/media/media_stream_dispatcher.h"
 #include "url/origin.h"
 
@@ -29,7 +30,7 @@
       int request_id,
       const base::WeakPtr<MediaStreamDispatcherEventHandler>& event_handler)
       override;
-  void StopStreamDevice(const StreamDeviceInfo& device_info) override;
+  void StopStreamDevice(const MediaStreamDevice& device) override;
   bool IsStream(const std::string& label) override;
   int video_session_id(const std::string& label, int index) override;
   int audio_session_id(const std::string& label, int index) override;
@@ -43,14 +44,11 @@
   int stop_video_device_counter() const { return stop_video_device_counter_; }
 
   const std::string& stream_label() const { return stream_label_;}
-  const StreamDeviceInfoArray& audio_input_array() const {
-    return audio_input_array_;
-  }
-  const StreamDeviceInfoArray& video_array() const { return video_array_; }
+  const MediaStreamDevices& audio_devices() const { return audio_devices_; }
+  const MediaStreamDevices& video_devices() const { return video_devices_; }
 
  private:
-  void AddAudioInputDeviceToArray(bool matched_output,
-                                  const std::string& device_id);
+  void AddAudioDeviceToArray(bool matched_output, const std::string& device_id);
   void AddVideoDeviceToArray(bool facing_user, const std::string& device_id);
 
   int audio_input_request_id_;
@@ -62,8 +60,8 @@
   std::string stream_label_;
   int session_id_;
   bool test_same_id_;
-  StreamDeviceInfoArray audio_input_array_;
-  StreamDeviceInfoArray video_array_;
+  MediaStreamDevices audio_devices_;
+  MediaStreamDevices video_devices_;
 
   DISALLOW_COPY_AND_ASSIGN(MockMediaStreamDispatcher);
 };
diff --git a/content/renderer/media/mock_peer_connection_impl.cc b/content/renderer/media/mock_peer_connection_impl.cc
index a962a4a..c667604 100644
--- a/content/renderer/media/mock_peer_connection_impl.cc
+++ b/content/renderer/media/mock_peer_connection_impl.cc
@@ -116,8 +116,7 @@
   int inter_tone_gap_;
 };
 
-class FakeRtpReceiver
-    : public rtc::RefCountedObject<webrtc::RtpReceiverInterface> {
+class FakeRtpReceiver : public webrtc::RtpReceiverInterface {
  public:
   FakeRtpReceiver(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track)
       : track_(track) {}
@@ -213,10 +212,12 @@
   std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers;
   for (size_t i = 0; i < remote_streams_->count(); ++i) {
     for (const auto& audio_track : remote_streams_->at(i)->GetAudioTracks()) {
-      receivers.push_back(new FakeRtpReceiver(audio_track));
+      receivers.push_back(
+          new rtc::RefCountedObject<FakeRtpReceiver>(audio_track));
     }
     for (const auto& video_track : remote_streams_->at(i)->GetVideoTracks()) {
-      receivers.push_back(new FakeRtpReceiver(video_track));
+      receivers.push_back(
+          new rtc::RefCountedObject<FakeRtpReceiver>(video_track));
     }
   }
   return receivers;
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 56e9c969..cb6321a 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -925,23 +925,29 @@
   return handlers;
 }
 
-bool IsReceiverForStream(
-    const rtc::scoped_refptr<webrtc::RtpReceiverInterface>& webrtc_receiver,
-    const scoped_refptr<webrtc::MediaStreamInterface>& webrtc_stream) {
-  rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track =
-      webrtc_receiver->track();
-  if (webrtc_track->kind() == webrtc::MediaStreamTrackInterface::kAudioKind) {
-    for (const auto& track : webrtc_stream->GetAudioTracks()) {
-      if (webrtc_track == track)
-        return true;
-    }
-  } else {
-    for (const auto& track : webrtc_stream->GetVideoTracks()) {
-      if (webrtc_track == track)
-        return true;
-    }
+rtc::scoped_refptr<webrtc::RtpReceiverInterface> FindReceiverForTrack(
+    const std::string& track_id,
+    const std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>>&
+        webrtc_receivers) {
+  for (const auto& webrtc_receiver : webrtc_receivers) {
+    if (webrtc_receiver->track()->id() == track_id)
+      return webrtc_receiver;
   }
-  return false;
+  return nullptr;
+}
+
+std::unique_ptr<RTCRtpReceiver> CreateRTCRtpReceiverForTrack(
+    webrtc::MediaStreamTrackInterface* webrtc_track,
+    const std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>>&
+        webrtc_receivers,
+    scoped_refptr<WebRtcMediaStreamTrackAdapterMap> track_adapter_map) {
+  auto webrtc_receiver =
+      FindReceiverForTrack(webrtc_track->id(), webrtc_receivers);
+  DCHECK(webrtc_receiver);
+  auto track_adapter = track_adapter_map->GetRemoteTrackAdapter(webrtc_track);
+  DCHECK(track_adapter);
+  return base::MakeUnique<RTCRtpReceiver>(std::move(webrtc_receiver),
+                                          std::move(track_adapter));
 }
 
 }  // namespace
@@ -995,10 +1001,15 @@
   Observer(const base::WeakPtr<RTCPeerConnectionHandler>& handler)
       : handler_(handler),
         main_thread_(base::ThreadTaskRunnerHandle::Get()),
-        track_adapter_map_(handler_->track_adapter_map_) {
+        track_adapter_map_(handler_->track_adapter_map_),
+        native_peer_connection_(nullptr) {
     DCHECK(track_adapter_map_);
   }
 
+  void Initialize(webrtc::PeerConnectionInterface* native_peer_connection) {
+    native_peer_connection_ = native_peer_connection;
+  }
+
  protected:
   friend class base::RefCountedThreadSafe<RTCPeerConnectionHandler::Observer>;
   virtual ~Observer() {}
@@ -1015,18 +1026,41 @@
     }
   }
 
-  void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) override {
-    DCHECK(stream);
+  void OnAddStream(
+      rtc::scoped_refptr<MediaStreamInterface> webrtc_stream) override {
+    DCHECK(webrtc_stream);
+    DCHECK(native_peer_connection_);
+    DCHECK(!main_thread_->BelongsToCurrentThread());
     std::unique_ptr<RemoteMediaStreamImpl> remote_stream(
-        new RemoteMediaStreamImpl(main_thread_, track_adapter_map_, stream));
+        new RemoteMediaStreamImpl(main_thread_, track_adapter_map_,
+                                  webrtc_stream));
 
-    // The webkit object owned by RemoteMediaStreamImpl, will be initialized
-    // asynchronously and the posted task will execude after that initialization
+    // Because |SetRemoteDescription| is asynchronous it is unsafe to query the
+    // |native_peer_connection_|'s state after the callback has jumped back to
+    // the main thread - something could happen in-between this callback on the
+    // signaling thread and |OnAddStreamImpl|. Every state that the callback on
+    // the main thread needs to know about has to be passed as arguments.
+    // Get all receivers that belong to the stream's track.
+    std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>>
+        webrtc_receivers = native_peer_connection_->GetReceivers();
+    std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>> stream_web_receivers;
+    for (const auto& webrtc_audio_track : webrtc_stream->GetAudioTracks()) {
+      stream_web_receivers.push_back(CreateRTCRtpReceiverForTrack(
+          webrtc_audio_track.get(), webrtc_receivers, track_adapter_map_));
+    }
+    for (const auto& webrtc_video_track : webrtc_stream->GetVideoTracks()) {
+      stream_web_receivers.push_back(CreateRTCRtpReceiverForTrack(
+          webrtc_video_track.get(), webrtc_receivers, track_adapter_map_));
+    }
+
+    // The webkit object owned by |RemoteMediaStreamImpl|, will be initialized
+    // asynchronously and the posted task will execute after that initialization
     // is done.
     main_thread_->PostTask(
         FROM_HERE,
         base::BindOnce(&RTCPeerConnectionHandler::Observer::OnAddStreamImpl,
-                       this, base::Passed(&remote_stream)));
+                       this, base::Passed(&remote_stream),
+                       base::Passed(&stream_web_receivers)));
   }
 
   void OnRemoveStream(
@@ -1101,9 +1135,13 @@
                        candidate->candidate().address().family()));
   }
 
-  void OnAddStreamImpl(std::unique_ptr<RemoteMediaStreamImpl> stream) {
-    if (handler_)
-      handler_->OnAddStream(std::move(stream));
+  void OnAddStreamImpl(std::unique_ptr<RemoteMediaStreamImpl> stream,
+                       std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>>
+                           stream_webrtc_receivers) {
+    if (handler_) {
+      handler_->OnAddStream(std::move(stream),
+                            std::move(stream_webrtc_receivers));
+    }
   }
 
   void OnRemoveStreamImpl(const scoped_refptr<MediaStreamInterface>& stream) {
@@ -1128,6 +1166,9 @@
   const base::WeakPtr<RTCPeerConnectionHandler> handler_;
   const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
   const scoped_refptr<WebRtcMediaStreamTrackAdapterMap> track_adapter_map_;
+  // Raw pointer. Only guaranteed to be valid within within callbacks on the
+  // signaling thread since these are triggered by |native_peer_connection_|.
+  webrtc::PeerConnectionInterface* native_peer_connection_;
 };
 
 RTCPeerConnectionHandler::RTCPeerConnectionHandler(
@@ -1197,6 +1238,7 @@
   peer_connection_observer_ = new Observer(weak_factory_.GetWeakPtr());
   native_peer_connection_ = dependency_factory_->CreatePeerConnection(
       configuration_, frame_, peer_connection_observer_.get());
+  peer_connection_observer_->Initialize(native_peer_connection_.get());
 
   if (!native_peer_connection_.get()) {
     LOG(ERROR) << "Failed to initialize native PeerConnection.";
@@ -1225,6 +1267,7 @@
 
   native_peer_connection_ = dependency_factory_->CreatePeerConnection(
       configuration_, nullptr, peer_connection_observer_.get());
+  peer_connection_observer_->Initialize(native_peer_connection_.get());
   if (!native_peer_connection_.get()) {
     LOG(ERROR) << "Failed to initialize native PeerConnection.";
     return false;
@@ -1991,7 +2034,9 @@
 }
 
 void RTCPeerConnectionHandler::OnAddStream(
-    std::unique_ptr<RemoteMediaStreamImpl> stream) {
+    std::unique_ptr<RemoteMediaStreamImpl> stream,
+    std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>>
+        stream_webrtc_receivers) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(remote_streams_.find(stream->webrtc_stream().get()) ==
          remote_streams_.end());
@@ -2011,27 +2056,14 @@
   track_metrics_.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
                            stream_ptr->webrtc_stream().get());
   if (!is_closed_) {
-    // Get receivers for the tracks in this stream. We need to filter out the
-    // webrtc layer receivers of interest before creating content layer
-    // receivers so that we don't end up with content layer receivers for
-    // receivers of remote streams that have not been processed yet (this could
-    // yield track adapters that have not completed initialization).
-    // Note: This performs a synchronous call to the webrtc signaling thread.
-    // Once we switch over to |OnAddTrack| we'll get rid of these thread hops
-    // since it will contain the receiver. https://crbug.com/741619
-    std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>>
-        webrtc_receivers = native_peer_connection_->GetReceivers();
-    std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>> stream_web_receivers;
-    for (const auto& webrtc_receiver : webrtc_receivers) {
-      if (IsReceiverForStream(webrtc_receiver, stream_ptr->webrtc_stream()))
-        stream_web_receivers.push_back(GetWebRTCRtpReceiver(webrtc_receiver));
+    blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>>
+        web_vector_stream_webrtc_receivers(stream_webrtc_receivers.size());
+    for (size_t i = 0; i < stream_webrtc_receivers.size(); ++i) {
+      web_vector_stream_webrtc_receivers[i] =
+          std::move(stream_webrtc_receivers[i]);
     }
-    blink::WebVector<std::unique_ptr<blink::WebRTCRtpReceiver>> result(
-        stream_web_receivers.size());
-    for (size_t i = 0; i < stream_web_receivers.size(); ++i) {
-      result[i] = std::move(stream_web_receivers[i]);
-    }
-    client_->DidAddRemoteStream(stream_ptr->webkit_stream(), &result);
+    client_->DidAddRemoteStream(stream_ptr->webkit_stream(),
+                                &web_vector_stream_webrtc_receivers);
   }
 }
 
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h
index b2eacef..6311070 100644
--- a/content/renderer/media/rtc_peer_connection_handler.h
+++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -199,7 +199,9 @@
   void OnIceGatheringChange(
       webrtc::PeerConnectionInterface::IceGatheringState new_state);
   void OnRenegotiationNeeded();
-  void OnAddStream(std::unique_ptr<RemoteMediaStreamImpl> stream);
+  void OnAddStream(
+      std::unique_ptr<RemoteMediaStreamImpl> stream,
+      std::vector<std::unique_ptr<blink::WebRTCRtpReceiver>> web_receivers);
   void OnRemoveStream(
       const scoped_refptr<webrtc::MediaStreamInterface>& stream);
   void OnDataChannel(std::unique_ptr<RtcDataChannelHandler> handler);
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index 2c9e68e..ed51435 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -777,37 +777,37 @@
 void UserMediaClientImpl::OnStreamGenerated(
     int request_id,
     const std::string& label,
-    const StreamDeviceInfoArray& audio_array,
-    const StreamDeviceInfoArray& video_array) {
+    const MediaStreamDevices& audio_devices,
+    const MediaStreamDevices& video_devices) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!IsCurrentRequestInfo(request_id)) {
     // This can happen if the request is cancelled or the frame reloads while
     // MediaStreamDispatcher is processing the request.
     DVLOG(1) << "Request ID not found";
-    OnStreamGeneratedForCancelledRequest(audio_array, video_array);
+    OnStreamGeneratedForCancelledRequest(audio_devices, video_devices);
     return;
   }
   current_request_info_->set_state(UserMediaRequestInfo::State::GENERATED);
 
-  for (const auto* array : {&audio_array, &video_array}) {
-    for (const auto& info : *array) {
+  for (const auto* devices : {&audio_devices, &video_devices}) {
+    for (const auto& device : *devices) {
       WebRtcLogMessage(base::StringPrintf(
           "UMCI::OnStreamGenerated. request_id=%d, device id=\"%s\", "
           "device name=\"%s\"",
-          request_id, info.device.id.c_str(), info.device.name.c_str()));
+          request_id, device.id.c_str(), device.name.c_str()));
     }
   }
 
   DCHECK(!current_request_info_->request().IsNull());
   blink::WebVector<blink::WebMediaStreamTrack> audio_track_vector(
-      audio_array.size());
-  CreateAudioTracks(audio_array,
+      audio_devices.size());
+  CreateAudioTracks(audio_devices,
                     current_request_info_->request().AudioConstraints(),
                     &audio_track_vector);
 
   blink::WebVector<blink::WebMediaStreamTrack> video_track_vector(
-      video_array.size());
-  CreateVideoTracks(video_array, &video_track_vector);
+      video_devices.size());
+  CreateVideoTracks(video_devices, &video_track_vector);
 
   blink::WebString blink_id = blink::WebString::FromUTF8(label);
   current_request_info_->web_stream()->Initialize(blink_id, audio_track_vector,
@@ -820,17 +820,17 @@
 }
 
 void UserMediaClientImpl::OnStreamGeneratedForCancelledRequest(
-    const StreamDeviceInfoArray& audio_array,
-    const StreamDeviceInfoArray& video_array) {
+    const MediaStreamDevices& audio_devices,
+    const MediaStreamDevices& video_devices) {
   // Only stop the device if the device is not used in another MediaStream.
-  for (StreamDeviceInfoArray::const_iterator device_it = audio_array.begin();
-       device_it != audio_array.end(); ++device_it) {
+  for (MediaStreamDevices::const_iterator device_it = audio_devices.begin();
+       device_it != audio_devices.end(); ++device_it) {
     if (!FindLocalSource(*device_it))
       media_stream_dispatcher_->StopStreamDevice(*device_it);
   }
 
-  for (StreamDeviceInfoArray::const_iterator device_it = video_array.begin();
-       device_it != video_array.end(); ++device_it) {
+  for (MediaStreamDevices::const_iterator device_it = video_devices.begin();
+       device_it != video_devices.end(); ++device_it) {
     if (!FindLocalSource(*device_it))
       media_stream_dispatcher_->StopStreamDevice(*device_it);
   }
@@ -921,14 +921,13 @@
 
 // Callback from MediaStreamDispatcher.
 // The browser process has stopped a device used by a MediaStream.
-void UserMediaClientImpl::OnDeviceStopped(
-    const std::string& label,
-    const StreamDeviceInfo& device_info) {
+void UserMediaClientImpl::OnDeviceStopped(const std::string& label,
+                                          const MediaStreamDevice& device) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(1) << "UserMediaClientImpl::OnDeviceStopped("
-           << "{device_id = " << device_info.device.id << "})";
+           << "{device_id = " << device.id << "})";
 
-  const blink::WebMediaStreamSource* source_ptr = FindLocalSource(device_info);
+  const blink::WebMediaStreamSource* source_ptr = FindLocalSource(device);
   if (!source_ptr) {
     // This happens if the same device is used in several guM requests or
     // if a user happen stop a track from JS at the same time
@@ -943,7 +942,7 @@
 }
 
 blink::WebMediaStreamSource UserMediaClientImpl::InitializeVideoSourceObject(
-    const StreamDeviceInfo& device) {
+    const MediaStreamDevice& device) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(current_request_info_);
 
@@ -958,7 +957,7 @@
 }
 
 blink::WebMediaStreamSource UserMediaClientImpl::InitializeAudioSourceObject(
-    const StreamDeviceInfo& device,
+    const MediaStreamDevice& device,
     const blink::WebMediaConstraints& constraints,
     bool* is_pending) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -1002,64 +1001,54 @@
 }
 
 MediaStreamAudioSource* UserMediaClientImpl::CreateAudioSource(
-    const StreamDeviceInfo& device,
+    const MediaStreamDevice& device,
     const blink::WebMediaConstraints& constraints,
     const MediaStreamSource::ConstraintsCallback& source_ready,
     bool* has_sw_echo_cancellation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(current_request_info_);
 
-  // TODO(c.padhi): Remove this when |device|'s type is changed to
-  // MediaStreamDevice, see https://crbug.com/760493.
-  MediaStreamDevice audio_device = device.device;
-  audio_device.session_id = device.session_id;
-
   // If the audio device is a loopback device (for screen capture), or if the
   // constraints/effects parameters indicate no audio processing is needed,
   // create an efficient, direct-path MediaStreamAudioSource instance.
   AudioProcessingProperties audio_processing_properties =
       IsOldAudioConstraints() ? AudioProcessingProperties::FromConstraints(
-                                    constraints, audio_device.input)
+                                    constraints, device.input)
                               : current_request_info_->audio_capture_settings()
                                     .audio_processing_properties();
-  if (IsScreenCaptureMediaType(audio_device.type) ||
+  if (IsScreenCaptureMediaType(device.type) ||
       !MediaStreamAudioProcessor::WouldModifyAudio(
           audio_processing_properties)) {
     *has_sw_echo_cancellation = false;
     return new LocalMediaStreamAudioSource(RenderFrameObserver::routing_id(),
-                                           audio_device, source_ready);
+                                           device, source_ready);
   }
 
   // The audio device is not associated with screen capture and also requires
   // processing.
   ProcessedLocalAudioSource* source = new ProcessedLocalAudioSource(
-      RenderFrameObserver::routing_id(), audio_device,
-      audio_processing_properties, source_ready, dependency_factory_);
+      RenderFrameObserver::routing_id(), device, audio_processing_properties,
+      source_ready, dependency_factory_);
   *has_sw_echo_cancellation =
       audio_processing_properties.enable_sw_echo_cancellation;
   return source;
 }
 
 MediaStreamVideoSource* UserMediaClientImpl::CreateVideoSource(
-    const StreamDeviceInfo& device,
+    const MediaStreamDevice& device,
     const MediaStreamSource::SourceStoppedCallback& stop_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(current_request_info_);
   DCHECK(current_request_info_->video_capture_settings().HasValue());
 
-  // TODO(c.padhi): Remove this when |device|'s type is changed to
-  // MediaStreamDevice, see https://crbug.com/760493.
-  MediaStreamDevice video_device = device.device;
-  video_device.session_id = device.session_id;
-
   return new MediaStreamVideoCapturerSource(
-      stop_callback, video_device,
+      stop_callback, device,
       current_request_info_->video_capture_settings().capture_params(),
       render_frame());
 }
 
 void UserMediaClientImpl::CreateVideoTracks(
-    const StreamDeviceInfoArray& devices,
+    const MediaStreamDevices& devices,
     blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(current_request_info_);
@@ -1074,14 +1063,14 @@
 }
 
 void UserMediaClientImpl::CreateAudioTracks(
-    const StreamDeviceInfoArray& devices,
+    const MediaStreamDevices& devices,
     const blink::WebMediaConstraints& constraints,
     blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(current_request_info_);
   DCHECK_EQ(devices.size(), webkit_tracks->size());
 
-  StreamDeviceInfoArray overridden_audio_array = devices;
+  MediaStreamDevices overridden_audio_devices = devices;
   bool render_to_associated_sink =
       IsOldAudioConstraints()
           ? current_request_info_
@@ -1093,17 +1082,16 @@
     // If the GetUserMedia request did not explicitly set the constraint
     // kMediaStreamRenderToAssociatedSink, the output device parameters must
     // be removed.
-    for (auto& device_info : overridden_audio_array) {
-      device_info.device.matched_output_device_id = "";
-      device_info.device.matched_output =
-          media::AudioParameters::UnavailableDeviceParams();
+    for (auto& device : overridden_audio_devices) {
+      device.matched_output_device_id = "";
+      device.matched_output = media::AudioParameters::UnavailableDeviceParams();
     }
   }
 
-  for (size_t i = 0; i < overridden_audio_array.size(); ++i) {
+  for (size_t i = 0; i < overridden_audio_devices.size(); ++i) {
     bool is_pending = false;
     blink::WebMediaStreamSource source = InitializeAudioSourceObject(
-        overridden_audio_array[i], constraints, &is_pending);
+        overridden_audio_devices[i], constraints, &is_pending);
     (*webkit_tracks)[i].Initialize(source);
     current_request_info_->StartAudioTrack((*webkit_tracks)[i], is_pending);
     // At this point the source has started, and its audio parameters have been
@@ -1119,7 +1107,7 @@
     MediaStreamRequestResult result,
     const blink::WebString& result_name) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (result == content::MEDIA_DEVICE_OK) {
+  if (result == MEDIA_DEVICE_OK) {
     GetUserMediaRequestSucceeded(*request_info->web_stream(),
                                  request_info->request());
     media_stream_dispatcher_->OnStreamStarted(label);
@@ -1144,10 +1132,9 @@
   DeleteRequestInfo(request_info->request());
 }
 
-void UserMediaClientImpl::OnDeviceOpened(
-    int request_id,
-    const std::string& label,
-    const StreamDeviceInfo& video_device) {
+void UserMediaClientImpl::OnDeviceOpened(int request_id,
+                                         const std::string& label,
+                                         const MediaStreamDevice& device) {
   DVLOG(1) << "UserMediaClientImpl::OnDeviceOpened("
            << request_id << ", " << label << ")";
   NOTIMPLEMENTED();
@@ -1275,24 +1262,19 @@
 
 const blink::WebMediaStreamSource* UserMediaClientImpl::FindLocalSource(
     const LocalStreamSources& sources,
-    const StreamDeviceInfo& device) const {
-  // TODO(c.padhi): Remove this when |device|'s type is changed to
-  // MediaStreamDevice, see https://crbug.com/760493.
-  MediaStreamDevice media_stream_device = device.device;
-  media_stream_device.session_id = device.session_id;
-
+    const MediaStreamDevice& device) const {
   for (const auto& local_source : sources) {
     MediaStreamSource* const source =
         static_cast<MediaStreamSource*>(local_source.GetExtraData());
     const MediaStreamDevice& active_device = source->device();
-    if (IsSameDevice(active_device, media_stream_device))
+    if (IsSameDevice(active_device, device))
       return &local_source;
   }
   return nullptr;
 }
 
 blink::WebMediaStreamSource UserMediaClientImpl::FindOrInitializeSourceObject(
-    const StreamDeviceInfo& device) {
+    const MediaStreamDevice& device) {
   const blink::WebMediaStreamSource* existing_source = FindLocalSource(device);
   if (existing_source) {
     DVLOG(1) << "Source already exists. Reusing source with id "
@@ -1301,13 +1283,13 @@
   }
 
   blink::WebMediaStreamSource::Type type =
-      IsAudioInputMediaType(device.device.type)
+      IsAudioInputMediaType(device.type)
           ? blink::WebMediaStreamSource::kTypeAudio
           : blink::WebMediaStreamSource::kTypeVideo;
 
   blink::WebMediaStreamSource source;
-  source.Initialize(blink::WebString::FromUTF8(device.device.id), type,
-                    blink::WebString::FromUTF8(device.device.name),
+  source.Initialize(blink::WebString::FromUTF8(device.id), type,
+                    blink::WebString::FromUTF8(device.name),
                     false /* remote */);
 
   DVLOG(1) << "Initialize source object :"
@@ -1435,8 +1417,7 @@
 
   MediaStreamSource* source_impl =
       static_cast<MediaStreamSource*>(source.GetExtraData());
-  media_stream_dispatcher_->StopStreamDevice(
-      StreamDeviceInfo(source_impl->device()));
+  media_stream_dispatcher_->StopStreamDevice(source_impl->device());
 }
 
 void UserMediaClientImpl::StopLocalSource(
@@ -1448,8 +1429,7 @@
            << "{device_id = " << source_impl->device().id << "})";
 
   if (notify_dispatcher) {
-    media_stream_dispatcher_->StopStreamDevice(
-        StreamDeviceInfo(source_impl->device()));
+    media_stream_dispatcher_->StopStreamDevice(source_impl->device());
   }
 
   source_impl->ResetSourceStoppedCallback();
diff --git a/content/renderer/media/user_media_client_impl.h b/content/renderer/media/user_media_client_impl.h
index e3cd054..b9c27afe 100644
--- a/content/renderer/media/user_media_client_impl.h
+++ b/content/renderer/media/user_media_client_impl.h
@@ -79,15 +79,15 @@
   // MediaStreamDispatcherEventHandler implementation.
   void OnStreamGenerated(int request_id,
                          const std::string& label,
-                         const StreamDeviceInfoArray& audio_array,
-                         const StreamDeviceInfoArray& video_array) override;
+                         const MediaStreamDevices& audio_devices,
+                         const MediaStreamDevices& video_devices) override;
   void OnStreamGenerationFailed(int request_id,
                                 MediaStreamRequestResult result) override;
   void OnDeviceStopped(const std::string& label,
-                       const StreamDeviceInfo& device_info) override;
+                       const MediaStreamDevice& device) override;
   void OnDeviceOpened(int request_id,
                       const std::string& label,
-                      const StreamDeviceInfo& device_info) override;
+                      const MediaStreamDevice& device) override;
   void OnDeviceOpenFailed(int request_id) override;
 
   // RenderFrameObserver override
@@ -112,12 +112,12 @@
   // Creates a MediaStreamAudioSource/MediaStreamVideoSource objects.
   // These are virtual for test purposes.
   virtual MediaStreamAudioSource* CreateAudioSource(
-      const StreamDeviceInfo& device,
+      const MediaStreamDevice& device,
       const blink::WebMediaConstraints& constraints,
       const MediaStreamSource::ConstraintsCallback& source_ready,
       bool* has_sw_echo_cancellation);
   virtual MediaStreamVideoSource* CreateVideoSource(
-      const StreamDeviceInfo& device,
+      const MediaStreamDevice& device,
       const MediaStreamSource::SourceStoppedCallback& stop_callback);
 
   // Returns no value if there is no request being processed. Use only for
@@ -152,19 +152,19 @@
   // Creates a WebKit representation of stream sources based on
   // |devices| from the MediaStreamDispatcher.
   blink::WebMediaStreamSource InitializeVideoSourceObject(
-      const StreamDeviceInfo& device);
+      const MediaStreamDevice& device);
 
   blink::WebMediaStreamSource InitializeAudioSourceObject(
-      const StreamDeviceInfo& device,
+      const MediaStreamDevice& device,
       const blink::WebMediaConstraints& constraints,
       bool* is_pending);
 
   void CreateVideoTracks(
-      const StreamDeviceInfoArray& devices,
+      const MediaStreamDevices& devices,
       blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks);
 
   void CreateAudioTracks(
-      const StreamDeviceInfoArray& devices,
+      const MediaStreamDevices& devices,
       const blink::WebMediaConstraints& constraints,
       blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks);
 
@@ -176,8 +176,8 @@
                                      const blink::WebString& result_name);
 
   void OnStreamGeneratedForCancelledRequest(
-      const StreamDeviceInfoArray& audio_array,
-      const StreamDeviceInfoArray& video_array);
+      const MediaStreamDevices& audio_devices,
+      const MediaStreamDevices& video_devices);
 
   static void OnAudioSourceStartedOnAudioThread(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
@@ -204,21 +204,21 @@
   // Returns the source that use a device with |device.session_id|
   // and |device.device.id|. NULL if such source doesn't exist.
   const blink::WebMediaStreamSource* FindLocalSource(
-      const StreamDeviceInfo& device) const {
+      const MediaStreamDevice& device) const {
     return FindLocalSource(local_sources_, device);
   }
   const blink::WebMediaStreamSource* FindPendingLocalSource(
-      const StreamDeviceInfo& device) const {
+      const MediaStreamDevice& device) const {
     return FindLocalSource(pending_local_sources_, device);
   }
   const blink::WebMediaStreamSource* FindLocalSource(
       const LocalStreamSources& sources,
-      const StreamDeviceInfo& device) const;
+      const MediaStreamDevice& device) const;
 
   // Looks up a local source and returns it if found. If not found, prepares
   // a new WebMediaStreamSource with a NULL extraData pointer.
   blink::WebMediaStreamSource FindOrInitializeSourceObject(
-      const StreamDeviceInfo& device);
+      const MediaStreamDevice& device);
 
   // Returns true if we do find and remove the |source|.
   // Otherwise returns false.
diff --git a/content/renderer/media/user_media_client_impl_unittest.cc b/content/renderer/media/user_media_client_impl_unittest.cc
index 6273960..8cc1073 100644
--- a/content/renderer/media/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/user_media_client_impl_unittest.cc
@@ -281,7 +281,7 @@
   }
 
   MediaStreamAudioSource* CreateAudioSource(
-      const StreamDeviceInfo& device,
+      const MediaStreamDevice& device,
       const blink::WebMediaConstraints& constraints,
       const MediaStreamSource::ConstraintsCallback& source_ready,
       bool* has_sw_echo_cancellation) override {
@@ -300,12 +300,8 @@
     } else {
       source = new MediaStreamAudioSource(true);
     }
-    // TODO(c.padhi): Remove this when |device|'s type is changed to
-    // MediaStreamDevice, see https://crbug.com/760493.
-    MediaStreamDevice audio_device = device.device;
-    audio_device.session_id = device.session_id;
 
-    source->SetDevice(audio_device);
+    source->SetDevice(device);
 
     if (!create_source_that_fails_) {
       // RunUntilIdle is required for this task to complete.
@@ -320,15 +316,10 @@
   }
 
   MediaStreamVideoSource* CreateVideoSource(
-      const StreamDeviceInfo& device,
+      const MediaStreamDevice& device,
       const MediaStreamSource::SourceStoppedCallback& stop_callback) override {
-    // TODO(c.padhi): Remove this when |device|'s type is changed to
-    // MediaStreamDevice, see https://crbug.com/760493.
-    MediaStreamDevice video_device = device.device;
-    video_device.session_id = device.session_id;
-
-    video_source_ = new MockMediaStreamVideoCapturerSource(
-        video_device, stop_callback, factory_);
+    video_source_ =
+        new MockMediaStreamVideoCapturerSource(device, stop_callback, factory_);
     return video_source_;
   }
 
@@ -450,8 +441,8 @@
     // Audio request ID is used as the shared request ID.
     user_media_client_impl_->OnStreamGenerated(
         ms_dispatcher_->audio_input_request_id(),
-        ms_dispatcher_->stream_label(), ms_dispatcher_->audio_input_array(),
-        ms_dispatcher_->video_array());
+        ms_dispatcher_->stream_label(), ms_dispatcher_->audio_devices(),
+        ms_dispatcher_->video_devices());
     base::RunLoop().RunUntilIdle();
   }
 
@@ -499,14 +490,14 @@
 
     EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_SUCCEEDED,
               user_media_client_impl_->request_state());
-    EXPECT_EQ(1U, ms_dispatcher_->audio_input_array().size());
-    EXPECT_EQ(1U, ms_dispatcher_->video_array().size());
+    EXPECT_EQ(1U, ms_dispatcher_->audio_devices().size());
+    EXPECT_EQ(1U, ms_dispatcher_->video_devices().size());
     // MockMediaStreamDispatcher appends the session ID to its internal device
     // IDs.
     EXPECT_EQ(std::string(expected_audio_device_id) + "0",
-              ms_dispatcher_->audio_input_array()[0].device.id);
+              ms_dispatcher_->audio_devices()[0].id);
     EXPECT_EQ(std::string(expected_video_device_id) + "0",
-              ms_dispatcher_->video_array()[0].device.id);
+              ms_dispatcher_->video_devices()[0].id);
   }
 
  protected:
diff --git a/content/renderer/media/webrtc/rtc_rtp_receiver.cc b/content/renderer/media/webrtc/rtc_rtp_receiver.cc
index e8545f01..18dafc4 100644
--- a/content/renderer/media/webrtc/rtc_rtp_receiver.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_receiver.cc
@@ -23,7 +23,6 @@
       track_adapter_(std::move(track_adapter)) {
   DCHECK(webrtc_rtp_receiver_);
   DCHECK(track_adapter_);
-  DCHECK_EQ(track_adapter_->webrtc_track(), webrtc_rtp_receiver_->track());
 }
 
 RTCRtpReceiver::~RTCRtpReceiver() {}
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 e86e326..0c23be1 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.cc
@@ -23,25 +23,36 @@
 
 WebRtcMediaStreamAdapterMap::AdapterRef::AdapterRef(
     scoped_refptr<WebRtcMediaStreamAdapterMap> map,
+    std::map<std::string, AdapterEntry> WebRtcMediaStreamAdapterMap::*
+        stream_adapters,
     const MapEntryIterator& it)
-    : map_(std::move(map)), it_(it) {
+    : map_(std::move(map)), stream_adapters_(stream_adapters), it_(it) {
   DCHECK(map_);
-  DCHECK(map_->main_thread_->BelongsToCurrentThread());
-  DCHECK(it_ != map_->local_stream_adapters_.end());
+  DCHECK(stream_adapters_);
   DCHECK(entry()->adapter);
   ++entry()->ref_count;
 }
 
 WebRtcMediaStreamAdapterMap::AdapterRef::~AdapterRef() {
   DCHECK(map_->main_thread_->BelongsToCurrentThread());
-  if (--entry()->ref_count == 0) {
-    map_->local_stream_adapters_.erase(it_);
+  std::unique_ptr<WebRtcMediaStreamAdapter> removed_adapter;
+  {
+    base::AutoLock scoped_lock(map_->lock_);
+    if (--entry()->ref_count == 0) {
+      removed_adapter = std::move(entry()->adapter);
+      (*map_.*stream_adapters_).erase(it_);
+    }
   }
+  // Destroy the adapter whilst not holding the lock so that it is safe for
+  // destructors to use the signaling thread synchronously without any risk of
+  // deadlock.
+  removed_adapter.reset();
 }
 
 std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
 WebRtcMediaStreamAdapterMap::AdapterRef::Copy() const {
-  return base::WrapUnique(new AdapterRef(map_, it_));
+  base::AutoLock scoped_lock(map_->lock_);
+  return base::WrapUnique(new AdapterRef(map_, stream_adapters_, it_));
 }
 
 WebRtcMediaStreamAdapterMap::WebRtcMediaStreamAdapterMap(
@@ -62,34 +73,73 @@
 
 std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
 WebRtcMediaStreamAdapterMap::GetLocalStreamAdapter(const std::string& id) {
-  DCHECK(main_thread_->BelongsToCurrentThread());
+  base::AutoLock scoped_lock(lock_);
   auto it = local_stream_adapters_.find(id);
   if (it == local_stream_adapters_.end())
     return nullptr;
-  return base::WrapUnique(new AdapterRef(this, it));
+  return base::WrapUnique(new AdapterRef(
+      this, &WebRtcMediaStreamAdapterMap::local_stream_adapters_, it));
 }
 
 std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
 WebRtcMediaStreamAdapterMap::GetOrCreateLocalStreamAdapter(
     const blink::WebMediaStream& web_stream) {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  std::string id = web_stream.Id().Utf8();
-  auto it = local_stream_adapters_.find(id);
-  if (it == local_stream_adapters_.end()) {
-    it =
-        local_stream_adapters_
-            .insert(std::make_pair(
-                id,
-                AdapterEntry(WebRtcMediaStreamAdapter::CreateLocalStreamAdapter(
-                    factory_, track_adapter_map_, web_stream))))
-            .first;
-  }
-  return base::WrapUnique(new AdapterRef(this, it));
+  return GetOrCreateStreamAdapter(
+      &WebRtcMediaStreamAdapterMap::local_stream_adapters_,
+      base::Bind(&WebRtcMediaStreamAdapter::CreateLocalStreamAdapter, factory_,
+                 track_adapter_map_, web_stream),
+      web_stream.Id().Utf8());
 }
 
 size_t WebRtcMediaStreamAdapterMap::GetLocalStreamCount() const {
-  DCHECK(main_thread_->BelongsToCurrentThread());
+  base::AutoLock scoped_lock(lock_);
   return local_stream_adapters_.size();
 }
 
+std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
+WebRtcMediaStreamAdapterMap::GetRemoteStreamAdapter(const std::string& id) {
+  base::AutoLock scoped_lock(lock_);
+  auto it = remote_stream_adapters_.find(id);
+  if (it == remote_stream_adapters_.end())
+    return nullptr;
+  return base::WrapUnique(new AdapterRef(
+      this, &WebRtcMediaStreamAdapterMap::remote_stream_adapters_, it));
+}
+
+std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
+WebRtcMediaStreamAdapterMap::GetOrCreateRemoteStreamAdapter(
+    scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream) {
+  DCHECK(!main_thread_->BelongsToCurrentThread());
+  return GetOrCreateStreamAdapter(
+      &WebRtcMediaStreamAdapterMap::remote_stream_adapters_,
+      base::Bind(&WebRtcMediaStreamAdapter::CreateRemoteStreamAdapter,
+                 main_thread_, track_adapter_map_, webrtc_stream),
+      webrtc_stream->label());
+}
+
+size_t WebRtcMediaStreamAdapterMap::GetRemoteStreamCount() const {
+  base::AutoLock scoped_lock(lock_);
+  return remote_stream_adapters_.size();
+}
+
+std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
+WebRtcMediaStreamAdapterMap::GetOrCreateStreamAdapter(
+    std::map<std::string, AdapterEntry> WebRtcMediaStreamAdapterMap::*
+        stream_adapters,
+    base::Callback<std::unique_ptr<WebRtcMediaStreamAdapter>()>
+        create_adapter_callback,
+    const std::string& id) {
+  base::AutoLock scoped_lock(lock_);
+  auto it = (this->*stream_adapters).find(id);
+  if (it == (this->*stream_adapters).end()) {
+    std::unique_ptr<WebRtcMediaStreamAdapter> adapter =
+        create_adapter_callback.Run();
+    it = (this->*stream_adapters)
+             .insert(std::make_pair(id, AdapterEntry(std::move(adapter))))
+             .first;
+  }
+  return base::WrapUnique(new AdapterRef(this, stream_adapters, it));
+}
+
 }  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h
index 5283ba5..5872d00 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h
@@ -5,8 +5,12 @@
 #ifndef CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_MEDIA_STREAM_ADAPTER_MAP_H_
 #define CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_MEDIA_STREAM_ADAPTER_MAP_H_
 
+#include <map>
+#include <memory>
+
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
 #include "content/common/content_export.h"
 #include "content/renderer/media/webrtc/webrtc_media_stream_adapter.h"
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
@@ -44,43 +48,21 @@
   };
 
  public:
-  // Accessor to an adapter to take care of reference counting. When the last
-  // |AdapterRef| is destroyed, the corresponding adapter is destroyed and
-  // removed from the map.
-  class CONTENT_EXPORT AdapterRef {
-   public:
-    // Must be invoked on the main thread. If this was the last reference to the
-    // adapter it will be disposed and removed from the map.
-    ~AdapterRef();
-
-    std::unique_ptr<AdapterRef> Copy() const;
-    const WebRtcMediaStreamAdapter& adapter() const {
-      return *it_->second.adapter;
-    }
-
-   private:
-    friend class WebRtcMediaStreamAdapterMap;
-    using MapEntryIterator = std::map<std::string, AdapterEntry>::iterator;
-
-    // Increments the |AdapterEntry::ref_count|.
-    AdapterRef(scoped_refptr<WebRtcMediaStreamAdapterMap> map,
-               const MapEntryIterator& it);
-
-    AdapterEntry* entry() { return &it_->second; }
-
-    scoped_refptr<WebRtcMediaStreamAdapterMap> map_;
-    MapEntryIterator it_;
-  };
+  // The definition of this class is placed outside, below this class
+  // definition. This is because |AdapterRef| contains usage of
+  // pointer-to-member of |WebRtcMediaStreamAdapterMap|. Defining |AdapterRef|
+  // here produces compile errors only on win-clang.
+  class AdapterRef;
 
   // Must be invoked on the main thread.
   WebRtcMediaStreamAdapterMap(
       PeerConnectionDependencyFactory* const factory,
       scoped_refptr<WebRtcMediaStreamTrackAdapterMap> track_adapter_map);
 
-  // Invoke on the main thread. Gets a new reference to the local stream adapter
-  // by ID, or null if no such adapter was found. When all references are
-  // destroyed the adapter is destroyed and removed from the map. References
-  // must be destroyed on the main thread.
+  // Gets a new reference to the local stream adapter by ID, or null if no such
+  // adapter was found. When all references are destroyed the adapter is
+  // destroyed and removed from the map. This can be called on any thread, but
+  // references must be destroyed on the main thread.
   std::unique_ptr<AdapterRef> GetLocalStreamAdapter(const std::string& id);
   // Invoke on the main thread. Gets a new reference to the local stream adapter
   // for the web stream. If no adapter exists for the stream one is created.
@@ -88,16 +70,34 @@
   // the map. References must be destroyed on the main thread.
   std::unique_ptr<AdapterRef> GetOrCreateLocalStreamAdapter(
       const blink::WebMediaStream& web_stream);
-  // Invoke on the main thread.
   size_t GetLocalStreamCount() const;
 
- protected:
+  // Gets a new reference to the remote stream adapter by ID, or null if no such
+  // adapter was found. When all references are destroyed the adapter is
+  // destroyed and removed from the map. This can be called on any thread, but
+  // references must be destroyed on the main thread.
+  std::unique_ptr<AdapterRef> GetRemoteStreamAdapter(const std::string& id);
+  // Invoke on the webrtc signaling thread. Gets a new reference to the remote
+  // stream adapter for the webrtc stream. If no adapter exists for the stream
+  // one is created. When all references are destroyed the adapter is destroyed
+  // and removed from the map. References must be destroyed on the main thread.
+  std::unique_ptr<AdapterRef> GetOrCreateRemoteStreamAdapter(
+      scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream);
+  size_t GetRemoteStreamCount() const;
+
+ private:
   friend class base::RefCountedThreadSafe<WebRtcMediaStreamAdapterMap>;
 
   // Invoke on the main thread.
   virtual ~WebRtcMediaStreamAdapterMap();
 
- private:
+  std::unique_ptr<AdapterRef> GetOrCreateStreamAdapter(
+      std::map<std::string, AdapterEntry> WebRtcMediaStreamAdapterMap::*
+          stream_adapters,
+      base::Callback<std::unique_ptr<WebRtcMediaStreamAdapter>()>
+          create_adapter_callback,
+      const std::string& id);
+
   // Pointer to a |PeerConnectionDependencyFactory| owned by the |RenderThread|.
   // It's valid for the lifetime of |RenderThread|.
   PeerConnectionDependencyFactory* const factory_;
@@ -105,9 +105,41 @@
   // Takes care of creating and owning track adapters, used by stream adapters.
   scoped_refptr<WebRtcMediaStreamTrackAdapterMap> track_adapter_map_;
 
+  mutable base::Lock lock_;
   std::map<std::string, AdapterEntry> local_stream_adapters_;
-  // TODO(hbos): Take care of remote stream adapters as well. This will require
-  // usage of the signaling thread. crbug.com/705901
+  std::map<std::string, AdapterEntry> remote_stream_adapters_;
+};
+
+// Accessor to an adapter to take care of reference counting. When the last
+// |AdapterRef| is destroyed, the corresponding adapter is destroyed and removed
+// from the map.
+class CONTENT_EXPORT WebRtcMediaStreamAdapterMap::AdapterRef {
+ public:
+  // Must be invoked on the main thread. If this was the last reference to the
+  // adapter it will be disposed and removed from the map.
+  ~AdapterRef();
+
+  std::unique_ptr<AdapterRef> Copy() const;
+  const WebRtcMediaStreamAdapter& adapter() const {
+    return *it_->second.adapter;
+  }
+
+ private:
+  friend class WebRtcMediaStreamAdapterMap;
+  using MapEntryIterator = std::map<std::string, AdapterEntry>::iterator;
+
+  // Increments the |AdapterEntry::ref_count|. Assumes map's |lock_| is held.
+  AdapterRef(scoped_refptr<WebRtcMediaStreamAdapterMap> map,
+             std::map<std::string, AdapterEntry> WebRtcMediaStreamAdapterMap::*
+                 stream_adapters,
+             const MapEntryIterator& it);
+
+  AdapterEntry* entry() { return &it_->second; }
+
+  scoped_refptr<WebRtcMediaStreamAdapterMap> map_;
+  std::map<std::string, AdapterEntry> WebRtcMediaStreamAdapterMap::*
+      stream_adapters_;
+  MapEntryIterator it_;
 };
 
 }  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc
index 6c61625e..f71918a 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
 #include "content/child/child_process.h"
 #include "content/renderer/media/media_stream_video_source.h"
 #include "content/renderer/media/media_stream_video_track.h"
@@ -62,7 +63,54 @@
     return web_stream;
   }
 
+  scoped_refptr<webrtc::MediaStreamInterface> CreateRemoteStream(
+      const std::string& id) {
+    scoped_refptr<webrtc::MediaStreamInterface> stream(
+        new rtc::RefCountedObject<MockMediaStream>(id));
+    stream->AddTrack(MockWebRtcAudioTrack::Create("remote_audio_track").get());
+    stream->AddTrack(MockWebRtcVideoTrack::Create("remote_video_track").get());
+    return stream;
+  }
+
+  std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>
+  GetOrCreateRemoteStreamAdapter(webrtc::MediaStreamInterface* webrtc_stream) {
+    std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef> adapter_ref;
+    dependency_factory_->GetWebRtcSignalingThread()->PostTask(
+        FROM_HERE,
+        base::Bind(&WebRtcMediaStreamAdapterMapTest::
+                       GetOrCreateRemoteStreamAdapterOnSignalingThread,
+                   base::Unretained(this), base::Unretained(webrtc_stream),
+                   base::Unretained(&adapter_ref)));
+    RunMessageLoopsUntilIdle();
+    DCHECK(adapter_ref);
+    return adapter_ref;
+  }
+
  protected:
+  void GetOrCreateRemoteStreamAdapterOnSignalingThread(
+      webrtc::MediaStreamInterface* webrtc_stream,
+      std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>* adapter_ref) {
+    *adapter_ref = map_->GetOrCreateRemoteStreamAdapter(webrtc_stream);
+    EXPECT_TRUE(*adapter_ref);
+  }
+
+  // Runs message loops on the webrtc signaling thread and the main thread until
+  // idle.
+  void RunMessageLoopsUntilIdle() {
+    base::WaitableEvent waitable_event(
+        base::WaitableEvent::ResetPolicy::MANUAL,
+        base::WaitableEvent::InitialState::NOT_SIGNALED);
+    dependency_factory_->GetWebRtcSignalingThread()->PostTask(
+        FROM_HERE, base::Bind(&WebRtcMediaStreamAdapterMapTest::SignalEvent,
+                              base::Unretained(this), &waitable_event));
+    waitable_event.Wait();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void SignalEvent(base::WaitableEvent* waitable_event) {
+    waitable_event->Signal();
+  }
+
   // Message loop and child processes is needed for task queues and threading to
   // work, as is necessary to create tracks and adapters.
   base::MessageLoop message_loop_;
@@ -97,4 +145,28 @@
   EXPECT_FALSE(map_->GetLocalStreamAdapter("invalid"));
 }
 
+TEST_F(WebRtcMediaStreamAdapterMapTest, AddAndRemoveRemoteStreamAdapter) {
+  scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream =
+      CreateRemoteStream("remote_stream");
+  std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef> adapter_ref =
+      GetOrCreateRemoteStreamAdapter(webrtc_stream.get());
+  EXPECT_EQ(webrtc_stream, adapter_ref->adapter().webrtc_stream());
+  EXPECT_EQ(1u, map_->GetRemoteStreamCount());
+
+  std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef> adapter_ref2 =
+      map_->GetRemoteStreamAdapter("remote_stream");
+  EXPECT_TRUE(adapter_ref2);
+  EXPECT_EQ(&adapter_ref2->adapter(), &adapter_ref->adapter());
+  EXPECT_EQ(1u, map_->GetRemoteStreamCount());
+
+  adapter_ref.reset();
+  EXPECT_EQ(1u, map_->GetRemoteStreamCount());
+  adapter_ref2.reset();
+  EXPECT_EQ(0u, map_->GetRemoteStreamCount());
+}
+
+TEST_F(WebRtcMediaStreamAdapterMapTest, GetRemoteStreamAdapterInvalidID) {
+  EXPECT_FALSE(map_->GetRemoteStreamAdapter("invalid"));
+}
+
 }  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc
index 6a0991c..9c75103e 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc
@@ -37,20 +37,20 @@
 WebRtcMediaStreamTrackAdapter::CreateRemoteTrackAdapter(
     PeerConnectionDependencyFactory* factory,
     const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
-    webrtc::MediaStreamTrackInterface* webrtc_track) {
+    const scoped_refptr<webrtc::MediaStreamTrackInterface>& webrtc_track) {
   DCHECK(factory);
   DCHECK(!main_thread->BelongsToCurrentThread());
   DCHECK(webrtc_track);
   scoped_refptr<WebRtcMediaStreamTrackAdapter> remote_track_adapter(
       new WebRtcMediaStreamTrackAdapter(factory, main_thread));
   if (webrtc_track->kind() == webrtc::MediaStreamTrackInterface::kAudioKind) {
-    remote_track_adapter->InitializeRemoteAudioTrack(
-        static_cast<webrtc::AudioTrackInterface*>(webrtc_track));
+    remote_track_adapter->InitializeRemoteAudioTrack(make_scoped_refptr(
+        static_cast<webrtc::AudioTrackInterface*>(webrtc_track.get())));
   } else {
     DCHECK_EQ(webrtc_track->kind(),
               webrtc::MediaStreamTrackInterface::kVideoKind);
-    remote_track_adapter->InitializeRemoteVideoTrack(
-        static_cast<webrtc::VideoTrackInterface*>(webrtc_track));
+    remote_track_adapter->InitializeRemoteVideoTrack(make_scoped_refptr(
+        static_cast<webrtc::VideoTrackInterface*>(webrtc_track.get())));
   }
   return remote_track_adapter;
 }
@@ -174,7 +174,7 @@
 }
 
 void WebRtcMediaStreamTrackAdapter::InitializeRemoteAudioTrack(
-    webrtc::AudioTrackInterface* webrtc_audio_track) {
+    const scoped_refptr<webrtc::AudioTrackInterface>& webrtc_audio_track) {
   DCHECK(!main_thread_->BelongsToCurrentThread());
   DCHECK(!is_initialized_);
   DCHECK(!remote_track_can_complete_initialization_.IsSignaled());
@@ -182,7 +182,7 @@
   DCHECK_EQ(webrtc_audio_track->kind(),
             webrtc::MediaStreamTrackInterface::kAudioKind);
   remote_audio_track_adapter_ =
-      new RemoteAudioTrackAdapter(main_thread_, webrtc_audio_track);
+      new RemoteAudioTrackAdapter(main_thread_, webrtc_audio_track.get());
   webrtc_track_ = webrtc_audio_track;
   remote_track_can_complete_initialization_.Signal();
   main_thread_->PostTask(
@@ -193,13 +193,13 @@
 }
 
 void WebRtcMediaStreamTrackAdapter::InitializeRemoteVideoTrack(
-    webrtc::VideoTrackInterface* webrtc_video_track) {
+    const scoped_refptr<webrtc::VideoTrackInterface>& webrtc_video_track) {
   DCHECK(!main_thread_->BelongsToCurrentThread());
   DCHECK(webrtc_video_track);
   DCHECK_EQ(webrtc_video_track->kind(),
             webrtc::MediaStreamTrackInterface::kVideoKind);
   remote_video_track_adapter_ =
-      new RemoteVideoTrackAdapter(main_thread_, webrtc_video_track);
+      new RemoteVideoTrackAdapter(main_thread_, webrtc_video_track.get());
   webrtc_track_ = webrtc_video_track;
   remote_track_can_complete_initialization_.Signal();
   main_thread_->PostTask(
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h
index 06bedcf..2088a829 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h
@@ -32,18 +32,19 @@
     : public base::RefCountedThreadSafe<WebRtcMediaStreamTrackAdapter> {
  public:
   // Invoke on the main thread. The returned adapter is fully initialized, see
-  // |is_initialized|.
+  // |is_initialized|. The adapter will keep a reference to the |main_thread|.
   static scoped_refptr<WebRtcMediaStreamTrackAdapter> CreateLocalTrackAdapter(
       PeerConnectionDependencyFactory* factory,
       const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
       const blink::WebMediaStreamTrack& web_track);
   // Invoke on the webrtc signaling thread. Initialization finishes on the main
   // thread in a post, meaning returned adapters are ensured to be initialized
-  // in posts to the main thread, see |is_initialized|.
+  // in posts to the main thread, see |is_initialized|. The adapter will keep
+  // references to the |main_thread| and |webrtc_track|.
   static scoped_refptr<WebRtcMediaStreamTrackAdapter> CreateRemoteTrackAdapter(
       PeerConnectionDependencyFactory* factory,
       const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
-      webrtc::MediaStreamTrackInterface* webrtc_track);
+      const scoped_refptr<webrtc::MediaStreamTrackInterface>& webrtc_track);
   // Must be called before all external references are released (i.e. before
   // destruction). Invoke on the main thread. Disposing may finish
   // asynchronously using the webrtc signaling thread and the main thread. After
@@ -88,9 +89,9 @@
   // Initialization of remote tracks starts on the webrtc signaling thread and
   // finishes on the main thread.
   void InitializeRemoteAudioTrack(
-      webrtc::AudioTrackInterface* webrtc_audio_track);
+      const scoped_refptr<webrtc::AudioTrackInterface>& webrtc_audio_track);
   void InitializeRemoteVideoTrack(
-      webrtc::VideoTrackInterface* webrtc_video_track);
+      const scoped_refptr<webrtc::VideoTrackInterface>& webrtc_video_track);
   void FinalizeRemoteTrackInitializationOnMainThread();
   void EnsureTrackIsInitialized();
 
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
index bdec0662..bff7a19 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
@@ -129,8 +129,9 @@
   base::AutoLock scoped_lock(lock_);
   scoped_refptr<WebRtcMediaStreamTrackAdapter>* adapter_ptr =
       remote_track_adapters_.FindBySecondary(web_track.UniqueId());
-  if (!adapter_ptr || !(*adapter_ptr)->is_initialized())
+  if (!adapter_ptr)
     return nullptr;
+  DCHECK((*adapter_ptr)->is_initialized());
   return base::WrapUnique(
       new AdapterRef(this, AdapterRef::Type::kRemote, *adapter_ptr));
 }
@@ -141,7 +142,7 @@
   base::AutoLock scoped_lock(lock_);
   scoped_refptr<WebRtcMediaStreamTrackAdapter>* adapter_ptr =
       remote_track_adapters_.FindByPrimary(webrtc_track);
-  if (!adapter_ptr || !(*adapter_ptr)->is_initialized())
+  if (!adapter_ptr)
     return nullptr;
   return base::WrapUnique(
       new AdapterRef(this, AdapterRef::Type::kRemote, *adapter_ptr));
@@ -149,12 +150,12 @@
 
 std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>
 WebRtcMediaStreamTrackAdapterMap::GetOrCreateRemoteTrackAdapter(
-    webrtc::MediaStreamTrackInterface* webrtc_track) {
+    scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track) {
   DCHECK(webrtc_track);
   DCHECK(!main_thread_->BelongsToCurrentThread());
   base::AutoLock scoped_lock(lock_);
   scoped_refptr<WebRtcMediaStreamTrackAdapter>* adapter_ptr =
-      remote_track_adapters_.FindByPrimary(webrtc_track);
+      remote_track_adapters_.FindByPrimary(webrtc_track.get());
   if (adapter_ptr) {
     return base::WrapUnique(
         new AdapterRef(this, AdapterRef::Type::kRemote, *adapter_ptr));
@@ -162,7 +163,7 @@
   scoped_refptr<WebRtcMediaStreamTrackAdapter> new_adapter =
       WebRtcMediaStreamTrackAdapter::CreateRemoteTrackAdapter(
           factory_, main_thread_, webrtc_track);
-  remote_track_adapters_.Insert(webrtc_track, new_adapter);
+  remote_track_adapters_.Insert(webrtc_track.get(), new_adapter);
   // The new adapter is initialized in a post to the main thread. As soon as it
   // is initialized we map its |webrtc_track| to the |remote_track_adapters_|
   // entry as its secondary key. This ensures that there is at least one
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h
index de92d96..f1322ffc 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h
@@ -91,14 +91,18 @@
       const blink::WebMediaStreamTrack& web_track);
   size_t GetLocalTrackCount() const;
 
-  // Gets a new reference to the remote track adapter if it exists and is
-  // initialized, null otherwise. When all references are destroyed the adapter
-  // is disposed and removed from the map. This method can be called from any
-  // thread, but references must be destroyed on the main thread.
-  // The adapter is a associated with a blink and webrtc track, lookup works by
-  // either track.
+  // Gets a new reference to the remote track adapter. When all references are
+  // destroyed the adapter is disposed and removed from the map. This method can
+  // be called from any thread, but references must be destroyed on the main
+  // thread. The adapter is a associated with a blink and webrtc track, lookup
+  // works by either track.
+  // First variety: If an adapter exists it will already be initialized, if one
+  // does not exist for then null is returned.
   std::unique_ptr<AdapterRef> GetRemoteTrackAdapter(
       const blink::WebMediaStreamTrack& web_track);
+  // Second variety: If an adapter exists it may or may not be initialized, see
+  // |AdapterRef::is_initialized|. If an adapter does not exist then null is
+  // returned.
   std::unique_ptr<AdapterRef> GetRemoteTrackAdapter(
       webrtc::MediaStreamTrackInterface* webrtc_track);
   // Invoke on the webrtc signaling thread. Gets a new reference to the remote
@@ -107,7 +111,7 @@
   // all references are destroyed the adapter is disposed and removed from the
   // map. References must be destroyed on the main thread.
   std::unique_ptr<AdapterRef> GetOrCreateRemoteTrackAdapter(
-      webrtc::MediaStreamTrackInterface* webrtc_track);
+      scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track);
   size_t GetRemoteTrackCount() const;
 
  protected:
@@ -117,6 +121,8 @@
   virtual ~WebRtcMediaStreamTrackAdapterMap();
 
  private:
+  // The adapter keeps the |webrtc::MediaStreamTrackInterface| alive with ref
+  // counting making it safe to use a raw pointer for key.
   using LocalTrackAdapterMap =
       TwoKeysAdapterMap<int,
                         webrtc::MediaStreamTrackInterface*,
diff --git a/content/renderer/media_recorder/OWNERS b/content/renderer/media_recorder/OWNERS
index 687c6bd..6675929 100644
--- a/content/renderer/media_recorder/OWNERS
+++ b/content/renderer/media_recorder/OWNERS
@@ -2,3 +2,4 @@
 mcasas@chromium.org
 
 # COMPONENT: Blink>MediaRecording
+# TEAM: media-dev@chromium.org
diff --git a/content/renderer/pepper/pepper_media_device_manager.cc b/content/renderer/pepper/pepper_media_device_manager.cc
index 8232a7ec..247b5c5 100644
--- a/content/renderer/pepper/pepper_media_device_manager.cc
+++ b/content/renderer/pepper/pepper_media_device_manager.cc
@@ -203,21 +203,20 @@
 void PepperMediaDeviceManager::OnStreamGenerated(
     int request_id,
     const std::string& label,
-    const StreamDeviceInfoArray& audio_device_array,
-    const StreamDeviceInfoArray& video_device_array) {}
+    const MediaStreamDevices& audio_devices,
+    const MediaStreamDevices& video_devices) {}
 
 void PepperMediaDeviceManager::OnStreamGenerationFailed(
     int request_id,
-    content::MediaStreamRequestResult result) {}
+    MediaStreamRequestResult result) {}
 
 void PepperMediaDeviceManager::OnDeviceStopped(
     const std::string& label,
-    const StreamDeviceInfo& device_info) {}
+    const MediaStreamDevice& device) {}
 
-void PepperMediaDeviceManager::OnDeviceOpened(
-    int request_id,
-    const std::string& label,
-    const StreamDeviceInfo& device_info) {
+void PepperMediaDeviceManager::OnDeviceOpened(int request_id,
+                                              const std::string& label,
+                                              const MediaStreamDevice& device) {
   NotifyDeviceOpened(request_id, true, label);
 }
 
diff --git a/content/renderer/pepper/pepper_media_device_manager.h b/content/renderer/pepper/pepper_media_device_manager.h
index 65f5fd4..2000648 100644
--- a/content/renderer/pepper/pepper_media_device_manager.h
+++ b/content/renderer/pepper/pepper_media_device_manager.h
@@ -63,19 +63,17 @@
   int GetSessionID(PP_DeviceType_Dev type, const std::string& label);
 
   // MediaStreamDispatcherEventHandler implementation.
-  void OnStreamGenerated(
-      int request_id,
-      const std::string& label,
-      const StreamDeviceInfoArray& audio_device_array,
-      const StreamDeviceInfoArray& video_device_array) override;
-  void OnStreamGenerationFailed(
-      int request_id,
-      content::MediaStreamRequestResult result) override;
+  void OnStreamGenerated(int request_id,
+                         const std::string& label,
+                         const MediaStreamDevices& audio_devices,
+                         const MediaStreamDevices& video_devices) override;
+  void OnStreamGenerationFailed(int request_id,
+                                MediaStreamRequestResult result) override;
   void OnDeviceStopped(const std::string& label,
-                       const StreamDeviceInfo& device_info) override;
+                       const MediaStreamDevice& device) override;
   void OnDeviceOpened(int request_id,
                       const std::string& label,
-                      const StreamDeviceInfo& device_info) override;
+                      const MediaStreamDevice& device) override;
   void OnDeviceOpenFailed(int request_id) override;
 
   // Stream type conversion.
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 7e729e5..4295d797 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6848,8 +6848,15 @@
     DCHECK(factory);
   }
 
+  mojom::KeepAliveHandlePtr keep_alive_handle;
+  if (base::FeatureList::IsEnabled(
+          features::kKeepAliveRendererForKeepaliveRequests) &&
+      request.GetKeepalive()) {
+    GetFrameHost()->IssueKeepAliveHandle(mojo::MakeRequest(&keep_alive_handle));
+  }
   return base::MakeUnique<WebURLLoaderImpl>(child_thread->resource_dispatcher(),
-                                            task_runner, factory);
+                                            task_runner, factory,
+                                            std::move(keep_alive_handle));
 }
 
 void RenderFrameImpl::DraggableRegionsChanged() {
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index f650918..71a64ac0 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -557,7 +557,7 @@
       viz::SurfaceInfo surface_info(
           viz::SurfaceId(frame_sink_id_, local_surface_id_),
           device_scale_factor,
-          gfx::ScaleToCeiledSize(frame_rect_.size(), device_scale_factor));
+          gfx::ScaleToCeiledSize(rect.size(), device_scale_factor));
       compositing_helper_->SetPrimarySurfaceInfo(surface_info);
     }
   }
diff --git a/content/test/data/accessibility/aria/aria-autocomplete-expected-android.txt b/content/test/data/accessibility/aria/aria-autocomplete-expected-android.txt
index cf339531..6b7edfa 100644
--- a/content/test/data/accessibility/aria/aria-autocomplete-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-autocomplete-expected-android.txt
@@ -1,5 +1,5 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.Spinner role_description='combo box' clickable name='autocomplete=inline'
-++android.widget.Spinner role_description='combo box' clickable name='autocomplete=list'
-++android.widget.Spinner role_description='combo box' clickable name='autocomplete=both'
-++android.widget.Spinner role_description='combo box' clickable name='autocomplete=none'
\ No newline at end of file
+++android.widget.Spinner role_description='combo box' clickable editable_text has_non_empty_value name='autocomplete=inline' text_change_added_count=19
+++android.widget.Spinner role_description='combo box' clickable editable_text has_non_empty_value name='autocomplete=list' text_change_added_count=17
+++android.widget.Spinner role_description='combo box' clickable editable_text has_non_empty_value name='autocomplete=both' text_change_added_count=17
+++android.widget.Spinner role_description='combo box' clickable editable_text has_non_empty_value name='autocomplete=none' text_change_added_count=17
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-haspopup-expected-android.txt b/content/test/data/accessibility/aria/aria-haspopup-expected-android.txt
index 12b2909..9da60590 100644
--- a/content/test/data/accessibility/aria/aria-haspopup-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-haspopup-expected-android.txt
@@ -1,3 +1,3 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.Spinner role_description='combo box' clickable focusable
-++android.widget.Spinner role_description='combo box' clickable focusable
\ No newline at end of file
+++android.widget.Spinner role_description='combo box' clickable editable_text focusable
+++android.widget.Spinner role_description='combo box' clickable editable_text focusable
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-orientation-expected-android.txt b/content/test/data/accessibility/aria/aria-orientation-expected-android.txt
index 05663323..f9a4f01 100644
--- a/content/test/data/accessibility/aria/aria-orientation-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-orientation-expected-android.txt
@@ -1,7 +1,7 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.Spinner role_description='combo box' clickable
-++android.widget.Spinner role_description='combo box' clickable
-++android.widget.Spinner role_description='combo box' clickable
+++android.widget.Spinner role_description='combo box' clickable editable_text
+++android.widget.Spinner role_description='combo box' clickable editable_text
+++android.widget.Spinner role_description='combo box' clickable editable_text
 ++android.widget.ListView role_description='list box' clickable collection
 ++android.widget.ListView role_description='list box' clickable collection
 ++android.widget.ListView role_description='list box' clickable collection
diff --git a/content/test/data/accessibility/aria/aria-readonly-expected-android.txt b/content/test/data/accessibility/aria/aria-readonly-expected-android.txt
index f2d6297..3308784 100644
--- a/content/test/data/accessibility/aria/aria-readonly-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-readonly-expected-android.txt
@@ -12,12 +12,12 @@
 ++android.widget.EditText clickable editable_text focusable name='Readonly-false contenteditable textbox'
 ++android.widget.EditText clickable editable_text focusable name='Readonly-true contenteditable textbox'
 ++android.widget.CheckBox role_description='checkbox' checkable clickable name='Readonly checkbox'
-++android.widget.Spinner role_description='combo box' clickable name='Readonly combobox'
+++android.widget.Spinner role_description='combo box' clickable editable_text name='Readonly combobox'
 ++android.widget.ListView role_description='list box' clickable collection name='Readonly listbox'
 ++android.view.View role_description='radio group' name='Readonly radiogroup'
 ++android.widget.SeekBar role_description='slider' range name='Readonly slider' item_count=100
 ++android.widget.EditText role_description='spin button' clickable name='Readonly spinbutton'
 ++android.view.MenuItem role_description='checkbox' checkable clickable name='Readonly menuitemcheckbox'
 ++android.view.MenuItem role_description='radio button' checkable clickable name='Readonly menuitemradio'
-++android.widget.EditText role_description='search text field' clickable name='Readonly searchbox'
+++android.widget.EditText role_description='search text field' clickable editable_text name='Readonly searchbox'
 ++android.widget.CheckBox role_description='switch' checkable clickable name='Readonly switch'
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-searchbox-expected-android.txt b/content/test/data/accessibility/aria/aria-searchbox-expected-android.txt
index 57664faa..928de295 100644
--- a/content/test/data/accessibility/aria/aria-searchbox-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-searchbox-expected-android.txt
@@ -1,2 +1,2 @@
 android.webkit.WebView focusable scrollable
-++android.widget.EditText role_description='search text field' clickable focusable focused name='ARIA role searchbox.'
\ No newline at end of file
+++android.widget.EditText role_description='search text field' clickable editable_text focusable focused has_non_empty_value name='ARIA role searchbox.' text_change_added_count=20
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-android.txt b/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-android.txt
index 57664faa..928de295 100644
--- a/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-searchbox-with-selection-expected-android.txt
@@ -1,2 +1,2 @@
 android.webkit.WebView focusable scrollable
-++android.widget.EditText role_description='search text field' clickable focusable focused name='ARIA role searchbox.'
\ No newline at end of file
+++android.widget.EditText role_description='search text field' clickable editable_text focusable focused has_non_empty_value name='ARIA role searchbox.' text_change_added_count=20
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-onclick-expected-blink.txt b/content/test/data/accessibility/html/a-onclick-expected-blink.txt
index 12ddc663..41a1ed47 100644
--- a/content/test/data/accessibility/html/a-onclick-expected-blink.txt
+++ b/content/test/data/accessibility/html/a-onclick-expected-blink.txt
@@ -1,7 +1,7 @@
 rootWebArea
 ++link name='link with no href but onclick' defaultActionVerb=jump
-++++staticText name='link with no href but onclick' defaultActionVerb=click
+++++staticText name='link with no href but onclick' defaultActionVerb=clickAncestor
 ++++++inlineTextBox name='link with no href but onclick'
 ++link name='link with no href and click handler added via script' defaultActionVerb=jump
-++++staticText name='link with no href and click handler added via script' defaultActionVerb=click
+++++staticText name='link with no href and click handler added via script' defaultActionVerb=clickAncestor
 ++++++inlineTextBox name='link with no href and click handler added via script'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-onclick-expected-win.txt b/content/test/data/accessibility/html/a-onclick-expected-win.txt
index a855aaf6..40e6d3f1 100644
--- a/content/test/data/accessibility/html/a-onclick-expected-win.txt
+++ b/content/test/data/accessibility/html/a-onclick-expected-win.txt
@@ -1,6 +1,5 @@
-#<skip -- bug 120951>
-ROLE_SYSTEM_DOCUMENT state=FOCUSED,READONLY,FOCUSABLE
-++ROLE_SYSTEM_LINK name='link with no href but onclick' state=FOCUSABLE,LINKED
-++++ROLE_SYSTEM_TEXT name='link with no href but onclick' state=READONLY,LINKED
-++ROLE_SYSTEM_LINK name='link with no href and click handler added via script' state=FOCUSABLE,LINKED
-++++ROLE_SYSTEM_TEXT name='link with no href and click handler added via script' state=READONLY,LINKED
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+++ROLE_SYSTEM_LINK name='link with no href but onclick' LINKED default_action='jump' action_name='jump'
+++++ROLE_SYSTEM_STATICTEXT name='link with no href but onclick' default_action='click ancestor' action_name='click-ancestor'
+++ROLE_SYSTEM_LINK name='link with no href and click handler added via script' LINKED default_action='jump' action_name='jump'
+++++ROLE_SYSTEM_STATICTEXT name='link with no href and click handler added via script' default_action='click ancestor' action_name='click-ancestor'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/a-onclick.html b/content/test/data/accessibility/html/a-onclick.html
index 5ae2827..d4a89dc8 100644
--- a/content/test/data/accessibility/html/a-onclick.html
+++ b/content/test/data/accessibility/html/a-onclick.html
@@ -1,5 +1,9 @@
 <!--
 @BLINK-ALLOW:defaultActionVerb*
+@BLINK-ALLOW:linked
+@WIN-ALLOW:action_name*
+@WIN-ALLOW:default_action*
+@WIN-ALLOW:LINKED
 -->
 <html>
 <style>a { text-decoration: underline; display: block; }</style>
diff --git a/content/test/data/accessibility/html/action-verbs-expected-blink.txt b/content/test/data/accessibility/html/action-verbs-expected-blink.txt
index dc11dc4..91bdd71 100644
--- a/content/test/data/accessibility/html/action-verbs-expected-blink.txt
+++ b/content/test/data/accessibility/html/action-verbs-expected-blink.txt
@@ -7,7 +7,7 @@
 ++++++inlineTextBox name='Heading'
 ++button name='Button' defaultActionVerb=press
 ++link name='Link' defaultActionVerb=jump
-++++staticText name='Link' defaultActionVerb=click
+++++staticText name='Link' defaultActionVerb=clickAncestor
 ++++++inlineTextBox name='Link'
 ++textField defaultActionVerb=activate
 ++searchBox defaultActionVerb=activate
@@ -25,9 +25,13 @@
 ++++menuListPopup invisible activedescendantId=menuListOption
 ++++++menuListOption selectable selected name='Pop-up button' defaultActionVerb=select
 ++genericContainer defaultActionVerb=click
-++++staticText name='Div with click handler' defaultActionVerb=click
+++++staticText name='Div with click handler' defaultActionVerb=clickAncestor
 ++++++inlineTextBox name='Div with click handler'
+++group defaultActionVerb=click
+++++paragraph defaultActionVerb=clickAncestor
+++++++staticText name='Paragraph with click handler on parent' defaultActionVerb=clickAncestor
+++++++++inlineTextBox name='Paragraph with click handler on parent'
 ++menu
 ++++menuItem name='Menu item 1' defaultActionVerb=select
 ++++menuItemCheckBox name='Menu item 2' defaultActionVerb=uncheck checkedState=true
-++++menuItemRadio name='Menu item 3' defaultActionVerb=check checkedState=false
+++++menuItemRadio name='Menu item 3' defaultActionVerb=check checkedState=false
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/action-verbs-expected-win.txt b/content/test/data/accessibility/html/action-verbs-expected-win.txt
new file mode 100644
index 0000000..4f4d94c
--- /dev/null
+++ b/content/test/data/accessibility/html/action-verbs-expected-win.txt
@@ -0,0 +1,31 @@
+ROLE_SYSTEM_DOCUMENT name='Action verbs' READONLY FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_STATICTEXT name='Generic div'
+++IA2_ROLE_HEADING name='Heading'
+++++ROLE_SYSTEM_STATICTEXT name='Heading'
+++ROLE_SYSTEM_PUSHBUTTON name='Button' FOCUSABLE default_action='press' action_name='press'
+++ROLE_SYSTEM_LINK name='Link' FOCUSABLE default_action='jump' action_name='jump'
+++++ROLE_SYSTEM_STATICTEXT name='Link' default_action='click ancestor' action_name='click-ancestor'
+++ROLE_SYSTEM_TEXT FOCUSABLE default_action='activate' action_name='activate'
+++ROLE_SYSTEM_TEXT FOCUSABLE default_action='activate' action_name='activate'
+++ROLE_SYSTEM_TEXT FOCUSABLE IA2_STATE_MULTI_LINE default_action='activate' action_name='activate'
+++ROLE_SYSTEM_TEXT FOCUSABLE default_action='activate' action_name='activate'
+++ROLE_SYSTEM_CHECKBUTTON FOCUSABLE IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check'
+++ROLE_SYSTEM_CHECKBUTTON CHECKED FOCUSABLE IA2_STATE_CHECKABLE checkable:true default_action='uncheck' action_name='uncheck'
+++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check'
+++IA2_ROLE_TOGGLE_BUTTON name='ARIA Switch' FOCUSABLE IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check'
+++ROLE_SYSTEM_GROUPING
+++++ROLE_SYSTEM_PUSHBUTTON name='Summary' COLLAPSED FOCUSABLE default_action='press' action_name='press'
+++++++ROLE_SYSTEM_STATICTEXT name='Summary'
+++ROLE_SYSTEM_COMBOBOX COLLAPSED FOCUSABLE HASPOPUP default_action='open' action_name='open'
+++++ROLE_SYSTEM_LIST INVISIBLE
+++++++ROLE_SYSTEM_LISTITEM name='Pop-up button' SELECTED FOCUSABLE default_action='select' action_name='select'
+++IA2_ROLE_SECTION default_action='click' action_name='click'
+++++ROLE_SYSTEM_STATICTEXT name='Div with click handler' default_action='click ancestor' action_name='click-ancestor'
+++ROLE_SYSTEM_GROUPING default_action='click' action_name='click'
+++++IA2_ROLE_PARAGRAPH default_action='click ancestor' action_name='click-ancestor'
+++++++ROLE_SYSTEM_STATICTEXT name='Paragraph with click handler on parent' default_action='click ancestor' action_name='click-ancestor'
+++ROLE_SYSTEM_MENUPOPUP
+++++ROLE_SYSTEM_MENUITEM name='Menu item 1' default_action='select' action_name='select'
+++++IA2_ROLE_CHECK_MENU_ITEM name='Menu item 2' CHECKED IA2_STATE_CHECKABLE checkable:true default_action='uncheck' action_name='uncheck'
+++++IA2_ROLE_RADIO_MENU_ITEM name='Menu item 3' IA2_STATE_CHECKABLE checkable:true default_action='check' action_name='check'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/action-verbs.html b/content/test/data/accessibility/html/action-verbs.html
index 7f963c9..a51af75 100644
--- a/content/test/data/accessibility/html/action-verbs.html
+++ b/content/test/data/accessibility/html/action-verbs.html
@@ -1,5 +1,7 @@
 <!--
 @BLINK-ALLOW:defaultActionVerb*
+@WIN-ALLOW:default_action*
+@WIN-ALLOW:action_name*
 -->
 <!doctype html>
 <html>
@@ -22,6 +24,9 @@
   <details><summary>Summary</summary>Details</details>
   <select><option>Pop-up button</select>
   <div onclick="alert('success');">Div with click handler</div>
+  <div onclick="alert('success');" role="group">
+    <p>Paragraph with click handler on parent</p>
+  </div>
   <div role="menu">
     <div role="menuitem">Menu item 1</div>
     <div role="menuitemcheckbox" aria-checked="true">Menu item 2</div>
diff --git a/content/test/data/accessibility/html/input-suggestions-source-element-expected-android.txt b/content/test/data/accessibility/html/input-suggestions-source-element-expected-android.txt
index 478c88d4..26abbeb2 100644
--- a/content/test/data/accessibility/html/input-suggestions-source-element-expected-android.txt
+++ b/content/test/data/accessibility/html/input-suggestions-source-element-expected-android.txt
@@ -1,3 +1,3 @@
 android.webkit.WebView focusable focused scrollable
 ++android.view.View
-++++android.widget.Spinner role_description='combo box' clickable focusable input_type=1
\ No newline at end of file
+++++android.widget.Spinner role_description='combo box' clickable editable_text focusable input_type=1
\ No newline at end of file
diff --git a/content/test/data/send-beacon.html b/content/test/data/send-beacon.html
new file mode 100644
index 0000000..a8d5fab7
--- /dev/null
+++ b/content/test/data/send-beacon.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<script>
+navigator.sendBeacon('/beacon', 'hello');
+</script>
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index d909bd0..0275d2c 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -211,10 +211,7 @@
     'GPU Mac Builder (dbg)' : {},
     'GPU Linux Builder' : {},
     'GPU Linux Builder (dbg)' : {},
-    'Linux ChromiumOS Builder' : {
-      'additional_compile_targets' : [ "All" ]
-    },
-    'Linux ChromiumOS Ozone Builder' : {},
+    'GPU Linux Ozone Builder' : {},
   },
 
   'testers': {
@@ -626,7 +623,7 @@
       'os_type': 'linux',
       'instrumentation_type': 'tsan',
     },
-    'Linux ChromiumOS Ozone (Intel)': {
+    'Linux Ozone (Intel)': {
       'swarming_dimensions': [
         {
           'gpu': '8086:1912',
@@ -657,7 +654,6 @@
     'Android Release (Nexus 5X)': {
       'swarming_dimensions': [
         {
-          'android_devices': '1',
           'device_type': 'bullhead',
           'device_os': 'M',
           'os': 'Android'
@@ -730,7 +726,6 @@
     'Android dEQP Release (Nexus 5X)': {
       'swarming_dimensions': [
         {
-          'android_devices': '1',
           'device_type': 'bullhead',
           'device_os': 'M',
           'os': 'Android'
@@ -947,7 +942,6 @@
     'Android Release (Nexus 5X)': {
       'swarming_dimensions': [
         {
-          'android_devices': '1',
           'device_type': 'bullhead',
           'device_os': 'M',
           'os': 'Android'
@@ -981,7 +975,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1015,7 +1009,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1048,7 +1042,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1071,7 +1065,6 @@
         'swarming_dimension_sets': [
           # Nexus 5X
           {
-            'android_devices': '1',
             'device_type': 'bullhead',
             'device_os': 'M',
             'os': 'Android'
@@ -1082,7 +1075,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1109,7 +1102,6 @@
         'swarming_dimension_sets': [
           # Nexus 5X
           {
-            'android_devices': '1',
             'device_type': 'bullhead',
             'device_os': 'M',
             'os': 'Android'
@@ -1120,7 +1112,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1169,7 +1161,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1203,7 +1195,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1234,7 +1226,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1271,7 +1263,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1326,7 +1318,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1363,7 +1355,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
       {
@@ -1381,7 +1373,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1396,7 +1388,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1410,7 +1402,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1430,7 +1422,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
       {
@@ -1450,7 +1442,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1471,7 +1463,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1495,7 +1487,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
       {
@@ -1523,7 +1515,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
           'Mac Experimental Release (Intel)',
           'Mac Experimental Retina Release (AMD)',
           'Mac Experimental Retina Release (NVIDIA)',
@@ -1543,7 +1535,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
         'os_types': ['android'],
       },
@@ -1625,7 +1617,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
         'os_types': ['android'],
       },
@@ -1657,7 +1649,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1672,7 +1664,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1688,7 +1680,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1703,7 +1695,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1725,7 +1717,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
 
           # The Mac ASAN swarming runs on two different GPU types so we can't
           # have one expected vendor ID / device ID
@@ -1753,7 +1745,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1785,7 +1777,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1800,7 +1792,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1815,7 +1807,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1830,7 +1822,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1866,7 +1858,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1888,7 +1880,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
       {
@@ -1937,7 +1929,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1960,7 +1952,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -1985,7 +1977,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
 
           # http://crbug.com/599451: this test is currently too slow
           # to run on x64 in Debug mode. Need to shard the tests.
@@ -2043,7 +2035,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -2088,7 +2080,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
@@ -2161,7 +2153,7 @@
     'disabled_tester_configs': [
       {
         'names': [
-          'Linux ChromiumOS Ozone (Intel)',
+          'Linux Ozone (Intel)',
         ],
       },
     ],
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 02d2e8b..c069fe1 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -59,3 +59,8 @@
 
     self.Flaky('Pixel_OffscreenCanvasWebGLSoftwareCompositingWorker',
         ['mac', ('nvidia', 0xfe9), 'debug'], bug=751328)
+
+    self.Fail('Pixel_DirectComposition_Video_MP4', bug=760132)
+    self.Fail('Pixel_Video_MP4', bug=760132)
+    self.Fail('Pixel_DirectComposition_Video_VP9', bug=760132)
+    self.Fail('Pixel_Video_VP9', bug=760132)
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 945642c3..77be3f0 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -141,13 +141,13 @@
       'pixel_video_mp4.html',
       base_name + '_Video_MP4',
       test_rect=[0, 0, 300, 300],
-      revision=5),
+      revision=6),
 
     PixelTestPage(
       'pixel_video_vp9.html',
       base_name + '_Video_VP9',
       test_rect=[0, 0, 300, 300],
-      revision=5),
+      revision=6),
   ]
 
 
@@ -501,13 +501,13 @@
       'pixel_video_mp4.html',
       base_name + '_DirectComposition_Video_MP4',
       test_rect=[0, 0, 300, 300],
-      revision=4,
+      revision=5,
       browser_args=browser_args),
 
     PixelTestPage(
       'pixel_video_vp9.html',
       base_name + '_DirectComposition_Video_VP9',
       test_rect=[0, 0, 300, 300],
-      revision=5,
+      revision=6,
       browser_args=browser_args),
   ]
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 06e499d..96a79c7 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -1065,6 +1065,9 @@
         'tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html',
         ['linux', ('amd', 0x6613)], bug=701138)
     self.Fail('conformance2/textures/image_data/' +
+        'tex-3d-rgb32f-rgb-float.html',
+        ['linux', ('amd', 0x6613)], bug=701138)
+    self.Fail('conformance2/textures/image_data/' +
         'tex-3d-rgb565-rgb-unsigned_byte.html',
         ['linux', ('amd', 0x6613)], bug=701138)
     self.Fail('conformance2/textures/image_data/' +
diff --git a/content/test/ppapi/ppapi_browsertest.cc b/content/test/ppapi/ppapi_browsertest.cc
index 6fc48bb..02ba5d0 100644
--- a/content/test/ppapi/ppapi_browsertest.cc
+++ b/content/test/ppapi/ppapi_browsertest.cc
@@ -137,8 +137,8 @@
 TEST_PPAPI_IN_PROCESS(TraceEvent)
 TEST_PPAPI_OUT_OF_PROCESS(TraceEvent)
 
-// Doesn't work in GN CrOS ozone builds yet, http://crbug.com/619765
-#if defined(OS_CHROMEOS) && defined(USE_OZONE)
+// Doesn't work in CrOS builds, http://crbug.com/619765
+#if defined(OS_CHROMEOS)
 #define MAYBE_TrueTypeFont DISABLED_TrueTypeFont
 #else
 #define MAYBE_TrueTypeFont TrueTypeFont
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index d6c1bb15..5490e1e 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -31,6 +31,8 @@
     std::move(callback).Run(std::move(reply));
   }
 
+  void IssueKeepAliveHandle(mojom::KeepAliveHandleRequest request) override {}
+
   void Bind(mojo::ScopedInterfaceEndpointHandle handle) {
     binding_.Bind(mojom::FrameHostAssociatedRequest(std::move(handle)));
   }
diff --git a/content/utility/DEPS b/content/utility/DEPS
index 1e371033..af97e099 100644
--- a/content/utility/DEPS
+++ b/content/utility/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+components/scheduler/child",
   "+content/child",
   "+content/network",
   "+content/public/utility",
diff --git a/device/BUILD.gn b/device/BUILD.gn
index a2cfa21..ccc6e58 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -248,6 +248,7 @@
     deps += [
       "//device/vr",
       "//device/vr:fakes",
+      "//device/vr:java",
       "//device/vr:mojo_bindings",
     ]
   }
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 66c7655..eae3eb3 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -47,8 +47,9 @@
         "android/gvr/cardboard_gamepad_data_provider.h",
         "android/gvr/gvr_delegate.cc",
         "android/gvr/gvr_delegate.h",
-        "android/gvr/gvr_delegate_provider.cc",
         "android/gvr/gvr_delegate_provider.h",
+        "android/gvr/gvr_delegate_provider_factory.cc",
+        "android/gvr/gvr_delegate_provider_factory.h",
         "android/gvr/gvr_device.cc",
         "android/gvr/gvr_device.h",
         "android/gvr/gvr_device_provider.cc",
@@ -59,6 +60,7 @@
       ]
 
       deps += [
+        ":jni_headers",
         "//device/gamepad",
         "//device/gamepad/public/cpp:shared_with_blink",
         "//third_party/WebKit/public:blink_headers",
@@ -115,6 +117,24 @@
   }
 }
 
+if (is_android && (current_cpu == "arm" || current_cpu == "arm64")) {
+  java_sources_needing_jni =
+      [ "android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java" ]
+
+  generate_jni("jni_headers") {
+    sources = java_sources_needing_jni
+    jni_package = "device"
+  }
+
+  android_library("java") {
+    java_files = java_sources_needing_jni
+    deps = [
+      "//base:base_java",
+      "//third_party/gvr-android-sdk:gvr_common_java",
+    ]
+  }
+}
+
 mojom_component("mojo_bindings") {
   output_prefix = "device_vr_mojo_bindings"
   macro_prefix = "DEVICE_VR_MOJO_BINDINGS"
diff --git a/device/vr/android/gvr/gvr_delegate_provider.cc b/device/vr/android/gvr/gvr_delegate_provider.cc
deleted file mode 100644
index ecca146..0000000
--- a/device/vr/android/gvr/gvr_delegate_provider.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/vr/android/gvr/gvr_delegate_provider.h"
-
-#include "base/callback.h"
-
-namespace device {
-
-base::Callback<GvrDelegateProvider*()> GvrDelegateProvider::delegate_provider_;
-
-GvrDelegateProvider* GvrDelegateProvider::GetInstance() {
-  if (delegate_provider_.is_null())
-    return nullptr;
-  return delegate_provider_.Run();
-}
-
-void GvrDelegateProvider::SetInstance(
-    const base::Callback<GvrDelegateProvider*()>& provider_callback) {
-  delegate_provider_ = provider_callback;
-}
-
-}  // namespace device
diff --git a/device/vr/android/gvr/gvr_delegate_provider.h b/device/vr/android/gvr/gvr_delegate_provider.h
index 4ee01bb..0344317d 100644
--- a/device/vr/android/gvr/gvr_delegate_provider.h
+++ b/device/vr/android/gvr/gvr_delegate_provider.h
@@ -2,23 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_H
-#define DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_H
+#ifndef DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_H_
+#define DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_H_
 
+#include "base/macros.h"
 #include "device/vr/android/gvr/gvr_device_provider.h"
 #include "device/vr/vr_export.h"
 #include "device/vr/vr_service.mojom.h"
 
+namespace gvr {
+class GvrApi;
+}
+
 namespace device {
 
 class VRDisplayImpl;
 
 class DEVICE_VR_EXPORT GvrDelegateProvider {
  public:
-  static void SetInstance(
-      const base::Callback<GvrDelegateProvider*()>& provider_callback);
-  static GvrDelegateProvider* GetInstance();
-
+  GvrDelegateProvider() = default;
   virtual void SetDeviceId(unsigned int device_id) = 0;
   virtual void RequestWebVRPresent(
       mojom::VRSubmitFrameClientPtr submit_client,
@@ -28,10 +30,13 @@
   virtual void OnDisplayAdded(VRDisplayImpl* display) = 0;
   virtual void OnDisplayRemoved(VRDisplayImpl* display) = 0;
   virtual void OnListeningForActivateChanged(VRDisplayImpl* display) = 0;
+  // TODO(mthiesse): Remove the GvrApi from these calls.
   virtual void CreateVRDisplayInfo(
+      gvr::GvrApi* gvr_api,
       const base::Callback<void(mojom::VRDisplayInfoPtr)>& callback,
       uint32_t device_id) = 0;
   virtual void GetNextMagicWindowPose(
+      gvr::GvrApi* gvr_api,
       VRDisplayImpl* display,
       mojom::VRDisplay::GetNextMagicWindowPoseCallback callback) = 0;
 
@@ -39,9 +44,9 @@
   virtual ~GvrDelegateProvider() {}
 
  private:
-  static base::Callback<GvrDelegateProvider*()> delegate_provider_;
+  DISALLOW_COPY_AND_ASSIGN(GvrDelegateProvider);
 };
 
 }  // namespace device
 
-#endif  // DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_H
+#endif  // DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_H_
diff --git a/device/vr/android/gvr/gvr_delegate_provider_factory.cc b/device/vr/android/gvr/gvr_delegate_provider_factory.cc
new file mode 100644
index 0000000..033fec4
--- /dev/null
+++ b/device/vr/android/gvr/gvr_delegate_provider_factory.cc
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/vr/android/gvr/gvr_delegate_provider_factory.h"
+
+namespace device {
+
+namespace {
+GvrDelegateProviderFactory* g_gvr_delegate_provider_factory = nullptr;
+}  // namespace
+
+// static
+GvrDelegateProvider* GvrDelegateProviderFactory::Create() {
+  if (!g_gvr_delegate_provider_factory)
+    return nullptr;
+  return g_gvr_delegate_provider_factory->CreateGvrDelegateProvider();
+}
+
+// static
+void GvrDelegateProviderFactory::Install(GvrDelegateProviderFactory* f) {
+  if (g_gvr_delegate_provider_factory == f)
+    return;
+  delete g_gvr_delegate_provider_factory;
+  g_gvr_delegate_provider_factory = f;
+}
+
+}  // namespace device
diff --git a/device/vr/android/gvr/gvr_delegate_provider_factory.h b/device/vr/android/gvr/gvr_delegate_provider_factory.h
new file mode 100644
index 0000000..3db3003
--- /dev/null
+++ b/device/vr/android/gvr/gvr_delegate_provider_factory.h
@@ -0,0 +1,33 @@
+// 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 DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_FACTORY_H_
+#define DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_FACTORY_H_
+
+#include "base/macros.h"
+
+#include "device/vr/vr_export.h"
+
+namespace device {
+
+class GvrDelegateProvider;
+
+class DEVICE_VR_EXPORT GvrDelegateProviderFactory {
+ public:
+  static GvrDelegateProvider* Create();
+  static void Install(GvrDelegateProviderFactory* factory);
+
+ protected:
+  GvrDelegateProviderFactory() = default;
+  virtual ~GvrDelegateProviderFactory() = default;
+
+  virtual GvrDelegateProvider* CreateGvrDelegateProvider() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GvrDelegateProviderFactory);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_FACTORY_H_
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 4ff8f53f1..4b76022 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -7,30 +7,53 @@
 #include <math.h>
 #include <algorithm>
 
+#include "base/memory/ptr_util.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "device/vr/android/gvr/gvr_delegate.h"
 #include "device/vr/android/gvr/gvr_delegate_provider.h"
+#include "device/vr/android/gvr/gvr_delegate_provider_factory.h"
 #include "device/vr/android/gvr/gvr_device_provider.h"
 #include "device/vr/vr_device_manager.h"
 #include "device/vr/vr_display_impl.h"
+#include "jni/NonPresentingGvrContext_jni.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/transform.h"
 #include "ui/gfx/transform_util.h"
 
 namespace device {
 
-GvrDevice::GvrDevice() : VRDevice() {
-  GetGvrDelegateProvider();
+std::unique_ptr<GvrDevice> GvrDevice::Create() {
+  std::unique_ptr<GvrDevice> device = base::WrapUnique(new GvrDevice());
+  if (!device->gvr_api_)
+    return nullptr;
+  return device;
 }
 
-GvrDevice::~GvrDevice() {}
+GvrDevice::GvrDevice() : VRDevice() {
+  GetGvrDelegateProvider();
+  JNIEnv* env = base::android::AttachCurrentThread();
+  non_presenting_context_.Reset(Java_NonPresentingGvrContext_create(env));
+  if (!non_presenting_context_.obj())
+    return;
+  jlong context = Java_NonPresentingGvrContext_getNativeGvrContext(
+      env, non_presenting_context_);
+  gvr_api_ = gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context));
+}
+
+GvrDevice::~GvrDevice() {
+  if (!non_presenting_context_.obj())
+    return;
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_NonPresentingGvrContext_shutdown(env, non_presenting_context_);
+}
 
 void GvrDevice::CreateVRDisplayInfo(
     const base::Callback<void(mojom::VRDisplayInfoPtr)>& on_created) {
   GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
   if (delegate_provider) {
-    delegate_provider->CreateVRDisplayInfo(on_created, id());
+    delegate_provider->CreateVRDisplayInfo(gvr_api_.get(), on_created, id());
   } else {
     on_created.Run(nullptr);
   }
@@ -64,7 +87,8 @@
     std::move(callback).Run(nullptr);
     return;
   }
-  delegate_provider->GetNextMagicWindowPose(display, std::move(callback));
+  delegate_provider->GetNextMagicWindowPose(gvr_api_.get(), display,
+                                            std::move(callback));
 }
 
 void GvrDevice::OnDisplayAdded(VRDisplayImpl* display) {
@@ -88,10 +112,18 @@
   delegate_provider->OnListeningForActivateChanged(display);
 }
 
+void GvrDevice::PauseTracking() {
+  gvr_api_->PauseTracking();
+}
+
+void GvrDevice::ResumeTracking() {
+  gvr_api_->ResumeTracking();
+}
+
 GvrDelegateProvider* GvrDevice::GetGvrDelegateProvider() {
-  // GvrDelegateProvider::GetInstance() may fail transiently, so every time we
+  // GvrDelegateProviderFactory::Create() may fail transiently, so every time we
   // try to get it, set the device ID.
-  GvrDelegateProvider* delegate_provider = GvrDelegateProvider::GetInstance();
+  GvrDelegateProvider* delegate_provider = GvrDelegateProviderFactory::Create();
   if (delegate_provider)
     delegate_provider->SetDeviceId(id());
   return delegate_provider;
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h
index 3d487471..8004540 100644
--- a/device/vr/android/gvr/gvr_device.h
+++ b/device/vr/android/gvr/gvr_device.h
@@ -5,8 +5,12 @@
 #ifndef DEVICE_VR_ANDROID_GVR_DEVICE_H
 #define DEVICE_VR_ANDROID_GVR_DEVICE_H
 
+#include <memory>
+
+#include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "device/vr/vr_device.h"
+#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
 namespace device {
 
@@ -15,7 +19,7 @@
 
 class DEVICE_VR_EXPORT GvrDevice : public VRDevice {
  public:
-  GvrDevice();
+  static std::unique_ptr<GvrDevice> Create();
   ~GvrDevice() override;
 
   // VRDevice
@@ -32,10 +36,16 @@
   void OnDisplayAdded(VRDisplayImpl* display) override;
   void OnDisplayRemoved(VRDisplayImpl* display) override;
   void OnListeningForActivateChanged(VRDisplayImpl* display) override;
+  void PauseTracking() override;
+  void ResumeTracking() override;
 
  private:
+  GvrDevice();
   GvrDelegateProvider* GetGvrDelegateProvider();
 
+  base::android::ScopedJavaGlobalRef<jobject> non_presenting_context_;
+  std::unique_ptr<gvr::GvrApi> gvr_api_;
+
   DISALLOW_COPY_AND_ASSIGN(GvrDevice);
 };
 
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index e1f37c07..9cf4633 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -14,11 +14,12 @@
 GvrDeviceProvider::~GvrDeviceProvider() = default;
 
 void GvrDeviceProvider::GetDevices(std::vector<VRDevice*>* devices) {
-  devices->push_back(vr_device_.get());
+  if (vr_device_.get())
+    devices->push_back(vr_device_.get());
 }
 
 void GvrDeviceProvider::Initialize() {
-  vr_device_ = std::make_unique<GvrDevice>();
+  vr_device_ = GvrDevice::Create();
 }
 
 }  // namespace device
diff --git a/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java b/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
new file mode 100644
index 0000000..3328436
--- /dev/null
+++ b/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
@@ -0,0 +1,62 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.device.vr;
+
+import android.content.Context;
+import android.os.StrictMode;
+import android.view.Display;
+import android.view.WindowManager;
+
+import com.google.vr.cardboard.DisplaySynchronizer;
+import com.google.vr.ndk.base.GvrApi;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * Creates an active GvrContext from a GvrApi created from the Application Context. This GvrContext
+ * cannot be used for VR rendering, and should only be used to query pose information and device
+ * parameters.
+ */
+@JNINamespace("device")
+public class NonPresentingGvrContext {
+    private GvrApi mGvrApi;
+
+    private NonPresentingGvrContext() {
+        Context context = ContextUtils.getApplicationContext();
+        WindowManager windowManager =
+                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display display = windowManager.getDefaultDisplay();
+        DisplaySynchronizer synchronizer = new DisplaySynchronizer(context, display);
+
+        // Creating the GvrApi can sometimes create the Daydream config file.
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+        try {
+            mGvrApi = new GvrApi(context, synchronizer);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+    }
+
+    @CalledByNative
+    private static NonPresentingGvrContext create() {
+        try {
+            return new NonPresentingGvrContext();
+        } catch (IllegalStateException | UnsatisfiedLinkError e) {
+            return null;
+        }
+    }
+
+    @CalledByNative
+    private long getNativeGvrContext() {
+        return mGvrApi.getNativeGvrContext();
+    }
+
+    @CalledByNative
+    private void shutdown() {
+        mGvrApi.shutdown();
+    }
+}
diff --git a/device/vr/vr_device.h b/device/vr/vr_device.h
index 995e698..37c2a0e2 100644
--- a/device/vr/vr_device.h
+++ b/device/vr/vr_device.h
@@ -43,12 +43,15 @@
   void RemoveDisplay(VRDisplayImpl* display);
   virtual void OnDisplayAdded(VRDisplayImpl* display) {}
   virtual void OnDisplayRemoved(VRDisplayImpl* display) {}
-  virtual void OnListeningForActivateChanged(VRDisplayImpl* display){};
+  virtual void OnListeningForActivateChanged(VRDisplayImpl* display) {}
 
   bool IsAccessAllowed(VRDisplayImpl* display);
   bool CheckPresentingDisplay(VRDisplayImpl* display);
   VRDisplayImpl* GetPresentingDisplay() { return presenting_display_; }
 
+  virtual void PauseTracking() {}
+  virtual void ResumeTracking() {}
+
   void OnChanged();
   void OnExitPresent();
   void OnBlur();
diff --git a/device/vr/vr_service_impl.cc b/device/vr/vr_service_impl.cc
index 96aa3fac..3e48202 100644
--- a/device/vr/vr_service_impl.cc
+++ b/device/vr/vr_service_impl.cc
@@ -18,10 +18,7 @@
 
 VRServiceImpl::VRServiceImpl(int render_frame_process_id,
                              int render_frame_routing_id)
-    : in_set_client_(false),
-      connected_devices_(0),
-      handled_devices_(0),
-      render_frame_process_id_(render_frame_process_id),
+    : render_frame_process_id_(render_frame_process_id),
       render_frame_routing_id_(render_frame_routing_id),
       weak_ptr_factory_(this) {}
 
diff --git a/device/vr/vr_service_impl.h b/device/vr/vr_service_impl.h
index a338ee0..d1b682d 100644
--- a/device/vr/vr_service_impl.h
+++ b/device/vr/vr_service_impl.h
@@ -52,9 +52,9 @@
 
   mojom::VRServiceClientPtr client_;
 
-  bool in_set_client_;
-  unsigned connected_devices_;
-  unsigned handled_devices_;
+  bool in_set_client_ = false;
+  unsigned connected_devices_ = 0;
+  unsigned handled_devices_ = 0;
   const int render_frame_process_id_;
   const int render_frame_routing_id_;
 
diff --git a/docs/speed/apk_size_regressions.md b/docs/speed/apk_size_regressions.md
index 08bc228..fbf05e0d 100644
--- a/docs/speed/apk_size_regressions.md
+++ b/docs/speed/apk_size_regressions.md
@@ -45,44 +45,6 @@
 
 ## Step 2: File Bug or Silence Alert
 
-### For Static Initializer Alerts
-
-Policy is to revert the offending CL.
-
-File a bug:
-
- * Change the bug's title from `X% regression` to `Static Initializer regression`
- * Assign to yourself, cc the CL author
- * Set description to (replacing **bold** parts):
-
-> Caused by "**First line of commit message**"
->
-> Commit: **abc123abc123abc123abc123abc123abc123abcd**
->
-> Link to size graph:
-> [https://chromeperf.appspot.com/report?sid=2e1421013ce75306cdc0974cbd058b84083ef684dabed256879bacb31613b326&num_points=10&rev=**480214**](https://chromeperf.appspot.com/report?sid=2e1421013ce75306cdc0974cbd058b84083ef684dabed256879bacb31613b326&num_points=10&rev=480214)
->
-> Policy is to revert the CL that added static initializers and reland it with
-> the fix.
->
-> You can verify locally that no static initializers are added by running the
-> following from within an Android checkout:
-> `tools/binary_size/diagnose_bloat.py HEAD -v`
->
-> Common fixes include:
->
->  * Add constexpr,
->  * Use LazyInstance<>,
->  * Use a getter to return a local static variable.
->
-> Thanks!
-
-Then, create a revert of the offending CL with the reasoning "Adds static
-initializers to MonochromePublic.apk" and add the issue number from the issue
-created above to the "BUG: XXXXXX" line in the CL description.
-
-### For Size Alerts
-
 If the code clearly justifies the size increase, silence the alert.
 
 Otherwise, file a bug (TODO: [Make this template automatic](https://github.com/catapult-project/catapult/issues/3150)):
diff --git a/docs/static_initializers.md b/docs/static_initializers.md
new file mode 100644
index 0000000..7fcd3297
--- /dev/null
+++ b/docs/static_initializers.md
@@ -0,0 +1,35 @@
+# Static Initializers
+
+[TOC]
+
+Some background on the original decision to ban static initializers:
+
+http://neugierig.org/software/chromium/notes/2011/08/static-initializers.html
+
+# How Static Initializers are Checked
+
+* For Linux and Mac:
+  * The expected count is stored in [//tools/perf_expectations/perf_expectations.json](https://cs.chromium.org/chromium/src/tools/perf_expectations/perf_expectations.json)
+* For Android:
+  * The expected count is stored in the build target [//chrome/android:monochrome_static_initializers](https://cs.chromium.org/chromium/src/chrome/android/BUILD.gn)
+
+## Removing Static Initializers
+
+Common fixes include:
+
+* Add constexpr,
+* Use LazyInstance<>,
+* Move global variable to be a static variable within a function that returns it.
+
+## Listing Static Initializers
+
+For Linux:
+
+    tools/linux/dump-static-initializers.py out/Release/chrome
+
+For Android:
+
+    build/android/resource_sizes.py --chromium-output-directory out/Release --dump-static-initializers out/Release/apks/MonochromePublic.apk
+    tools/binary_size/diagnose_bloat.py HEAD
+
+For more information about `diagnose_bloat.py`, refer to its [README.md](../tools/binary_size/README.md)
diff --git a/extensions/browser/api/declarative_net_request/BUILD.gn b/extensions/browser/api/declarative_net_request/BUILD.gn
index 48188339..7b5fb78 100644
--- a/extensions/browser/api/declarative_net_request/BUILD.gn
+++ b/extensions/browser/api/declarative_net_request/BUILD.gn
@@ -4,11 +4,16 @@
 
 source_set("declarative_net_request") {
   sources = [
+    "constants.cc",
     "constants.h",
     "flat_ruleset_indexer.cc",
     "flat_ruleset_indexer.h",
     "indexed_rule.cc",
     "indexed_rule.h",
+    "parse_info.cc",
+    "parse_info.h",
+    "utils.cc",
+    "utils.h",
   ]
 
   public_deps = [
diff --git a/extensions/browser/api/declarative_net_request/constants.cc b/extensions/browser/api/declarative_net_request/constants.cc
new file mode 100644
index 0000000..87a39195
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/constants.cc
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/declarative_net_request/constants.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+const char kErrorResourceTypeDuplicated[] =
+    "*: Rule at index * includes and excludes the same resource.";
+const char kErrorEmptyRedirectRuleKey[] =
+    "*: Rule at index * does not specify the value for * key. This is required "
+    "for redirect rules.";
+const char kErrorInvalidRuleKey[] =
+    "*: Rule at index * has an invalid value for * key. This should be greater "
+    "than or equal to *.";
+const char kErrorNoApplicableResourceTypes[] =
+    "*: Rule at index * is not applicable to any resource type.";
+const char kErrorEmptyList[] =
+    "*: Rule at index * cannot have an empty list as the value for * key.";
+const char kErrorEmptyUrlFilter[] =
+    "*: Rule at index * cannot have an empty value for * key.";
+const char kErrorInvalidRedirectUrl[] =
+    "*: Rule at index * does not provide a valid URL for * key.";
+const char kErrorListNotPassed[] = "*: Rules file does not have a valid list.";
+const char kErrorDuplicateIDs[] =
+    "*: Rule at index * does not have a unique ID.";
+// Don't surface the actual error to the user, since it's an implementation
+// detail.
+const char kErrorPersisting[] = "*: Rules file could not be parsed.";
+
+const char kRulesNotParsedWarning[] =
+    "Declarative Net Request: Not all rules were successfully parsed.";
+
+const char kIDKey[] = "id";
+const char kPriorityKey[] = "priority";
+const char kUrlFilterKey[] = "urlFilter";
+const char kIsUrlFilterCaseSensitiveKey[] = "isUrlFilterCaseSensitive";
+const char kDomainsKey[] = "domains";
+const char kResourceTypesKey[] = "resourceTypes";
+const char kRedirectUrlKey[] = "redirectUrl";
+
+const char kIndexAndPersistRulesTimeHistogram[] =
+    "Extensions.DeclarativeNetRequest.IndexAndPersistRulesTime";
+const char kIndexRulesTimeHistogram[] =
+    "Extensions.DeclarativeNetRequest.IndexRulesTime";
+const char kManifestRulesCountHistogram[] =
+    "Extensions.DeclarativeNetRequest.ManifestRulesCount";
+
+}  // namespace declarative_net_request
+}  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/constants.h b/extensions/browser/api/declarative_net_request/constants.h
index e165da1..5aee04fc 100644
--- a/extensions/browser/api/declarative_net_request/constants.h
+++ b/extensions/browser/api/declarative_net_request/constants.h
@@ -8,7 +8,8 @@
 namespace extensions {
 namespace declarative_net_request {
 
-// The result of parsing a JSON rule provided by an extension.
+// The result of parsing JSON rules provided by an extension. Can correspond to
+// a single or multiple rules.
 enum class ParseResult {
   SUCCESS,
   ERROR_RESOURCE_TYPE_DUPLICATED,
@@ -21,8 +22,26 @@
   ERROR_EMPTY_RESOURCE_TYPES_LIST,
   ERROR_EMPTY_URL_FILTER,
   ERROR_INVALID_REDIRECT_URL,
+  ERROR_LIST_NOT_PASSED,
+  ERROR_DUPLICATE_IDS,
+  ERROR_PERSISTING_RULESET,
 };
 
+// Rule parsing errors.
+extern const char kErrorResourceTypeDuplicated[];
+extern const char kErrorEmptyRedirectRuleKey[];
+extern const char kErrorInvalidRuleKey[];
+extern const char kErrorNoApplicableResourceTypes[];
+extern const char kErrorEmptyList[];
+extern const char kErrorEmptyUrlFilter[];
+extern const char kErrorInvalidRedirectUrl[];
+extern const char kErrorListNotPassed[];
+extern const char kErrorDuplicateIDs[];
+extern const char kErrorPersisting[];
+
+// Rule parsing install warnings.
+extern const char kRulesNotParsedWarning[];
+
 // Minimum valid value of a declarative rule ID.
 constexpr int kMinValidID = 1;
 
@@ -32,6 +51,21 @@
 // Default priority used for rules when the priority is not explicity provided
 // by an extension.
 constexpr int kDefaultPriority = 1;
+
+// Keys used in rules.
+extern const char kIDKey[];
+extern const char kPriorityKey[];
+extern const char kUrlFilterKey[];
+extern const char kIsUrlFilterCaseSensitiveKey[];
+extern const char kDomainsKey[];
+extern const char kResourceTypesKey[];
+extern const char kRedirectUrlKey[];
+
+// Histogram names.
+extern const char kIndexAndPersistRulesTimeHistogram[];
+extern const char kIndexRulesTimeHistogram[];
+extern const char kManifestRulesCountHistogram[];
+
 }  // namespace declarative_net_request
 }  // namespace extensions
 
diff --git a/extensions/browser/api/declarative_net_request/parse_info.cc b/extensions/browser/api/declarative_net_request/parse_info.cc
new file mode 100644
index 0000000..9fdebadf
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/parse_info.cc
@@ -0,0 +1,102 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/declarative_net_request/parse_info.h"
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "extensions/common/error_utils.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+ParseInfo::ParseInfo(ParseResult result) : result_(result) {}
+ParseInfo::ParseInfo(ParseResult result, size_t rule_index)
+    : result_(result), rule_index_(rule_index) {}
+ParseInfo::ParseInfo(const ParseInfo&) = default;
+ParseInfo& ParseInfo::operator=(const ParseInfo&) = default;
+
+std::string ParseInfo::GetErrorDescription(
+    const base::StringPiece json_rules_filename) const {
+  // Every error except ERROR_PERSISTING_RULESET and ERROR_LIST_NOT_PASSED
+  // requires |rule_index_|.
+  DCHECK_EQ(!rule_index_.has_value(),
+            result_ == ParseResult::ERROR_LIST_NOT_PASSED ||
+                result_ == ParseResult::ERROR_PERSISTING_RULESET);
+
+  std::string error;
+  switch (result_) {
+    case ParseResult::SUCCESS:
+      NOTREACHED();
+      break;
+    case ParseResult::ERROR_RESOURCE_TYPE_DUPLICATED:
+      error = ErrorUtils::FormatErrorMessage(kErrorResourceTypeDuplicated,
+                                             json_rules_filename,
+                                             std::to_string(*rule_index_));
+      break;
+    case ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorEmptyRedirectRuleKey, json_rules_filename,
+          std::to_string(*rule_index_), kPriorityKey);
+      break;
+    case ParseResult::ERROR_EMPTY_REDIRECT_URL:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorEmptyRedirectRuleKey, json_rules_filename,
+          std::to_string(*rule_index_), kRedirectUrlKey);
+      break;
+    case ParseResult::ERROR_INVALID_RULE_ID:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorInvalidRuleKey, json_rules_filename,
+          std::to_string(*rule_index_), kIDKey, std::to_string(kMinValidID));
+      break;
+    case ParseResult::ERROR_INVALID_REDIRECT_RULE_PRIORITY:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorInvalidRuleKey, json_rules_filename,
+          std::to_string(*rule_index_), kPriorityKey,
+          std::to_string(kMinValidPriority));
+      break;
+    case ParseResult::ERROR_NO_APPLICABLE_RESOURCE_TYPES:
+      error = ErrorUtils::FormatErrorMessage(kErrorNoApplicableResourceTypes,
+                                             json_rules_filename,
+                                             std::to_string(*rule_index_));
+      break;
+    case ParseResult::ERROR_EMPTY_DOMAINS_LIST:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorEmptyList, json_rules_filename, std::to_string(*rule_index_),
+          kDomainsKey);
+      break;
+    case ParseResult::ERROR_EMPTY_RESOURCE_TYPES_LIST:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorEmptyList, json_rules_filename, std::to_string(*rule_index_),
+          kResourceTypesKey);
+      break;
+    case ParseResult::ERROR_EMPTY_URL_FILTER:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorEmptyUrlFilter, json_rules_filename,
+          std::to_string(*rule_index_), kUrlFilterKey);
+      break;
+    case ParseResult::ERROR_INVALID_REDIRECT_URL:
+      error = ErrorUtils::FormatErrorMessage(
+          kErrorInvalidRedirectUrl, json_rules_filename,
+          std::to_string(*rule_index_), kRedirectUrlKey);
+      break;
+    case ParseResult::ERROR_LIST_NOT_PASSED:
+      error = ErrorUtils::FormatErrorMessage(kErrorListNotPassed,
+                                             json_rules_filename);
+      break;
+    case ParseResult::ERROR_DUPLICATE_IDS:
+      error = ErrorUtils::FormatErrorMessage(kErrorDuplicateIDs,
+                                             json_rules_filename,
+                                             std::to_string(*rule_index_));
+      break;
+    case ParseResult::ERROR_PERSISTING_RULESET:
+      error =
+          ErrorUtils::FormatErrorMessage(kErrorPersisting, json_rules_filename);
+      break;
+  }
+  return error;
+}
+
+}  // namespace declarative_net_request
+}  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/parse_info.h b/extensions/browser/api/declarative_net_request/parse_info.h
new file mode 100644
index 0000000..aae037c
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/parse_info.h
@@ -0,0 +1,44 @@
+// 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 EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_PARSE_INFO_H_
+#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_PARSE_INFO_H_
+
+#include <stddef.h>
+#include <string>
+
+#include "base/optional.h"
+#include "base/strings/string_piece_forward.h"
+#include "extensions/browser/api/declarative_net_request/constants.h"
+
+namespace extensions {
+namespace declarative_net_request {
+
+// Holds the ParseResult together with the index of the rule at which the error
+// occurred, if any.
+class ParseInfo {
+ public:
+  explicit ParseInfo(ParseResult result);
+  ParseInfo(ParseResult result, size_t rule_index);
+  ParseInfo(const ParseInfo&);
+  ParseInfo& operator=(const ParseInfo&);
+
+  ParseResult result() const { return result_; }
+
+  // Returns the error string corresponding to this ParseInfo. Should not be
+  // called on a successful parse.
+  std::string GetErrorDescription(
+      const base::StringPiece json_rules_filename) const;
+
+ private:
+  ParseResult result_;
+  // When set, denotes the index of the rule with which the |result_| is
+  // associated.
+  base::Optional<size_t> rule_index_;
+};
+
+}  // namespace declarative_net_request
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_PARSE_INFO_H_
diff --git a/extensions/browser/api/declarative_net_request/utils.cc b/extensions/browser/api/declarative_net_request/utils.cc
new file mode 100644
index 0000000..191cfbc8
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/utils.cc
@@ -0,0 +1,156 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/declarative_net_request/utils.h"
+
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/timer/elapsed_timer.h"
+#include "base/values.h"
+#include "extensions/browser/api/declarative_net_request/constants.h"
+#include "extensions/browser/api/declarative_net_request/flat_ruleset_indexer.h"
+#include "extensions/browser/api/declarative_net_request/indexed_rule.h"
+#include "extensions/browser/api/declarative_net_request/parse_info.h"
+#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
+#include "extensions/common/api/declarative_net_request/utils.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/install_warning.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+namespace declarative_net_request {
+namespace {
+
+// Name of the indexed ruleset file for the Declarative Net Request API.
+const base::FilePath::CharType kIndexedRulesetFilename[] =
+    FILE_PATH_LITERAL("_generated_indexed_ruleset");
+
+namespace dnr_api = extensions::api::declarative_net_request;
+
+// Helper function to persist the indexed ruleset |data| for |extension|.
+bool PersistRuleset(const Extension& extension,
+                    const FlatRulesetIndexer::SerializedData& data) {
+  const base::FilePath path = GetIndexedRulesetPath(extension.path());
+
+  // Create the directory corresponding to |path| if it does not exist and then
+  // persist the ruleset.
+  const int data_size = base::checked_cast<int>(data.second);
+  return base::CreateDirectory(path.DirName()) &&
+         base::WriteFile(path, reinterpret_cast<const char*>(data.first),
+                         data_size) == data_size;
+}
+
+// Helper to retrieve the ruleset ExtensionResource for |extension|.
+const ExtensionResource* GetRulesetResource(const Extension& extension) {
+  return declarative_net_request::DNRManifestData::GetRulesetResource(
+      &extension);
+}
+
+// Helper to retrieve the filename of the JSON ruleset provided by |extension|.
+std::string GetJSONRulesetFilename(const Extension& extension) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  return GetRulesetResource(extension)->GetFilePath().BaseName().AsUTF8Unsafe();
+}
+
+// Helper function to index |rules| and persist them to the
+// |indexed_ruleset_path|.
+ParseInfo IndexAndPersistRulesImpl(const base::Value& rules,
+                                   const Extension& extension,
+                                   std::vector<InstallWarning>* warnings) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (!rules.is_list())
+    return ParseInfo(ParseResult::ERROR_LIST_NOT_PASSED);
+
+  FlatRulesetIndexer indexer;
+  bool all_rules_parsed = true;
+  base::ElapsedTimer timer;
+  {
+    std::set<int> id_set;  // Ensure all ids are distinct.
+    std::unique_ptr<dnr_api::Rule> parsed_rule;
+
+    const auto& rules_list = rules.GetList();
+    for (size_t i = 0; i < rules_list.size(); i++) {
+      parsed_rule = dnr_api::Rule::FromValue(rules_list[i]);
+
+      // Ignore rules which can't be successfully parsed and show an install
+      // warning for them.
+      if (!parsed_rule) {
+        all_rules_parsed = false;
+        continue;
+      }
+
+      bool inserted = id_set.insert(parsed_rule->id).second;
+      if (!inserted)
+        return ParseInfo(ParseResult::ERROR_DUPLICATE_IDS, i);
+
+      IndexedRule indexed_rule;
+      ParseResult parse_result =
+          IndexedRule::CreateIndexedRule(std::move(parsed_rule), &indexed_rule);
+      if (parse_result != ParseResult::SUCCESS)
+        return ParseInfo(parse_result, i);
+
+      indexer.AddUrlRule(indexed_rule);
+    }
+  }
+  indexer.Finish();
+  UMA_HISTOGRAM_TIMES(kIndexRulesTimeHistogram, timer.Elapsed());
+
+  // The actual data buffer is still owned by |indexer|.
+  const FlatRulesetIndexer::SerializedData data = indexer.GetData();
+  if (!PersistRuleset(extension, data))
+    return ParseInfo(ParseResult::ERROR_PERSISTING_RULESET);
+
+  if (!all_rules_parsed && warnings) {
+    warnings->push_back(InstallWarning(
+        kRulesNotParsedWarning, manifest_keys::kDeclarativeNetRequestKey,
+        manifest_keys::kDeclarativeRuleResourcesKey));
+  }
+
+  UMA_HISTOGRAM_TIMES(kIndexAndPersistRulesTimeHistogram, timer.Elapsed());
+  UMA_HISTOGRAM_COUNTS_100000(kManifestRulesCountHistogram,
+                              indexer.indexed_rules_count());
+
+  return ParseInfo(ParseResult::SUCCESS);
+}
+
+}  // namespace
+
+bool IndexAndPersistRules(const base::Value& rules,
+                          const Extension& extension,
+                          std::string* error,
+                          std::vector<InstallWarning>* warnings) {
+  DCHECK(IsAPIAvailable());
+  DCHECK(GetRulesetResource(extension));
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // TODO(crbug.com/696822): While persisting the ruleset, store the ruleset
+  // checksum, probably as part of preferences. This would help in verifying the
+  // ruleset while loading and help us ascertain quickly whether a ruleset
+  // corresponding to an extension exists.
+
+  const ParseInfo info = IndexAndPersistRulesImpl(rules, extension, warnings);
+  if (info.result() == ParseResult::SUCCESS)
+    return true;
+
+  if (error)
+    *error = info.GetErrorDescription(GetJSONRulesetFilename(extension));
+  return false;
+}
+
+base::FilePath GetIndexedRulesetPath(const base::FilePath& extension_path) {
+  DCHECK(IsAPIAvailable());
+
+  return extension_path.Append(kMetadataFolder).Append(kIndexedRulesetFilename);
+}
+
+}  // namespace declarative_net_request
+}  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/utils.h b/extensions/browser/api/declarative_net_request/utils.h
new file mode 100644
index 0000000..a9f99703
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/utils.h
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_UTILS_H_
+#define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_UTILS_H_
+
+namespace base {
+class FilePath;
+class Value;
+}  // namespace base
+
+namespace extensions {
+class Extension;
+struct InstallWarning;
+
+namespace declarative_net_request {
+
+// Indexes and persists |rules| for |extension|. In case of an error, returns
+// false and populates |error|.
+// Note: This must be called on a thread where file IO is allowed.
+bool IndexAndPersistRules(const base::Value& rules,
+                          const Extension& extension,
+                          std::string* error,
+                          std::vector<InstallWarning>* warnings);
+
+// Returns the path where the indexed ruleset file should be persisted for
+// |extension_path|.
+base::FilePath GetIndexedRulesetPath(const base::FilePath& extension_path);
+
+}  // namespace declarative_net_request
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_UTILS_H_
diff --git a/extensions/common/api/declarative_net_request/dnr_manifest_data.h b/extensions/common/api/declarative_net_request/dnr_manifest_data.h
index 5abe7a7..cd7e44dd 100644
--- a/extensions/common/api/declarative_net_request/dnr_manifest_data.h
+++ b/extensions/common/api/declarative_net_request/dnr_manifest_data.h
@@ -21,6 +21,7 @@
   // Returns ExtensionResource corresponding to the kDeclarativeNetRequestKey
   // manifest key for the |extension|. Returns null if the extension didn't
   // specify the manifest key.
+  // TODO(karandeepb): Change this so that it accepts a const reference.
   static const ExtensionResource* GetRulesetResource(
       const Extension* extension);
 
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
index b18769a..f013f13 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
@@ -178,7 +178,7 @@
 
 void MimeHandlerViewContainer::PluginDidFinishLoading() {
   DCHECK(!is_embedded_);
-  CreateMimeHandlerViewGuest();
+  CreateMimeHandlerViewGuestIfNecessary();
 }
 
 void MimeHandlerViewContainer::OnRenderFrameDestroyed() {
@@ -194,6 +194,7 @@
 void MimeHandlerViewContainer::DidResizeElement(const gfx::Size& new_size) {
   element_size_ = new_size;
 
+  CreateMimeHandlerViewGuestIfNecessary();
   render_frame()->Send(new ExtensionsGuestViewHostMsg_ResizeGuest(
       render_frame()->GetRoutingID(), element_instance_id(), new_size));
 }
@@ -215,7 +216,7 @@
 
 void MimeHandlerViewContainer::DidFinishLoading(double /* unused */) {
   DCHECK(is_embedded_);
-  CreateMimeHandlerViewGuest();
+  CreateMimeHandlerViewGuestIfNecessary();
 }
 
 void MimeHandlerViewContainer::PostMessage(v8::Isolate* isolate,
@@ -307,7 +308,10 @@
   pending_messages_.clear();
 }
 
-void MimeHandlerViewContainer::CreateMimeHandlerViewGuest() {
+void MimeHandlerViewContainer::CreateMimeHandlerViewGuestIfNecessary() {
+  if (guest_created_ || element_size_.IsEmpty() || view_id_.empty())
+    return;
+
   // The loader has completed loading |view_id_| so we can dispose it.
   if (loader_) {
     DCHECK(is_embedded_);
@@ -323,6 +327,8 @@
       new ExtensionsGuestViewHostMsg_CreateMimeHandlerViewGuest(
           render_frame()->GetRoutingID(), view_id_, element_instance_id(),
           element_size_));
+
+  guest_created_ = true;
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
index 7f5915c..0bf9476 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
@@ -83,7 +83,9 @@
                        int guest_proxy_routing_id);
   void OnMimeHandlerViewGuestOnLoadCompleted(int element_instance_id);
 
-  void CreateMimeHandlerViewGuest();
+  // Creates a guest when a geometry and the URL of the extension to navigate
+  // to are available.
+  void CreateMimeHandlerViewGuestIfNecessary();
 
   // The MIME type of the plugin.
   const std::string mime_type_;
@@ -112,6 +114,9 @@
   // delivered so that messages aren't lost.
   std::vector<v8::Global<v8::Value>> pending_messages_;
 
+  // True if a guest process has been requested.
+  bool guest_created_ = false;
+
   // True if the guest page has fully loaded and its JavaScript onload function
   // has been called.
   bool guest_loaded_;
diff --git a/extensions/shell/browser/media_capture_util.cc b/extensions/shell/browser/media_capture_util.cc
index fe2db183..90b3df5d 100644
--- a/extensions/shell/browser/media_capture_util.cc
+++ b/extensions/shell/browser/media_capture_util.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/shell/browser/media_capture_util.h"
 
+#include <algorithm>
 #include <string>
 #include <utility>
 
@@ -20,18 +21,28 @@
 
 namespace extensions {
 
+namespace {
+
 const MediaStreamDevice* GetRequestedDeviceOrDefault(
     const MediaStreamDevices& devices,
     const std::string& requested_device_id) {
-  if (!requested_device_id.empty())
-    return devices.FindById(requested_device_id);
+  if (!requested_device_id.empty()) {
+    auto it = std::find_if(
+        devices.begin(), devices.end(),
+        [requested_device_id](const content::MediaStreamDevice& device) {
+          return device.id == requested_device_id;
+        });
+    return it != devices.end() ? &(*it) : nullptr;
+  }
 
   if (!devices.empty())
     return &devices[0];
 
-  return NULL;
+  return nullptr;
 }
 
+}  // namespace
+
 namespace media_capture_util {
 
 // See also Chrome's MediaCaptureDevicesDispatcher.
diff --git a/google_apis/test/service_login.html b/google_apis/test/service_login.html
index d605707..351d4cb 100644
--- a/google_apis/test/service_login.html
+++ b/google_apis/test/service_login.html
@@ -52,7 +52,7 @@
 
 function onAuthError() {
   if (window.domAutomationController) {
-    window.domAutomationController.sendWithId(4444, 'loginfail');
+    window.domAutomationController.send(4444, 'loginfail');
   }
 }
 
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 316a337..f038996 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -39,49 +39,6 @@
 
 }  // anonymous namespace.
 
-class FeatureInfo::StringSet {
- public:
-  StringSet() {}
-
-  StringSet(const char* s) {
-    Init(s);
-  }
-
-  StringSet(const std::string& str) {
-    Init(str);
-  }
-
-  StringSet(const std::vector<std::string>& strs) {
-    string_set_.insert(strs.begin(), strs.end());
-  }
-
-  void Init(const char* s) {
-    std::string str(s ? s : "");
-    Init(str);
-  }
-
-  void Init(const std::string& str) {
-    std::vector<std::string> tokens = base::SplitString(
-        str, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-    string_set_.insert(tokens.begin(), tokens.end());
-  }
-
-  bool Contains(const char* s) const {
-    return string_set_.find(s) != string_set_.end();
-  }
-
-  bool Contains(const std::string& s) const {
-    return string_set_.find(s) != string_set_.end();
-  }
-
-  const std::set<std::string>& GetImpl() {
-    return string_set_;
-  }
-
- private:
-  std::set<std::string> string_set_;
-};
-
 namespace {
 
 class ScopedPixelUnpackBufferOverride {
@@ -405,7 +362,8 @@
 
 void FeatureInfo::InitializeFeatures() {
   // Figure out what extensions to turn on.
-  StringSet extensions(gl::GetGLExtensionsFromCurrentContext());
+  std::string extensions_string(gl::GetGLExtensionsFromCurrentContext());
+  gl::ExtensionSet extensions(gl::MakeExtensionSet(extensions_string));
 
   const char* version_str =
       reinterpret_cast<const char*>(glGetString(GL_VERSION));
@@ -413,7 +371,7 @@
       reinterpret_cast<const char*>(glGetString(GL_RENDERER));
 
   gl_version_info_.reset(
-      new gl::GLVersionInfo(version_str, renderer_str, extensions.GetImpl()));
+      new gl::GLVersionInfo(version_str, renderer_str, extensions));
 
   bool enable_es3 = IsWebGL2OrES3Context();
 
@@ -451,7 +409,7 @@
   if (!disallowed_features_.gpu_memory_manager)
     AddExtensionString("GL_CHROMIUM_gpu_memory_manager");
 
-  if (extensions.Contains("GL_ANGLE_translated_shader_source")) {
+  if (gl::HasExtension(extensions, "GL_ANGLE_translated_shader_source")) {
     feature_flags_.angle_translated_shader_source = true;
   }
 
@@ -460,13 +418,17 @@
   bool enable_dxt1 = false;
   bool enable_dxt3 = false;
   bool enable_dxt5 = false;
-  bool have_s3tc = extensions.Contains("GL_EXT_texture_compression_s3tc");
+  bool have_s3tc =
+      gl::HasExtension(extensions, "GL_EXT_texture_compression_s3tc");
   bool have_dxt3 =
-      have_s3tc || extensions.Contains("GL_ANGLE_texture_compression_dxt3");
+      have_s3tc ||
+      gl::HasExtension(extensions, "GL_ANGLE_texture_compression_dxt3");
   bool have_dxt5 =
-      have_s3tc || extensions.Contains("GL_ANGLE_texture_compression_dxt5");
+      have_s3tc ||
+      gl::HasExtension(extensions, "GL_ANGLE_texture_compression_dxt5");
 
-  if (extensions.Contains("GL_EXT_texture_compression_dxt1") || have_s3tc) {
+  if (gl::HasExtension(extensions, "GL_EXT_texture_compression_dxt1") ||
+      have_s3tc) {
     enable_dxt1 = true;
   }
   if (have_dxt3) {
@@ -515,7 +477,8 @@
         GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
   }
 
-  bool have_astc = extensions.Contains("GL_KHR_texture_compression_astc_ldr");
+  bool have_astc =
+      gl::HasExtension(extensions, "GL_KHR_texture_compression_astc_ldr");
   if (have_astc) {
     feature_flags_.ext_texture_format_astc = true;
     AddExtensionString("GL_KHR_texture_compression_astc_ldr");
@@ -537,8 +500,9 @@
     }
   }
 
-  bool have_atc = extensions.Contains("GL_AMD_compressed_ATC_texture") ||
-                  extensions.Contains("GL_ATI_texture_compression_atitc");
+  bool have_atc =
+      gl::HasExtension(extensions, "GL_AMD_compressed_ATC_texture") ||
+      gl::HasExtension(extensions, "GL_ATI_texture_compression_atitc");
   if (have_atc) {
     feature_flags_.ext_texture_format_atc = true;
 
@@ -553,7 +517,7 @@
   }
 
   // Check if we should enable GL_EXT_texture_filter_anisotropic.
-  if (extensions.Contains("GL_EXT_texture_filter_anisotropic")) {
+  if (gl::HasExtension(extensions, "GL_EXT_texture_filter_anisotropic")) {
     AddExtensionString("GL_EXT_texture_filter_anisotropic");
     validators_.texture_parameter.AddValue(
         GL_TEXTURE_MAX_ANISOTROPY_EXT);
@@ -576,9 +540,9 @@
   bool enable_depth_texture = false;
   GLenum depth_texture_format = GL_NONE;
   if (!workarounds_.disable_depth_texture &&
-      (extensions.Contains("GL_ARB_depth_texture") ||
-       extensions.Contains("GL_OES_depth_texture") ||
-       extensions.Contains("GL_ANGLE_depth_texture") ||
+      (gl::HasExtension(extensions, "GL_ARB_depth_texture") ||
+       gl::HasExtension(extensions, "GL_OES_depth_texture") ||
+       gl::HasExtension(extensions, "GL_ANGLE_depth_texture") ||
        gl_version_info_->is_desktop_core_profile)) {
     // Note that we don't expose depth_texture extenion on top of ES3 if
     // the depth_texture extension isn't exposed by the ES3 driver.
@@ -587,7 +551,7 @@
     enable_depth_texture = true;
     depth_texture_format = GL_DEPTH_COMPONENT;
     feature_flags_.angle_depth_texture =
-        extensions.Contains("GL_ANGLE_depth_texture");
+        gl::HasExtension(extensions, "GL_ANGLE_depth_texture");
   }
 
   if (enable_depth_texture) {
@@ -602,10 +566,9 @@
   }
 
   GLenum depth_stencil_texture_format = GL_NONE;
-  if (extensions.Contains("GL_EXT_packed_depth_stencil") ||
-      extensions.Contains("GL_OES_packed_depth_stencil") ||
-      gl_version_info_->is_es3 ||
-      gl_version_info_->is_desktop_core_profile) {
+  if (gl::HasExtension(extensions, "GL_EXT_packed_depth_stencil") ||
+      gl::HasExtension(extensions, "GL_OES_packed_depth_stencil") ||
+      gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile) {
     AddExtensionString("GL_OES_packed_depth_stencil");
     feature_flags_.packed_depth24_stencil8 = true;
     if (enable_depth_texture) {
@@ -635,11 +598,10 @@
     }
   }
 
-  if (gl_version_info_->is_es3 ||
-      gl_version_info_->is_desktop_core_profile ||
-      extensions.Contains("GL_OES_vertex_array_object") ||
-      extensions.Contains("GL_ARB_vertex_array_object") ||
-      extensions.Contains("GL_APPLE_vertex_array_object")) {
+  if (gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile ||
+      gl::HasExtension(extensions, "GL_OES_vertex_array_object") ||
+      gl::HasExtension(extensions, "GL_ARB_vertex_array_object") ||
+      gl::HasExtension(extensions, "GL_APPLE_vertex_array_object")) {
     feature_flags_.native_vertex_array_object = true;
   }
 
@@ -651,7 +613,7 @@
   }
 
   if (gl_version_info_->is_es3 ||
-      extensions.Contains("GL_OES_element_index_uint") ||
+      gl::HasExtension(extensions, "GL_OES_element_index_uint") ||
       gl::HasDesktopGLFeatures()) {
     AddExtensionString("GL_OES_element_index_uint");
     validators_.index_type.AddValue(GL_UNSIGNED_INT);
@@ -660,8 +622,8 @@
   bool has_srgb_framebuffer_support = false;
   if (gl_version_info_->IsAtLeastGL(3, 2) ||
       (gl_version_info_->IsAtLeastGL(2, 0) &&
-       (extensions.Contains("GL_EXT_framebuffer_sRGB") ||
-        extensions.Contains("GL_ARB_framebuffer_sRGB")))) {
+       (gl::HasExtension(extensions, "GL_EXT_framebuffer_sRGB") ||
+        gl::HasExtension(extensions, "GL_ARB_framebuffer_sRGB")))) {
     feature_flags_.desktop_srgb_support = true;
     has_srgb_framebuffer_support = true;
   }
@@ -672,10 +634,10 @@
   // <format> in this case. So, even with GLES3 explicitly check for
   // GL_EXT_sRGB.
   if ((((gl_version_info_->is_es3 ||
-         extensions.Contains("GL_OES_rgb8_rgba8")) &&
-        extensions.Contains("GL_EXT_sRGB")) ||
+         gl::HasExtension(extensions, "GL_OES_rgb8_rgba8")) &&
+        gl::HasExtension(extensions, "GL_EXT_sRGB")) ||
        feature_flags_.desktop_srgb_support) &&
-       IsWebGL1OrES2Context()) {
+      IsWebGL1OrES2Context()) {
     feature_flags_.ext_srgb = true;
     AddExtensionString("GL_EXT_sRGB");
     validators_.texture_internal_format.AddValue(GL_SRGB_EXT);
@@ -698,7 +660,7 @@
     // and the desktop extension GL_ARB_framebuffer_sRGB (part of the core in
     // 3.0).
     if (feature_flags_.desktop_srgb_support ||
-        extensions.Contains("GL_EXT_sRGB_write_control")) {
+        gl::HasExtension(extensions, "GL_EXT_sRGB_write_control")) {
       feature_flags_.ext_srgb_write_control = true;
       AddExtensionString("GL_EXT_sRGB_write_control");
       validators_.capability.AddValue(GL_FRAMEBUFFER_SRGB_EXT);
@@ -706,7 +668,8 @@
   }
 
   // The extension GL_EXT_texture_sRGB_decode is the same on desktop and GLES.
-  if (extensions.Contains("GL_EXT_texture_sRGB_decode") && !IsWebGLContext()) {
+  if (gl::HasExtension(extensions, "GL_EXT_texture_sRGB_decode") &&
+      !IsWebGLContext()) {
     AddExtensionString("GL_EXT_texture_sRGB_decode");
     validators_.texture_parameter.AddValue(GL_TEXTURE_SRGB_DECODE_EXT);
   }
@@ -716,17 +679,19 @@
     // On mobile, the only extension that supports S3TC+sRGB is NV_sRGB_formats.
     // The draft extension EXT_texture_compression_s3tc_srgb also supports it
     // and is used if available (e.g. if ANGLE exposes it).
-    have_s3tc_srgb = extensions.Contains("GL_NV_sRGB_formats") ||
-        extensions.Contains("GL_EXT_texture_compression_s3tc_srgb");
+    have_s3tc_srgb =
+        gl::HasExtension(extensions, "GL_NV_sRGB_formats") ||
+        gl::HasExtension(extensions, "GL_EXT_texture_compression_s3tc_srgb");
   } else {
     // On desktop, strictly-speaking, S3TC+sRGB is only available if both
     // EXT_texture_sRGB and EXT_texture_compression_s3tc_srgb are available.
     //
     // However, on macOS, S3TC+sRGB is supported on OpenGL 4.1 with only
     // EXT_texture_compression_s3tc_srgb, so we allow that as well.
-    if (extensions.Contains("GL_EXT_texture_sRGB") ||
+    if (gl::HasExtension(extensions, "GL_EXT_texture_sRGB") ||
         gl_version_info_->IsAtLeastGL(4, 1)) {
-      have_s3tc_srgb = extensions.Contains("GL_EXT_texture_compression_s3tc");
+      have_s3tc_srgb =
+          gl::HasExtension(extensions, "GL_EXT_texture_compression_s3tc");
     }
   }
 
@@ -766,13 +731,17 @@
   // In WebGL contexts, BRGA is used for hardware overlay and WebGL 2.0 exposes
   // glTexStorage2D. WebGL never uses both BGRA and glTexStorage2D together
   // because WebGL API doesn't expose BGRA format. So allow both.
-  bool has_apple_bgra = extensions.Contains("GL_APPLE_texture_format_BGRA8888");
-  bool has_ext_bgra = extensions.Contains("GL_EXT_texture_format_BGRA8888");
+  bool has_apple_bgra =
+      gl::HasExtension(extensions, "GL_APPLE_texture_format_BGRA8888");
+  bool has_ext_bgra =
+      gl::HasExtension(extensions, "GL_EXT_texture_format_BGRA8888");
   bool enable_texture_format_bgra8888 =
       has_ext_bgra || has_apple_bgra || !gl_version_info_->is_es;
 
-  bool has_ext_texture_storage = extensions.Contains("GL_EXT_texture_storage");
-  bool has_arb_texture_storage = extensions.Contains("GL_ARB_texture_storage");
+  bool has_ext_texture_storage =
+      gl::HasExtension(extensions, "GL_EXT_texture_storage");
+  bool has_arb_texture_storage =
+      gl::HasExtension(extensions, "GL_ARB_texture_storage");
   bool has_texture_storage =
       !workarounds_.disable_texture_storage &&
       (has_ext_texture_storage || has_arb_texture_storage ||
@@ -835,7 +804,7 @@
   // require. On ES, support is indicated by the GL_EXT_read_format_bgra
   // extension.
   bool enable_read_format_bgra =
-      extensions.Contains("GL_EXT_read_format_bgra") ||
+      gl::HasExtension(extensions, "GL_EXT_read_format_bgra") ||
       !gl_version_info_->is_es;
 
   if (enable_read_format_bgra) {
@@ -847,7 +816,7 @@
   // GL_ARB_ES3_compatibility adds support for some ES3 texture formats that are
   // not supported in desktop GL
   feature_flags_.arb_es3_compatibility =
-      extensions.Contains("GL_ARB_ES3_compatibility") &&
+      gl::HasExtension(extensions, "GL_ARB_ES3_compatibility") &&
       !gl_version_info_->is_es;
 
   // glGetInteger64v for timestamps is implemented on the client side in a way
@@ -857,14 +826,15 @@
   // ES2. Thus we can enable GL_EXT_disjoint_timer_query on ES2 contexts even
   // though it does not support glGetInteger64v due to a specification bug.
   feature_flags_.ext_disjoint_timer_query =
-      extensions.Contains("GL_EXT_disjoint_timer_query");
+      gl::HasExtension(extensions, "GL_EXT_disjoint_timer_query");
   if (feature_flags_.ext_disjoint_timer_query ||
-      extensions.Contains("GL_ARB_timer_query") ||
-      extensions.Contains("GL_EXT_timer_query")) {
+      gl::HasExtension(extensions, "GL_ARB_timer_query") ||
+      gl::HasExtension(extensions, "GL_EXT_timer_query")) {
     AddExtensionString("GL_EXT_disjoint_timer_query");
   }
 
-  if (extensions.Contains("GL_OES_rgb8_rgba8") || gl::HasDesktopGLFeatures()) {
+  if (gl::HasExtension(extensions, "GL_OES_rgb8_rgba8") ||
+      gl::HasDesktopGLFeatures()) {
     AddExtensionString("GL_OES_rgb8_rgba8");
     validators_.render_buffer_format.AddValue(GL_RGB8_OES);
     validators_.render_buffer_format.AddValue(GL_RGBA8_OES);
@@ -872,10 +842,9 @@
 
   // Check if we should allow GL_OES_texture_npot
   if (!disallowed_features_.npot_support &&
-      (gl_version_info_->is_es3 ||
-       gl_version_info_->is_desktop_core_profile ||
-       extensions.Contains("GL_ARB_texture_non_power_of_two") ||
-       extensions.Contains("GL_OES_texture_npot"))) {
+      (gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile ||
+       gl::HasExtension(extensions, "GL_ARB_texture_non_power_of_two") ||
+       gl::HasExtension(extensions, "GL_OES_texture_npot"))) {
     AddExtensionString("GL_OES_texture_npot");
     feature_flags_.npot_ok = true;
   }
@@ -885,12 +854,11 @@
   // Check for multisample support
   if (!workarounds_.disable_chromium_framebuffer_multisample) {
     bool ext_has_multisample =
-        extensions.Contains("GL_EXT_framebuffer_multisample") ||
-        gl_version_info_->is_es3 ||
-        gl_version_info_->is_desktop_core_profile;
+        gl::HasExtension(extensions, "GL_EXT_framebuffer_multisample") ||
+        gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile;
     if (gl_version_info_->is_angle || gl_version_info_->is_swiftshader) {
       feature_flags_.angle_framebuffer_multisample =
-          extensions.Contains("GL_ANGLE_framebuffer_multisample");
+          gl::HasExtension(extensions, "GL_ANGLE_framebuffer_multisample");
       ext_has_multisample |= feature_flags_.angle_framebuffer_multisample;
     }
     feature_flags_.use_core_framebuffer_multisample =
@@ -906,9 +874,10 @@
     }
   }
 
-  if (extensions.Contains("GL_EXT_multisampled_render_to_texture")) {
+  if (gl::HasExtension(extensions, "GL_EXT_multisampled_render_to_texture")) {
     feature_flags_.multisampled_render_to_texture = true;
-  } else if (extensions.Contains("GL_IMG_multisampled_render_to_texture")) {
+  } else if (gl::HasExtension(extensions,
+                              "GL_IMG_multisampled_render_to_texture")) {
     feature_flags_.multisampled_render_to_texture = true;
     feature_flags_.use_img_for_multisampled_render_to_texture = true;
   }
@@ -922,39 +891,43 @@
   }
 
   if (!gl_version_info_->is_es ||
-       extensions.Contains("GL_EXT_multisample_compatibility")) {
+      gl::HasExtension(extensions, "GL_EXT_multisample_compatibility")) {
     AddExtensionString("GL_EXT_multisample_compatibility");
     feature_flags_.ext_multisample_compatibility = true;
     validators_.capability.AddValue(GL_MULTISAMPLE_EXT);
     validators_.capability.AddValue(GL_SAMPLE_ALPHA_TO_ONE_EXT);
   }
 
-  if (extensions.Contains("GL_INTEL_framebuffer_CMAA")) {
+  if (gl::HasExtension(extensions, "GL_INTEL_framebuffer_CMAA")) {
     feature_flags_.chromium_screen_space_antialiasing = true;
     AddExtensionString("GL_CHROMIUM_screen_space_antialiasing");
   } else if (!workarounds_.disable_framebuffer_cmaa &&
              (gl_version_info_->IsAtLeastGLES(3, 1) ||
               (gl_version_info_->IsAtLeastGL(3, 0) &&
-               extensions.Contains("GL_ARB_shading_language_420pack") &&
-               extensions.Contains("GL_ARB_texture_storage") &&
-               extensions.Contains("GL_ARB_texture_gather") &&
-               extensions.Contains("GL_ARB_explicit_uniform_location") &&
-               extensions.Contains("GL_ARB_explicit_attrib_location") &&
-               extensions.Contains("GL_ARB_shader_image_load_store")))) {
+               gl::HasExtension(extensions,
+                                "GL_ARB_shading_language_420pack") &&
+               gl::HasExtension(extensions, "GL_ARB_texture_storage") &&
+               gl::HasExtension(extensions, "GL_ARB_texture_gather") &&
+               gl::HasExtension(extensions,
+                                "GL_ARB_explicit_uniform_location") &&
+               gl::HasExtension(extensions,
+                                "GL_ARB_explicit_attrib_location") &&
+               gl::HasExtension(extensions,
+                                "GL_ARB_shader_image_load_store")))) {
     feature_flags_.chromium_screen_space_antialiasing = true;
     feature_flags_.use_chromium_screen_space_antialiasing_via_shaders = true;
     AddExtensionString("GL_CHROMIUM_screen_space_antialiasing");
   }
 
-  if (extensions.Contains("GL_OES_depth24") || gl::HasDesktopGLFeatures() ||
-      gl_version_info_->is_es3) {
+  if (gl::HasExtension(extensions, "GL_OES_depth24") ||
+      gl::HasDesktopGLFeatures() || gl_version_info_->is_es3) {
     AddExtensionString("GL_OES_depth24");
     feature_flags_.oes_depth24 = true;
     validators_.render_buffer_format.AddValue(GL_DEPTH_COMPONENT24);
   }
 
   if (gl_version_info_->is_es3 ||
-      extensions.Contains("GL_OES_standard_derivatives") ||
+      gl::HasExtension(extensions, "GL_OES_standard_derivatives") ||
       gl::HasDesktopGLFeatures()) {
     AddExtensionString("GL_OES_standard_derivatives");
     feature_flags_.oes_standard_derivatives = true;
@@ -962,11 +935,11 @@
     validators_.g_l_state.AddValue(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
   }
 
-  if (extensions.Contains("GL_OES_EGL_image_external")) {
+  if (gl::HasExtension(extensions, "GL_OES_EGL_image_external")) {
     AddExtensionString("GL_OES_EGL_image_external");
     feature_flags_.oes_egl_image_external = true;
   }
-  if (extensions.Contains("GL_NV_EGL_stream_consumer_external")) {
+  if (gl::HasExtension(extensions, "GL_NV_EGL_stream_consumer_external")) {
     AddExtensionString("GL_NV_EGL_stream_consumer_external");
     feature_flags_.nv_egl_stream_consumer_external = true;
   }
@@ -982,7 +955,7 @@
   // TODO(kainino): If we add a way to query whether ANGLE is exposing
   // native support for ETC1 textures, require that here. Otherwise, we could
   // co-opt the native-ETC2-support query discussed below.
-  if (extensions.Contains("GL_OES_compressed_ETC1_RGB8_texture") &&
+  if (gl::HasExtension(extensions, "GL_OES_compressed_ETC1_RGB8_texture") &&
       !gl_version_info_->is_angle) {
     AddExtensionString("GL_OES_compressed_ETC1_RGB8_texture");
     feature_flags_.oes_compressed_etc1_rgb8_texture = true;
@@ -997,7 +970,7 @@
     validators_.UpdateETCCompressedTextureFormats();
   }
 
-  if (extensions.Contains("GL_AMD_compressed_ATC_texture")) {
+  if (gl::HasExtension(extensions, "GL_AMD_compressed_ATC_texture")) {
     AddExtensionString("GL_AMD_compressed_ATC_texture");
     validators_.compressed_texture_format.AddValue(
         GL_ATC_RGB_AMD);
@@ -1014,7 +987,7 @@
         GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD);
   }
 
-  if (extensions.Contains("GL_IMG_texture_compression_pvrtc")) {
+  if (gl::HasExtension(extensions, "GL_IMG_texture_compression_pvrtc")) {
     AddExtensionString("GL_IMG_texture_compression_pvrtc");
     validators_.compressed_texture_format.AddValue(
         GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
@@ -1039,8 +1012,8 @@
   // IOSurface backed textures. We don't want applications to start using it;
   // they should use ordinary non-power-of-two textures. However, for unit
   // testing purposes we expose it on all supported platforms.
-  if (extensions.Contains("GL_ARB_texture_rectangle") ||
-      extensions.Contains("GL_ANGLE_texture_rectangle") ||
+  if (gl::HasExtension(extensions, "GL_ARB_texture_rectangle") ||
+      gl::HasExtension(extensions, "GL_ANGLE_texture_rectangle") ||
       gl_version_info_->is_desktop_core_profile) {
     AddExtensionString("GL_ARB_texture_rectangle");
     feature_flags_.arb_texture_rectangle = true;
@@ -1062,7 +1035,7 @@
   }
 #endif
 
-  if (extensions.Contains("GL_APPLE_ycbcr_422")) {
+  if (gl::HasExtension(extensions, "GL_APPLE_ycbcr_422")) {
     AddExtensionString("GL_CHROMIUM_ycbcr_422_image");
     feature_flags_.chromium_image_ycbcr_422 = true;
   }
@@ -1070,7 +1043,7 @@
   // TODO(gman): Add support for these extensions.
   //     GL_OES_depth32
 
-  if (extensions.Contains("GL_ANGLE_texture_usage")) {
+  if (gl::HasExtension(extensions, "GL_ANGLE_texture_usage")) {
     feature_flags_.angle_texture_usage = true;
     AddExtensionString("GL_ANGLE_texture_usage");
     validators_.texture_parameter.AddValue(GL_TEXTURE_USAGE_ANGLE);
@@ -1080,13 +1053,13 @@
       gl_version_info_->IsAtLeastGLES(3, 0) ||
       gl_version_info_->IsAtLeastGL(3, 3);
   bool have_ext_occlusion_query_boolean =
-      extensions.Contains("GL_EXT_occlusion_query_boolean");
+      gl::HasExtension(extensions, "GL_EXT_occlusion_query_boolean");
   bool have_arb_occlusion_query2 =
-      extensions.Contains("GL_ARB_occlusion_query2");
+      gl::HasExtension(extensions, "GL_ARB_occlusion_query2");
   bool have_arb_occlusion_query =
       (gl_version_info_->is_desktop_core_profile &&
        gl_version_info_->IsAtLeastGL(1, 5)) ||
-      extensions.Contains("GL_ARB_occlusion_query");
+      gl::HasExtension(extensions, "GL_ARB_occlusion_query");
 
   if (have_occlusion_query ||
       have_ext_occlusion_query_boolean ||
@@ -1107,11 +1080,10 @@
   }
 
   if (!workarounds_.disable_angle_instanced_arrays &&
-      (extensions.Contains("GL_ANGLE_instanced_arrays") ||
-       (extensions.Contains("GL_ARB_instanced_arrays") &&
-        extensions.Contains("GL_ARB_draw_instanced")) ||
-       gl_version_info_->is_es3 ||
-       gl_version_info_->is_desktop_core_profile)) {
+      (gl::HasExtension(extensions, "GL_ANGLE_instanced_arrays") ||
+       (gl::HasExtension(extensions, "GL_ARB_instanced_arrays") &&
+        gl::HasExtension(extensions, "GL_ARB_draw_instanced")) ||
+       gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile)) {
     AddExtensionString("GL_ANGLE_instanced_arrays");
     feature_flags_.angle_instanced_arrays = true;
     validators_.vertex_attribute.AddValue(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
@@ -1119,12 +1091,13 @@
 
   bool have_es2_draw_buffers_vendor_agnostic =
       gl_version_info_->is_desktop_core_profile ||
-      extensions.Contains("GL_ARB_draw_buffers") ||
-      extensions.Contains("GL_EXT_draw_buffers");
+      gl::HasExtension(extensions, "GL_ARB_draw_buffers") ||
+      gl::HasExtension(extensions, "GL_EXT_draw_buffers");
   bool can_emulate_es2_draw_buffers_on_es3_nv =
-      gl_version_info_->is_es3 && extensions.Contains("GL_NV_draw_buffers");
+      gl_version_info_->is_es3 &&
+      gl::HasExtension(extensions, "GL_NV_draw_buffers");
   bool is_webgl_compatbility_context =
-      extensions.Contains("GL_ANGLE_webgl_compatibility");
+      gl::HasExtension(extensions, "GL_ANGLE_webgl_compatibility");
   bool have_es2_draw_buffers =
       !workarounds_.disable_ext_draw_buffers &&
       (have_es2_draw_buffers_vendor_agnostic ||
@@ -1173,7 +1146,8 @@
     }
   }
 
-  if (gl_version_info_->is_es3 || extensions.Contains("GL_EXT_blend_minmax") ||
+  if (gl_version_info_->is_es3 ||
+      gl::HasExtension(extensions, "GL_EXT_blend_minmax") ||
       gl::HasDesktopGLFeatures()) {
     AddExtensionString("GL_EXT_blend_minmax");
     validators_.equation.AddValue(GL_MIN_EXT);
@@ -1183,12 +1157,13 @@
   }
 
   // TODO(dshwang): GLES3 supports gl_FragDepth, not gl_FragDepthEXT.
-  if (extensions.Contains("GL_EXT_frag_depth") || gl::HasDesktopGLFeatures()) {
+  if (gl::HasExtension(extensions, "GL_EXT_frag_depth") ||
+      gl::HasDesktopGLFeatures()) {
     AddExtensionString("GL_EXT_frag_depth");
     feature_flags_.ext_frag_depth = true;
   }
 
-  if (extensions.Contains("GL_EXT_shader_texture_lod") ||
+  if (gl::HasExtension(extensions, "GL_EXT_shader_texture_lod") ||
       gl::HasDesktopGLFeatures()) {
     AddExtensionString("GL_EXT_shader_texture_lod");
     feature_flags_.ext_shader_texture_lod = true;
@@ -1198,18 +1173,16 @@
   UMA_HISTOGRAM_BOOLEAN("GPU.FenceSupport", ui_gl_fence_works);
 
   feature_flags_.map_buffer_range =
-      gl_version_info_->is_es3 ||
-      gl_version_info_->is_desktop_core_profile ||
-      extensions.Contains("GL_ARB_map_buffer_range") ||
-      extensions.Contains("GL_EXT_map_buffer_range");
+      gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile ||
+      gl::HasExtension(extensions, "GL_ARB_map_buffer_range") ||
+      gl::HasExtension(extensions, "GL_EXT_map_buffer_range");
 
   // Really it's part of core OpenGL 2.1 and up, but let's assume the
   // extension is still advertised.
   bool has_pixel_buffers =
-      gl_version_info_->is_es3 ||
-      gl_version_info_->is_desktop_core_profile ||
-      extensions.Contains("GL_ARB_pixel_buffer_object") ||
-      extensions.Contains("GL_NV_pixel_buffer_object");
+      gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile ||
+      gl::HasExtension(extensions, "GL_ARB_pixel_buffer_object") ||
+      gl::HasExtension(extensions, "GL_NV_pixel_buffer_object");
 
   // We will use either glMapBuffer() or glMapBufferRange() for async readbacks.
   if (has_pixel_buffers && ui_gl_fence_works &&
@@ -1218,14 +1191,14 @@
   }
 
   if (gl_version_info_->is_es3 ||
-      extensions.Contains("GL_ARB_sampler_objects")) {
+      gl::HasExtension(extensions, "GL_ARB_sampler_objects")) {
     feature_flags_.enable_samplers = true;
     // TODO(dsinclair): Add AddExtensionString("GL_CHROMIUM_sampler_objects")
     // when available.
   }
 
   if ((gl_version_info_->is_es3 ||
-       extensions.Contains("GL_EXT_discard_framebuffer")) &&
+       gl::HasExtension(extensions, "GL_EXT_discard_framebuffer")) &&
       !workarounds_.disable_discard_framebuffer) {
     // DiscardFramebufferEXT is automatically bound to InvalidateFramebuffer.
     AddExtensionString("GL_EXT_discard_framebuffer");
@@ -1239,12 +1212,13 @@
 
   if (!workarounds_.disable_blend_equation_advanced) {
     bool blend_equation_advanced_coherent =
-        extensions.Contains("GL_NV_blend_equation_advanced_coherent") ||
-        extensions.Contains("GL_KHR_blend_equation_advanced_coherent");
+        gl::HasExtension(extensions,
+                         "GL_NV_blend_equation_advanced_coherent") ||
+        gl::HasExtension(extensions, "GL_KHR_blend_equation_advanced_coherent");
 
     if (blend_equation_advanced_coherent ||
-        extensions.Contains("GL_NV_blend_equation_advanced") ||
-        extensions.Contains("GL_KHR_blend_equation_advanced")) {
+        gl::HasExtension(extensions, "GL_NV_blend_equation_advanced") ||
+        gl::HasExtension(extensions, "GL_KHR_blend_equation_advanced")) {
       const GLenum equations[] = {GL_MULTIPLY_KHR,
                                   GL_SCREEN_KHR,
                                   GL_OVERLAY_KHR,
@@ -1273,17 +1247,18 @@
     }
   }
 
-  if (extensions.Contains("GL_NV_framebuffer_mixed_samples")) {
+  if (gl::HasExtension(extensions, "GL_NV_framebuffer_mixed_samples")) {
     AddExtensionString("GL_CHROMIUM_framebuffer_mixed_samples");
     feature_flags_.chromium_framebuffer_mixed_samples = true;
     validators_.g_l_state.AddValue(GL_COVERAGE_MODULATION_CHROMIUM);
   }
 
-  if (extensions.Contains("GL_NV_path_rendering")) {
+  if (gl::HasExtension(extensions, "GL_NV_path_rendering")) {
     bool has_dsa = gl_version_info_->IsAtLeastGL(4, 5) ||
-                   extensions.Contains("GL_EXT_direct_state_access");
-    bool has_piq = gl_version_info_->IsAtLeastGL(4, 3) ||
-                   extensions.Contains("GL_ARB_program_interface_query");
+                   gl::HasExtension(extensions, "GL_EXT_direct_state_access");
+    bool has_piq =
+        gl_version_info_->IsAtLeastGL(4, 3) ||
+        gl::HasExtension(extensions, "GL_ARB_program_interface_query");
     bool has_fms = feature_flags_.chromium_framebuffer_mixed_samples;
     if ((gl_version_info_->IsAtLeastGLES(3, 1) ||
          (gl_version_info_->IsAtLeastGL(3, 2) && has_dsa && has_piq)) &&
@@ -1299,8 +1274,8 @@
   }
 
   if ((gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile ||
-       extensions.Contains("GL_EXT_texture_rg") ||
-       extensions.Contains("GL_ARB_texture_rg")) &&
+       gl::HasExtension(extensions, "GL_EXT_texture_rg") ||
+       gl::HasExtension(extensions, "GL_ARB_texture_rg")) &&
       IsGL_REDSupportedOnFBOs()) {
     feature_flags_.ext_texture_rg = true;
     AddExtensionString("GL_EXT_texture_rg");
@@ -1321,7 +1296,7 @@
   UMA_HISTOGRAM_BOOLEAN("GPU.TextureRG", feature_flags_.ext_texture_rg);
 
   if (gl_version_info_->is_desktop_core_profile ||
-      extensions.Contains("GL_EXT_texture_norm16")) {
+      gl::HasExtension(extensions, "GL_EXT_texture_norm16")) {
     feature_flags_.ext_texture_norm16 = true;
     AddExtensionString("GL_EXT_texture_norm16");
 
@@ -1336,13 +1311,12 @@
   bool has_opengl_dual_source_blending =
       gl_version_info_->IsAtLeastGL(3, 3) ||
       (gl_version_info_->IsAtLeastGL(3, 2) &&
-       extensions.Contains("GL_ARB_blend_func_extended"));
-  if (!disable_shader_translator_ &&
-      !workarounds_.get_frag_data_info_bug &&
+       gl::HasExtension(extensions, "GL_ARB_blend_func_extended"));
+  if (!disable_shader_translator_ && !workarounds_.get_frag_data_info_bug &&
       ((gl_version_info_->IsAtLeastGL(3, 2) &&
         has_opengl_dual_source_blending) ||
        (gl_version_info_->IsAtLeastGLES(3, 0) &&
-        extensions.Contains("GL_EXT_blend_func_extended")))) {
+        gl::HasExtension(extensions, "GL_EXT_blend_func_extended")))) {
     // Note: to simplify the code, we do not expose EXT_blend_func_extended
     // unless the service context supports ES 3.0. This means the theoretical ES
     // 2.0 implementation with EXT_blend_func_extended is not sufficient.
@@ -1382,35 +1356,39 @@
   }
 
   feature_flags_.angle_robust_client_memory =
-      extensions.Contains("GL_ANGLE_robust_client_memory");
+      gl::HasExtension(extensions, "GL_ANGLE_robust_client_memory");
 
   feature_flags_.khr_debug = gl_version_info_->IsAtLeastGL(4, 3) ||
                              gl_version_info_->IsAtLeastGLES(3, 2) ||
-                             extensions.Contains("GL_KHR_debug");
+                             gl::HasExtension(extensions, "GL_KHR_debug");
 
   feature_flags_.chromium_bind_generates_resource =
-      extensions.Contains("GL_CHROMIUM_bind_generates_resource");
+      gl::HasExtension(extensions, "GL_CHROMIUM_bind_generates_resource");
   feature_flags_.angle_webgl_compatibility = is_webgl_compatbility_context;
   feature_flags_.chromium_copy_texture =
-      extensions.Contains("GL_CHROMIUM_copy_texture");
+      gl::HasExtension(extensions, "GL_CHROMIUM_copy_texture");
   feature_flags_.chromium_copy_compressed_texture =
-      extensions.Contains("GL_CHROMIUM_copy_compressed_texture");
+      gl::HasExtension(extensions, "GL_CHROMIUM_copy_compressed_texture");
   feature_flags_.angle_client_arrays =
-      extensions.Contains("GL_ANGLE_client_arrays");
+      gl::HasExtension(extensions, "GL_ANGLE_client_arrays");
   feature_flags_.angle_request_extension =
-      extensions.Contains("GL_ANGLE_request_extension");
-  feature_flags_.ext_debug_marker = extensions.Contains("GL_EXT_debug_marker");
-  feature_flags_.arb_robustness = extensions.Contains("GL_ARB_robustness");
-  feature_flags_.khr_robustness = extensions.Contains("GL_KHR_robustness");
-  feature_flags_.ext_robustness = extensions.Contains("GL_EXT_robustness");
+      gl::HasExtension(extensions, "GL_ANGLE_request_extension");
+  feature_flags_.ext_debug_marker =
+      gl::HasExtension(extensions, "GL_EXT_debug_marker");
+  feature_flags_.arb_robustness =
+      gl::HasExtension(extensions, "GL_ARB_robustness");
+  feature_flags_.khr_robustness =
+      gl::HasExtension(extensions, "GL_KHR_robustness");
+  feature_flags_.ext_robustness =
+      gl::HasExtension(extensions, "GL_EXT_robustness");
   feature_flags_.chromium_texture_filtering_hint =
-      extensions.Contains("GL_CHROMIUM_texture_filtering_hint");
+      gl::HasExtension(extensions, "GL_CHROMIUM_texture_filtering_hint");
   feature_flags_.ext_pixel_buffer_object =
-      extensions.Contains("GL_NV_pixel_buffer_object");
+      gl::HasExtension(extensions, "GL_NV_pixel_buffer_object");
 }
 
 void FeatureInfo::InitializeFloatAndHalfFloatFeatures(
-    const StringSet& extensions) {
+    const gl::ExtensionSet& extensions) {
   // Check if we should allow GL_OES_texture_float, GL_OES_texture_half_float,
   // GL_OES_texture_float_linear, GL_OES_texture_half_float_linear
   bool enable_texture_float = false;
@@ -1426,12 +1404,12 @@
 
   // These extensions allow a variety of floating point formats to be
   // rendered to via framebuffer objects.
-  if (extensions.Contains("GL_EXT_color_buffer_float"))
+  if (gl::HasExtension(extensions, "GL_EXT_color_buffer_float"))
     enable_ext_color_buffer_float = true;
-  if (extensions.Contains("GL_EXT_color_buffer_half_float"))
+  if (gl::HasExtension(extensions, "GL_EXT_color_buffer_half_float"))
     enable_ext_color_buffer_half_float = true;
 
-  if (extensions.Contains("GL_ARB_texture_float") ||
+  if (gl::HasExtension(extensions, "GL_ARB_texture_float") ||
       gl_version_info_->is_desktop_core_profile) {
     enable_texture_float = true;
     enable_texture_float_linear = true;
@@ -1441,24 +1419,24 @@
   } else {
     // GLES3 adds support for Float type by default but it doesn't support all
     // formats as GL_OES_texture_float(i.e.LUMINANCE_ALPHA,LUMINANCE and Alpha)
-    if (extensions.Contains("GL_OES_texture_float")) {
+    if (gl::HasExtension(extensions, "GL_OES_texture_float")) {
       enable_texture_float = true;
       if (enable_ext_color_buffer_float) {
         may_enable_chromium_color_buffer_float = true;
       }
     }
 
-    if (extensions.Contains("GL_OES_texture_float_linear")) {
+    if (gl::HasExtension(extensions, "GL_OES_texture_float_linear")) {
       enable_texture_float_linear = true;
     }
 
     // TODO(dshwang): GLES3 supports half float by default but GL_HALF_FLOAT_OES
     // isn't equal to GL_HALF_FLOAT.
-    if (extensions.Contains("GL_OES_texture_half_float")) {
+    if (gl::HasExtension(extensions, "GL_OES_texture_half_float")) {
       enable_texture_half_float = true;
     }
 
-    if (extensions.Contains("GL_OES_texture_half_float_linear")) {
+    if (gl::HasExtension(extensions, "GL_OES_texture_half_float_linear")) {
       enable_texture_half_float_linear = true;
     }
   }
@@ -1488,7 +1466,7 @@
   }
 
   bool had_native_chromium_color_buffer_float_ext = false;
-  if (extensions.Contains("GL_CHROMIUM_color_buffer_float_rgb")) {
+  if (gl::HasExtension(extensions, "GL_CHROMIUM_color_buffer_float_rgb")) {
     had_native_chromium_color_buffer_float_ext = true;
     feature_flags_.chromium_color_buffer_float_rgb = true;
     if (!disallowed_features_.chromium_color_buffer_float_rgb) {
@@ -1496,7 +1474,7 @@
     }
   }
 
-  if (extensions.Contains("GL_CHROMIUM_color_buffer_float_rgba")) {
+  if (gl::HasExtension(extensions, "GL_CHROMIUM_color_buffer_float_rgba")) {
     had_native_chromium_color_buffer_float_ext = true;
     feature_flags_.chromium_color_buffer_float_rgba = true;
     if (!disallowed_features_.chromium_color_buffer_float_rgba) {
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 2124d4d..6fe9fbe 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -14,6 +14,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_validation.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/gpu_export.h"
+#include "ui/gl/extension_set.h"
 
 namespace base {
 class CommandLine;
@@ -189,14 +190,13 @@
  private:
   friend class base::RefCounted<FeatureInfo>;
   friend class BufferManagerClientSideArraysTest;
-  class StringSet;
 
   ~FeatureInfo();
 
   void AddExtensionString(const char* s);
   void InitializeBasicState(const base::CommandLine* command_line);
   void InitializeFeatures();
-  void InitializeFloatAndHalfFloatFeatures(const StringSet& extensions);
+  void InitializeFloatAndHalfFloatFeatures(const gl::ExtensionSet& extensions);
 
   Validators validators_;
 
diff --git a/gpu/command_buffer/service/gl_context_virtual.cc b/gpu/command_buffer/service/gl_context_virtual.cc
index da4a805a..a500558 100644
--- a/gpu/command_buffer/service/gl_context_virtual.cc
+++ b/gpu/command_buffer/service/gl_context_virtual.cc
@@ -77,7 +77,7 @@
   return shared_context_->GetGLRenderer();
 }
 
-std::string GLContextVirtual::GetExtensions() {
+const gl::ExtensionSet& GLContextVirtual::GetExtensions() {
   return shared_context_->GetExtensions();
 }
 
@@ -109,4 +109,8 @@
   Destroy();
 }
 
+void GLContextVirtual::ResetExtensions() {
+  shared_context_->ResetExtensions();
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gl_context_virtual.h b/gpu/command_buffer/service/gl_context_virtual.h
index 648b0c88..f9768f5 100644
--- a/gpu/command_buffer/service/gl_context_virtual.h
+++ b/gpu/command_buffer/service/gl_context_virtual.h
@@ -42,7 +42,7 @@
   void OnSetSwapInterval(int interval) override;
   std::string GetGLVersion() override;
   std::string GetGLRenderer() override;
-  std::string GetExtensions() override;
+  const gl::ExtensionSet& GetExtensions() override;
   void SetSafeToForceGpuSwitch() override;
   bool WasAllocatedUsingRobustnessExtension() override;
   void SetUnbindFboOnMakeCurrent() override;
@@ -52,6 +52,7 @@
 
  protected:
   ~GLContextVirtual() override;
+  void ResetExtensions() override;
 
  private:
   void Destroy();
diff --git a/gpu/command_buffer/service/service_discardable_manager.cc b/gpu/command_buffer/service/service_discardable_manager.cc
index 18810e6c..038e36a 100644
--- a/gpu/command_buffer/service/service_discardable_manager.cc
+++ b/gpu/command_buffer/service/service_discardable_manager.cc
@@ -5,11 +5,59 @@
 #include "gpu/command_buffer/service/service_discardable_manager.h"
 
 #include "base/memory/singleton.h"
+#include "base/sys_info.h"
+#include "build/build_config.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 
 namespace gpu {
+namespace {
+// TODO(ericrk): AmountOfPhysicalMemoryMB is broken in the GPU proc on Linux.
+// Use 0 on Linux for now, causing us to pick our normal cache sizes. GPU
+// discardable is currently only used in production by GPU raster, which is not
+// enabled on Linux. crbug.com/743271
+#if !defined(OS_ANDROID)
+int AmountOfPhysicalMemoryWithWorkaround() {
+#if defined(OS_LINUX)
+  return 0;
+#else
+  return base::SysInfo::AmountOfPhysicalMemoryMB();
+#endif
+}
+#endif  // !defined(OS_ANDROID)
 
-const size_t ServiceDiscardableManager::kMaxSize;
+size_t CacheSizeLimit() {
+// Cache size values are designed to roughly correspond to existing image cache
+// sizes for 2-3 renderers. These will be updated as more types of data are
+// moved to this cache.
+#if defined(OS_ANDROID)
+  const size_t kLowEndCacheSizeBytes = 512 * 1024;
+  const size_t kNormalCacheSizeBytes = 128 * 1024 * 1024;
+#else
+  const size_t kNormalCacheSizeBytes = 384 * 1024 * 1024;
+  const size_t kLargeCacheSizeBytes = 512 * 1024 * 1024;
+  // Device ram threshold at which we move from a normal cache to a large cache.
+  // While this is a GPU memory cache, we can't read GPU memory reliably, so we
+  // use system ram as a proxy.
+  const int kLargeCacheSizeMemoryThresholdMB = 4 * 1024;
+#endif  // defined(OS_ANDROID)
+
+#if defined(OS_ANDROID)
+  if (base::SysInfo::IsLowEndDevice()) {
+    return kLowEndCacheSizeBytes;
+  } else {
+    return kNormalCacheSizeBytes;
+  }
+#else
+  if (AmountOfPhysicalMemoryWithWorkaround() <
+      kLargeCacheSizeMemoryThresholdMB) {
+    return kNormalCacheSizeBytes;
+  } else {
+    return kLargeCacheSizeBytes;
+  }
+#endif
+}
+
+}  // namespace
 
 ServiceDiscardableManager::GpuDiscardableEntry::GpuDiscardableEntry(
     ServiceDiscardableHandle handle,
@@ -23,7 +71,9 @@
     default;
 
 ServiceDiscardableManager::ServiceDiscardableManager()
-    : entries_(EntryCache::NO_AUTO_EVICT) {}
+    : entries_(EntryCache::NO_AUTO_EVICT),
+      cache_size_limit_(CacheSizeLimit()) {}
+
 ServiceDiscardableManager::~ServiceDiscardableManager() {
 #if DCHECK_IS_ON()
   for (const auto& entry : entries_) {
@@ -132,7 +182,7 @@
 
 void ServiceDiscardableManager::EnforceLimits() {
   for (auto it = entries_.rbegin(); it != entries_.rend();) {
-    if (total_size_ <= kMaxSize) {
+    if (total_size_ <= cache_size_limit_) {
       return;
     }
     if (!it->second.handle.Delete()) {
diff --git a/gpu/command_buffer/service/service_discardable_manager.h b/gpu/command_buffer/service/service_discardable_manager.h
index d8fe6f4..b9bf82b 100644
--- a/gpu/command_buffer/service/service_discardable_manager.h
+++ b/gpu/command_buffer/service/service_discardable_manager.h
@@ -64,9 +64,9 @@
       uint32_t texture_id,
       gles2::TextureManager* texture_manager) const;
 
-  // TODO(ericrk): Arbitrary limit, refine this once we actually use this class
-  // in production. crbug.com/706456
-  static const size_t kMaxSize = 256 * 1024 * 1024;
+  void SetCacheSizeLimitForTesting(size_t cache_size_limit) {
+    cache_size_limit_ = cache_size_limit;
+  }
 
  private:
   void EnforceLimits();
@@ -106,6 +106,9 @@
   // GpuDiscardableEntry::size for each entry.
   size_t total_size_ = 0;
 
+  // The limit above which the cache will start evicting resources.
+  size_t cache_size_limit_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(ServiceDiscardableManager);
 };
 
diff --git a/gpu/command_buffer/service/service_discardable_manager_unittest.cc b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
index 3213139..11f37be 100644
--- a/gpu/command_buffer/service/service_discardable_manager_unittest.cc
+++ b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
@@ -200,9 +200,12 @@
 
 TEST_F(ServiceDiscardableManagerTest, Limits) {
   // Size textures so that four fit in the discardable manager.
-  const size_t texture_size = ServiceDiscardableManager::kMaxSize / 4;
+  const size_t cache_size_limit = 4 * 1024 * 1024;
+  const size_t texture_size = cache_size_limit / 4;
   const size_t large_texture_size = 3 * texture_size;
 
+  discardable_manager_.SetCacheSizeLimitForTesting(cache_size_limit);
+
   // Create 4 textures, this should fill up the discardable cache.
   for (int i = 1; i < 5; ++i) {
     texture_manager_->CreateTexture(i, i);
diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc
index cb651e4..8962c633 100644
--- a/gpu/command_buffer/service/shader_translator_unittest.cc
+++ b/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -16,7 +16,7 @@
   ShaderTranslatorTest() {
     shader_output_language_ =
         ShaderTranslator::GetShaderOutputLanguageForContext(
-            gl::GLVersionInfo("2.0", "", ""));
+            gl::GLVersionInfo("2.0", "", gl::ExtensionSet()));
   }
 
   ~ShaderTranslatorTest() override {}
@@ -55,7 +55,7 @@
   ES3ShaderTranslatorTest() {
     shader_output_language_ =
         ShaderTranslator::GetShaderOutputLanguageForContext(
-            gl::GLVersionInfo("3.0", "", ""));
+            gl::GLVersionInfo("3.0", "", gl::ExtensionSet()));
   }
 
   ~ES3ShaderTranslatorTest() override {}
@@ -507,7 +507,8 @@
       "  gl_Position = vPosition;\n"
       "}";
 
-  gl::GLVersionInfo output_context_version(testing::get<0>(GetParam()), "", "");
+  gl::GLVersionInfo output_context_version(testing::get<0>(GetParam()), "",
+                                           gl::ExtensionSet());
 
   scoped_refptr<ShaderTranslator> translator = new ShaderTranslator();
   ShBuiltInResources resources;
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index 85315f05..27686d75 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -11,8 +11,6 @@
 #include <string>
 
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_tokenizer.h"
 #include "gpu/command_buffer/service/buffer_manager.h"
 #include "gpu/command_buffer/service/error_state_mock.h"
 #include "gpu/command_buffer/service/feature_info.h"
@@ -207,7 +205,7 @@
     bool is_es3_enabled,
     bool is_es3_capable,
     bool is_desktop_core_profile,
-    const char* extensions,
+    const gl::ExtensionSet& extensions,
     bool use_default_textures) {
   InSequence sequence;
 
@@ -229,19 +227,11 @@
         gl, GL_TEXTURE_2D_ARRAY, use_default_textures);
   }
 
-  bool ext_image_external = false;
-  bool arb_texture_rectangle = is_desktop_core_profile;
-  base::CStringTokenizer t(extensions, extensions + strlen(extensions), " ");
-  while (t.GetNext()) {
-    if (t.token() == "GL_OES_EGL_image_external") {
-      ext_image_external = true;
-      break;
-    }
-    if (t.token() == "GL_ARB_texture_rectangle") {
-      arb_texture_rectangle = true;
-      break;
-    }
-  }
+  bool ext_image_external =
+      gl::HasExtension(extensions, "GL_OES_EGL_image_external");
+  bool arb_texture_rectangle =
+      is_desktop_core_profile ||
+      gl::HasExtension(extensions, "GL_ARB_texture_rectangle");
 
   if (ext_image_external) {
     SetupTextureInitializationExpectations(
@@ -293,7 +283,7 @@
     ::gl::MockGLInterface* gl,
     bool is_es3_enabled,
     bool is_desktop_core_profile,
-    const char* extensions,
+    const gl::ExtensionSet& extensions,
     bool use_default_textures) {
   SetupTextureDestructionExpectations(gl, GL_TEXTURE_2D, use_default_textures);
   SetupTextureDestructionExpectations(
@@ -306,19 +296,11 @@
         gl, GL_TEXTURE_2D_ARRAY,use_default_textures);
   }
 
-  bool ext_image_external = false;
-  bool arb_texture_rectangle = false;
-  base::CStringTokenizer t(extensions, extensions + strlen(extensions), " ");
-  while (t.GetNext()) {
-    if (t.token() == "GL_OES_EGL_image_external") {
-      ext_image_external = true;
-      break;
-    }
-    if (t.token() == "GL_ARB_texture_rectangle") {
-      arb_texture_rectangle = true;
-      break;
-    }
-  }
+  bool ext_image_external =
+      gl::HasExtension(extensions, "GL_OES_EGL_image_external");
+  bool arb_texture_rectangle =
+      is_desktop_core_profile ||
+      gl::HasExtension(extensions, "GL_ARB_texture_rectangle");
 
   if (ext_image_external) {
     SetupTextureDestructionExpectations(
@@ -346,20 +328,23 @@
   bool enable_es3 = !(context_type == CONTEXT_TYPE_OPENGLES2 ||
                       context_type == CONTEXT_TYPE_WEBGL1);
 
-  gl::GLVersionInfo gl_info(gl_version, "", extensions);
+  gl::ExtensionSet extension_set(gl::MakeExtensionSet(extensions));
+  gl::GLVersionInfo gl_info(gl_version, "", extension_set);
 
   SetupFeatureInfoInitExpectationsWithGLVersion(gl, extensions, "", gl_version,
       context_type);
   EXPECT_CALL(*gl, GetIntegerv(GL_MAX_RENDERBUFFER_SIZE, _))
       .WillOnce(SetArgPointee<1>(kMaxRenderbufferSize))
       .RetiresOnSaturation();
-  if (strstr(extensions, "GL_EXT_framebuffer_multisample") ||
-      strstr(extensions, "GL_EXT_multisampled_render_to_texture") ||
+  if (gl::HasExtension(extension_set, "GL_EXT_framebuffer_multisample") ||
+      gl::HasExtension(extension_set,
+                       "GL_EXT_multisampled_render_to_texture") ||
       gl_info.is_es3 || gl_info.is_desktop_core_profile) {
     EXPECT_CALL(*gl, GetIntegerv(GL_MAX_SAMPLES, _))
         .WillOnce(SetArgPointee<1>(kMaxSamples))
         .RetiresOnSaturation();
-  } else if (strstr(extensions, "GL_IMG_multisampled_render_to_texture")) {
+  } else if (gl::HasExtension(extension_set,
+                              "GL_IMG_multisampled_render_to_texture")) {
     EXPECT_CALL(*gl, GetIntegerv(GL_MAX_SAMPLES_IMG, _))
         .WillOnce(SetArgPointee<1>(kMaxSamples))
         .RetiresOnSaturation();
@@ -368,9 +353,10 @@
   if (enable_es3 ||
       (!enable_es3 &&
        (gl_info.is_desktop_core_profile ||
-        strstr(extensions, "GL_EXT_draw_buffers") ||
-        strstr(extensions, "GL_ARB_draw_buffers") ||
-        (gl_info.is_es3 && strstr(extensions, "GL_NV_draw_buffers"))))) {
+        gl::HasExtension(extension_set, "GL_EXT_draw_buffers") ||
+        gl::HasExtension(extension_set, "GL_ARB_draw_buffers") ||
+        (gl_info.is_es3 &&
+         gl::HasExtension(extension_set, "GL_NV_draw_buffers"))))) {
     EXPECT_CALL(*gl, GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, _))
         .WillOnce(SetArgPointee<1>(8))
         .RetiresOnSaturation();
@@ -381,8 +367,9 @@
 
   if (gl_info.IsAtLeastGL(3, 3) ||
       (gl_info.IsAtLeastGL(3, 2) &&
-       strstr(extensions, "GL_ARB_blend_func_extended")) ||
-      (gl_info.is_es && strstr(extensions, "GL_EXT_blend_func_extended"))) {
+       gl::HasExtension(extension_set, "GL_ARB_blend_func_extended")) ||
+      (gl_info.is_es &&
+       gl::HasExtension(extension_set, "GL_EXT_blend_func_extended"))) {
     EXPECT_CALL(*gl, GetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, _))
         .WillOnce(SetArgPointee<1>(8))
         .RetiresOnSaturation();
@@ -422,7 +409,7 @@
         .WillOnce(SetArgPointee<1>(kMaxArrayTextureLayers))
         .RetiresOnSaturation();
   }
-  if (strstr(extensions, "GL_ARB_texture_rectangle") ||
+  if (gl::HasExtension(extension_set, "GL_ARB_texture_rectangle") ||
       gl_info.is_desktop_core_profile) {
     EXPECT_CALL(*gl, GetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE, _))
         .WillOnce(SetArgPointee<1>(kMaxRectangleTextureSize))
@@ -475,9 +462,9 @@
       .RetiresOnSaturation();
 
   bool use_default_textures = bind_generates_resource;
-  SetupTextureManagerInitExpectations(
-      gl, enable_es3, gl_info.is_es3_capable, gl_info.is_desktop_core_profile,
-      extensions, use_default_textures);
+  SetupTextureManagerInitExpectations(gl, enable_es3, gl_info.is_es3_capable,
+                                      gl_info.is_desktop_core_profile,
+                                      extension_set, use_default_textures);
 }
 
 void TestHelper::SetupFeatureInfoInitExpectations(::gl::MockGLInterface* gl,
@@ -501,14 +488,11 @@
       .WillOnce(Return(reinterpret_cast<const uint8_t*>(gl_version)))
       .RetiresOnSaturation();
 
+  gl::ExtensionSet extension_set(gl::MakeExtensionSet(extensions));
   // Persistent storage is needed for the split extension string.
-  split_extensions_.clear();
-  if (extensions) {
-    split_extensions_ = base::SplitString(
-        extensions, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  }
-
-  gl::GLVersionInfo gl_info(gl_version, gl_renderer, extensions);
+  split_extensions_ =
+      std::vector<std::string>(extension_set.begin(), extension_set.end());
+  gl::GLVersionInfo gl_info(gl_version, gl_renderer, extension_set);
   if (!gl_info.is_es && gl_info.major_version >= 3) {
     EXPECT_CALL(*gl, GetIntegerv(GL_NUM_EXTENSIONS, _))
         .WillOnce(SetArgPointee<1>(split_extensions_.size()))
@@ -538,10 +522,11 @@
       .RetiresOnSaturation();
   }
 
-  if ((strstr(extensions, "GL_ARB_texture_float") ||
+  if ((gl::HasExtension(extension_set, "GL_ARB_texture_float") ||
        gl_info.is_desktop_core_profile) ||
-      (gl_info.is_es3 && strstr(extensions, "GL_OES_texture_float") &&
-       strstr(extensions, "GL_EXT_color_buffer_float"))) {
+      (gl_info.is_es3 &&
+       gl::HasExtension(extension_set, "GL_OES_texture_float") &&
+       gl::HasExtension(extension_set, "GL_EXT_color_buffer_float"))) {
     static const GLuint tx_ids[] = {101, 102};
     static const GLuint fb_ids[] = {103, 104};
     const GLsizei width = 16;
@@ -637,7 +622,8 @@
           .Times(1)
           .RetiresOnSaturation();
     }
-    if (!enable_es3 && !strstr(extensions, "GL_EXT_color_buffer_half_float") &&
+    if (!enable_es3 &&
+        !gl::HasExtension(extension_set, "GL_EXT_color_buffer_half_float") &&
         (gl_info.is_es || gl_info.IsAtLeastGL(3, 0))) {
       EXPECT_CALL(
           *gl,
@@ -687,9 +673,10 @@
   if (enable_es3 ||
       (!enable_es3 &&
        (gl_info.is_desktop_core_profile ||
-        strstr(extensions, "GL_EXT_draw_buffers") ||
-        strstr(extensions, "GL_ARB_draw_buffers") ||
-        (gl_info.is_es3 && strstr(extensions, "GL_NV_draw_buffers"))))) {
+        gl::HasExtension(extension_set, "GL_EXT_draw_buffers") ||
+        gl::HasExtension(extension_set, "GL_ARB_draw_buffers") ||
+        (gl_info.is_es3 &&
+         gl::HasExtension(extension_set, "GL_NV_draw_buffers"))))) {
     EXPECT_CALL(*gl, GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, _))
         .WillOnce(SetArgPointee<1>(8))
         .RetiresOnSaturation();
@@ -699,8 +686,8 @@
   }
 
   if (gl_info.is_es3 || gl_info.is_desktop_core_profile ||
-      strstr(extensions, "GL_EXT_texture_rg") ||
-      (strstr(extensions, "GL_ARB_texture_rg"))) {
+      gl::HasExtension(extension_set, "GL_EXT_texture_rg") ||
+      (gl::HasExtension(extension_set, "GL_ARB_texture_rg"))) {
     static const GLuint tx_ids[] = {101, 102};
     static const GLuint fb_ids[] = {103, 104};
     const GLsizei width = 1;
diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h
index 7334064..e096a7a 100644
--- a/gpu/command_buffer/service/test_helper.h
+++ b/gpu/command_buffer/service/test_helper.h
@@ -117,17 +117,18 @@
       const char* gl_renderer,
       const char* gl_version,
       ContextType context_type);
-  static void SetupTextureManagerInitExpectations(::gl::MockGLInterface* gl,
-                                                  bool is_es3_enabled,
-                                                  bool is_es3_capable,
-                                                  bool is_desktop_core_profile,
-                                                  const char* extensions,
-                                                  bool use_default_textures);
+  static void SetupTextureManagerInitExpectations(
+      ::gl::MockGLInterface* gl,
+      bool is_es3_enabled,
+      bool is_es3_capable,
+      bool is_desktop_core_profile,
+      const gl::ExtensionSet& extensions,
+      bool use_default_textures);
   static void SetupTextureManagerDestructionExpectations(
       ::gl::MockGLInterface* gl,
       bool is_es3_enabled,
       bool is_desktop_core_profile,
-      const char* extensions,
+      const gl::ExtensionSet& extensions,
       bool use_default_textures);
 
   static void SetupExpectationsForClearingUniforms(::gl::MockGLInterface* gl,
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index ad82cf3..92a2c767 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -85,7 +85,7 @@
         kUseDefaultTextures, nullptr, &discardable_manager_));
     SetupFeatureInfo("", "OpenGL ES 2.0", CONTEXT_TYPE_OPENGLES2);
     TestHelper::SetupTextureManagerInitExpectations(
-        gl_.get(), false, false, false, "", kUseDefaultTextures);
+        gl_.get(), false, false, false, {}, kUseDefaultTextures);
     manager_->Initialize();
     error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
   }
@@ -240,8 +240,9 @@
 
 TEST_F(TextureManagerTest, UseDefaultTexturesTrue) {
   bool use_default_textures = true;
-  TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      false, false, false, "GL_ANGLE_texture_usage", use_default_textures);
+  TestHelper::SetupTextureManagerInitExpectations(
+      gl_.get(), false, false, false, {"GL_ANGLE_texture_usage"},
+      use_default_textures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
                          kMax3DTextureSize, kMaxArrayTextureLayers,
@@ -258,8 +259,9 @@
 
 TEST_F(TextureManagerTest, UseDefaultTexturesFalse) {
   bool use_default_textures = false;
-  TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      false, false, false, "GL_ANGLE_texture_usage", use_default_textures);
+  TestHelper::SetupTextureManagerInitExpectations(
+      gl_.get(), false, false, false, {"GL_ANGLE_texture_usage"},
+      use_default_textures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
                          kMax3DTextureSize, kMaxArrayTextureLayers,
@@ -277,8 +279,8 @@
 TEST_F(TextureManagerTest, UseDefaultTexturesTrueES3) {
   bool use_default_textures = true;
   SetupFeatureInfo("", "OpenGL ES 3.0", CONTEXT_TYPE_OPENGLES3);
-  TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      true, true, false, "", use_default_textures);
+  TestHelper::SetupTextureManagerInitExpectations(gl_.get(), true, true, false,
+                                                  {}, use_default_textures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
                          kMax3DTextureSize, kMaxArrayTextureLayers,
@@ -294,8 +296,8 @@
 TEST_F(TextureManagerTest, UseDefaultTexturesFalseES3) {
   bool use_default_textures = false;
   SetupFeatureInfo("", "OpenGL ES 3.0", CONTEXT_TYPE_OPENGLES3);
-  TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
-      true, true, false, "", use_default_textures);
+  TestHelper::SetupTextureManagerInitExpectations(gl_.get(), true, true, false,
+                                                  {}, use_default_textures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
                          kMax3DTextureSize, kMaxArrayTextureLayers,
@@ -310,7 +312,7 @@
 
 TEST_F(TextureManagerTest, TextureUsageExt) {
   TestHelper::SetupTextureManagerInitExpectations(
-      gl_.get(), false, false, false, "GL_ANGLE_texture_usage",
+      gl_.get(), false, false, false, {"GL_ANGLE_texture_usage"},
       kUseDefaultTextures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
@@ -336,7 +338,7 @@
   const GLuint kClient1Id = 1;
   const GLuint kService1Id = 11;
   TestHelper::SetupTextureManagerInitExpectations(
-      gl_.get(), false, false, false, "", kUseDefaultTextures);
+      gl_.get(), false, false, false, {}, kUseDefaultTextures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
                          kMax3DTextureSize, kMaxArrayTextureLayers,
@@ -351,7 +353,7 @@
       .Times(1)
       .RetiresOnSaturation();
   TestHelper::SetupTextureManagerDestructionExpectations(
-      gl_.get(), false, false, "", kUseDefaultTextures);
+      gl_.get(), false, false, {}, kUseDefaultTextures);
   manager.Destroy(true);
   // Check that resources got freed.
   texture = manager.GetTexture(kClient1Id);
@@ -512,8 +514,8 @@
   const GLuint kServiceId = 11;
 
   SetupFeatureInfo("", "2.1", CONTEXT_TYPE_OPENGLES2);
-  TestHelper::SetupTextureManagerInitExpectations(gl_.get(), false, false,
-      false, "", kUseDefaultTextures);
+  TestHelper::SetupTextureManagerInitExpectations(
+      gl_.get(), false, false, false, {}, kUseDefaultTextures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
                          kMax3DTextureSize, kMaxArrayTextureLayers,
@@ -554,7 +556,7 @@
 
   SetupFeatureInfo("", "4.2", CONTEXT_TYPE_OPENGLES3);
   TestHelper::SetupTextureManagerInitExpectations(gl_.get(), true, true, true,
-      "", kUseDefaultTextures);
+                                                  {}, kUseDefaultTextures);
   TextureManager manager(nullptr, feature_info_.get(), kMaxTextureSize,
                          kMaxCubeMapTextureSize, kMaxRectangleTextureSize,
                          kMax3DTextureSize, kMaxArrayTextureLayers,
@@ -2212,10 +2214,10 @@
         nullptr, &discardable_manager_));
     SetupFeatureInfo("", "OpenGL ES 2.0", CONTEXT_TYPE_OPENGLES2);
     TestHelper::SetupTextureManagerInitExpectations(
-        gl_.get(), false, false, false, "", kUseDefaultTextures);
+        gl_.get(), false, false, false, {}, kUseDefaultTextures);
     texture_manager1_->Initialize();
     TestHelper::SetupTextureManagerInitExpectations(
-        gl_.get(), false, false, false, "", kUseDefaultTextures);
+        gl_.get(), false, false, false, {}, kUseDefaultTextures);
     texture_manager2_->Initialize();
   }
 
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index a5c76adb..f6961e8 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -123,6 +123,7 @@
   gpu_info->gl_renderer = GetGLString(GL_RENDERER);
   gpu_info->gl_vendor = GetGLString(GL_VENDOR);
   gpu_info->gl_version = GetGLString(GL_VERSION);
+  std::string glsl_version_string = GetGLString(GL_SHADING_LANGUAGE_VERSION);
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kGpuTestingGLVendor)) {
@@ -139,23 +140,19 @@
   }
 
   gpu_info->gl_extensions = gl::GetGLExtensionsFromCurrentContext();
-  std::string glsl_version_string = GetGLString(GL_SHADING_LANGUAGE_VERSION);
+  gl::ExtensionSet extension_set =
+      gl::MakeExtensionSet(gpu_info->gl_extensions);
 
   gl::GLVersionInfo gl_info(gpu_info->gl_version.c_str(),
-                            gpu_info->gl_renderer.c_str(),
-                            gpu_info->gl_extensions.c_str());
+                            gpu_info->gl_renderer.c_str(), extension_set);
   GLint max_samples = 0;
   if (gl_info.IsAtLeastGL(3, 0) || gl_info.IsAtLeastGLES(3, 0) ||
-      gpu_info->gl_extensions.find("GL_ANGLE_framebuffer_multisample") !=
-          std::string::npos ||
-      gpu_info->gl_extensions.find("GL_APPLE_framebuffer_multisample") !=
-          std::string::npos ||
-      gpu_info->gl_extensions.find("GL_EXT_framebuffer_multisample") !=
-          std::string::npos ||
-      gpu_info->gl_extensions.find("GL_EXT_multisampled_render_to_texture") !=
-          std::string::npos ||
-      gpu_info->gl_extensions.find("GL_NV_framebuffer_multisample") !=
-          std::string::npos) {
+      gl::HasExtension(extension_set, "GL_ANGLE_framebuffer_multisample") ||
+      gl::HasExtension(extension_set, "GL_APPLE_framebuffer_multisample") ||
+      gl::HasExtension(extension_set, "GL_EXT_framebuffer_multisample") ||
+      gl::HasExtension(extension_set,
+                       "GL_EXT_multisampled_render_to_texture") ||
+      gl::HasExtension(extension_set, "GL_NV_framebuffer_multisample")) {
     glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
   }
   gpu_info->max_msaa_samples = base::IntToString(max_samples);
@@ -170,9 +167,9 @@
   }
 
   bool supports_robustness =
-      gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
-      gpu_info->gl_extensions.find("GL_KHR_robustness") != std::string::npos ||
-      gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
+      gl::HasExtension(extension_set, "GL_EXT_robustness") ||
+      gl::HasExtension(extension_set, "GL_KHR_robustness") ||
+      gl::HasExtension(extension_set, "GL_ARB_robustness");
   if (supports_robustness) {
     glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
         reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
diff --git a/headless/lib/browser/headless_browser_manifest_overlay.json b/headless/lib/browser/headless_browser_manifest_overlay.json
index 6483a30..80bc3f7 100644
--- a/headless/lib/browser/headless_browser_manifest_overlay.json
+++ b/headless/lib/browser/headless_browser_manifest_overlay.json
@@ -3,7 +3,7 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "requires": {
-        "pdf_compositor": [ "composite" ]
+        "pdf_compositor": [ "compositor" ]
       }
     },
     "navigation:frame": {
diff --git a/headless/lib/virtual_time_browsertest.cc b/headless/lib/virtual_time_browsertest.cc
index 3da3d0f..13fa6ba 100644
--- a/headless/lib/virtual_time_browsertest.cc
+++ b/headless/lib/virtual_time_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <memory>
+#include "base/strings/stringprintf.h"
 #include "content/public/test/browser_test.h"
 #include "headless/public/devtools/domains/emulation.h"
 #include "headless/public/devtools/domains/page.h"
@@ -51,20 +52,26 @@
     std::string message;
     if (args.size() == 1u && args[0]->HasValue() &&
         args[0]->GetValue()->GetAsString(&message)) {
-      console_logs_.push_back(message);
+      log_.push_back(message);
     }
   }
 
   // emulation::Observer implementation:
   void OnVirtualTimeBudgetExpired(
       const emulation::VirtualTimeBudgetExpiredParams& params) override {
-    EXPECT_THAT(console_logs_,
-                ElementsAre("step1", "step2", "step3", "step4", "pass"));
-
+    EXPECT_THAT(log_, ElementsAre("step1", "step2", "Paused @ 100ms", "step3",
+                                  "Paused @ 200ms", "step4", "pass",
+                                  "Paused @ 5000ms"));
     FinishAsynchronousTest();
   }
 
-  std::vector<std::string> console_logs_;
+  void OnVirtualTimePaused(
+      const emulation::VirtualTimePausedParams& params) override {
+    log_.push_back(
+        base::StringPrintf("Paused @ %dms", params.GetVirtualTimeElapsed()));
+  }
+
+  std::vector<std::string> log_;
 };
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(VirtualTimeBrowserTest);
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index 9dcb739..84f4b69 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -51,6 +51,10 @@
       builders { name: "fuchsia_compile" }
       builders { name: "linux_chromium_asan_rel_ng" }
       builders { name: "linux_chromium_chromeos_rel_ng" }
+      builders {
+        name: "linux_chromium_ozone_compile_only_ng"
+        experiment_percentage: 10
+      }
       builders { name: "linux_chromium_compile_dbg_ng" }
       builders { name: "linux_chromium_headless_rel" }
       builders { name: "linux_chromium_tsan_rel_ng" }
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
index 269f765..74ff975 100644
--- a/ios/build/bots/scripts/test_runner.py
+++ b/ios/build/bots/scripts/test_runner.py
@@ -224,7 +224,7 @@
     """
     return os.environ.copy()
 
-  def restart(self):
+  def shutdown_and_restart(self):
     """Restart a device or relaunch a simulator."""
     pass
 
@@ -327,7 +327,7 @@
       if result.crashed and not result.crashed_test:
         # If the app crashed but not during any particular test case, assume
         # it crashed on startup. Try one more time.
-        self.restart()
+        self.shutdown_and_restart()
         print 'Crashed on startup, retrying...'
         print
         result = self._run(cmd)
@@ -720,7 +720,7 @@
     except subprocess.CalledProcessError:
       raise TestDataExtractionError()
 
-  def restart(self):
+  def shutdown_and_restart(self):
     """Restart the device, wait for two minutes."""
     # TODO(crbug.com/760399): swarming bot ios 11 devices turn to be unavailable
     # in a few hours unexpectedly, which is assumed as an ios beta issue. Should
diff --git a/ios/chrome/DEPS b/ios/chrome/DEPS
index cba7de6..6304058 100644
--- a/ios/chrome/DEPS
+++ b/ios/chrome/DEPS
@@ -19,4 +19,10 @@
   "-ios/chrome",
   "+ios/chrome/common",
   "+ios/chrome/test",
+
+  # All code in ios/chrome assumes that web::BrowserState* can be safely
+  # casted to ios::ChromeBrowserState*. This mean that no code should use
+  # web::TestBrowserState in ios/chrome.
+  "+ios/web/public",
+  "-ios/web/public/test/fakes/test_browser_state.h",
 ]
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 63fffd41..17f1f470 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -32,7 +32,6 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
-    "chrome_app_startup_parameters_unittest.mm",
     "chrome_overlay_window_testing.h",
     "deferred_initialization_runner_unittest.mm",
     "main_application_delegate_unittest.mm",
@@ -117,8 +116,6 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
     "application_mode.h",
-    "chrome_app_startup_parameters.h",
-    "chrome_app_startup_parameters.mm",
     "chrome_overlay_window.h",
     "chrome_overlay_window.mm",
     "main_application_delegate.h",
@@ -228,6 +225,7 @@
     "//ios/public/provider/chrome/browser/distribution",
     "//ios/public/provider/chrome/browser/signin",
     "//ios/public/provider/chrome/browser/user_feedback",
+    "//ios/testing/perf:startup",
     "//ios/third_party/material_roboto_font_loader_ios",
     "//ios/web",
     "//ios/web/public/app",
@@ -263,6 +261,7 @@
     "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/crash_report",
     "//ios/chrome/common",
+    "//ios/testing/perf:startup",
     "//third_party/google_toolbox_for_mac",
   ]
 }
diff --git a/ios/chrome/app/DEPS b/ios/chrome/app/DEPS
index e52ccc7..e35b827 100644
--- a/ios/chrome/app/DEPS
+++ b/ios/chrome/app/DEPS
@@ -26,7 +26,6 @@
   "+ios/chrome/browser/feature_engagement",
   "+ios/net",
   "+ios/public/provider/chrome",
-  "+ios/web/public",
   "+mojo/edk/embedder/embedder.h",
 
   # Strings and resources.
diff --git a/ios/chrome/app/application_delegate/url_opener.mm b/ios/chrome/app/application_delegate/url_opener.mm
index c0b6d1b7..85eefae 100644
--- a/ios/chrome/app/application_delegate/url_opener.mm
+++ b/ios/chrome/app/application_delegate/url_opener.mm
@@ -10,7 +10,7 @@
 #import "ios/chrome/app/application_delegate/app_state.h"
 #import "ios/chrome/app/application_delegate/startup_information.h"
 #import "ios/chrome/app/application_delegate/tab_opening.h"
-#include "ios/chrome/app/chrome_app_startup_parameters.h"
+#include "ios/chrome/app/startup/chrome_app_startup_parameters.h"
 #import "ios/chrome/browser/chrome_url_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/app/application_delegate/url_opener_unittest.mm b/ios/chrome/app/application_delegate/url_opener_unittest.mm
index 253441b..c3c5764 100644
--- a/ios/chrome/app/application_delegate/url_opener_unittest.mm
+++ b/ios/chrome/app/application_delegate/url_opener_unittest.mm
@@ -10,10 +10,10 @@
 #include "ios/chrome/app/application_delegate/app_state.h"
 #include "ios/chrome/app/application_delegate/app_state_testing.h"
 #include "ios/chrome/app/application_delegate/mock_tab_opener.h"
-#include "ios/chrome/app/chrome_app_startup_parameters.h"
 #include "ios/chrome/app/main_application_delegate.h"
 #include "ios/chrome/app/main_controller.h"
 #include "ios/chrome/app/main_controller_private.h"
+#include "ios/chrome/app/startup/chrome_app_startup_parameters.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
diff --git a/ios/chrome/app/application_delegate/user_activity_handler.mm b/ios/chrome/app/application_delegate/user_activity_handler.mm
index 784ee54..0db6234 100644
--- a/ios/chrome/app/application_delegate/user_activity_handler.mm
+++ b/ios/chrome/app/application_delegate/user_activity_handler.mm
@@ -17,9 +17,9 @@
 #import "ios/chrome/app/application_delegate/startup_information.h"
 #import "ios/chrome/app/application_delegate/tab_opening.h"
 #include "ios/chrome/app/application_mode.h"
-#include "ios/chrome/app/chrome_app_startup_parameters.h"
 #import "ios/chrome/app/spotlight/actions_spotlight_manager.h"
 #import "ios/chrome/app/spotlight/spotlight_util.h"
+#include "ios/chrome/app/startup/chrome_app_startup_parameters.h"
 #include "ios/chrome/browser/app_startup_parameters.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/metrics/first_user_action_recorder.h"
diff --git a/ios/chrome/app/chrome_app_startup_parameters.h b/ios/chrome/app/chrome_app_startup_parameters.h
deleted file mode 100644
index eca5dde8..0000000
--- a/ios/chrome/app/chrome_app_startup_parameters.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_APP_CHROME_APP_STARTUP_PARAMETERS_H_
-#define IOS_CHROME_APP_CHROME_APP_STARTUP_PARAMETERS_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/app_startup_parameters.h"
-#import "ios/chrome/browser/first_run/first_run_metrics.h"
-
-// Values of the UMA Startup.MobileSessionCallerApp histogram.
-enum MobileSessionCallerApp {
-  CALLER_APP_GOOGLE_SEARCH = 0,
-  CALLER_APP_GOOGLE_GMAIL,
-  CALLER_APP_GOOGLE_PLUS,
-  CALLER_APP_GOOGLE_DRIVE,
-  CALLER_APP_GOOGLE_EARTH,
-  CALLER_APP_GOOGLE_OTHER,
-  CALLER_APP_OTHER,
-  CALLER_APP_APPLE_MOBILESAFARI,
-  CALLER_APP_APPLE_OTHER,
-  CALLER_APP_GOOGLE_YOUTUBE,
-  CALLER_APP_GOOGLE_MAPS,
-  CALLER_APP_NOT_AVAILABLE,  // Includes being launched from Smart App Banner.
-  CALLER_APP_GOOGLE_CHROME_TODAY_EXTENSION,
-  MOBILE_SESSION_CALLER_APP_COUNT,
-};
-
-@interface ChromeAppStartupParameters : AppStartupParameters
-
-- (instancetype)initWithExternalURL:(const GURL&)externalURL NS_UNAVAILABLE;
-
-- (instancetype)initWithExternalURL:(const GURL&)externalURL
-                  declaredSourceApp:(NSString*)declaredSourceApp
-                    secureSourceApp:(NSString*)secureSourceApp
-                        completeURL:(NSURL*)completeURL
-    NS_DESIGNATED_INITIALIZER;
-
-// Returns a ChromeAppStartupParameters instance containing the URL to
-// open (|externalURL|). In case the URL is conforming to the x-callback-url
-// specification, additional information are stored in the returned value.
-//
-// The forms of the URLs we expect are:
-//
-// - protocol0://url/goes/here
-//   Here protocol0s opens the app. The string for the
-//   parsed URL is "url/goes/here" with protocol
-//   "http", that is, the string for the parsed URL is
-//   "http://url/goes/here"
-//
-// - protocol0s://url/goes/here
-//   Here protocol0s opens the app. The string for the
-//   parsed URL is "url/goes/here" with protocol
-//   "https", that is, the string for the parsed URL is
-//   "https://url/goes/here"
-//
-// - url/goes/here
-//   No protocol is given. The string for the parsed URL is
-//   "url/goes/here", with protocol defaulting to "http",
-//   that is, the string for the parsed URL is
-//   "http://url/goes/here"
-//
-// - file://url/goes/here
-//   Here the received URL is a file. This is used in cases where the app
-//   receives a file from another app. The string for the parser URL is
-//   "chrome://external-file/url/goes/here"
-//
-// - x-<protocol>://x-callback-url/<action>?url=<url/goes/here>
-//   This forms is compliant with x-callback-url (x-callback-url.com).
-//   Currently the only action supported for external application is "open" and
-//   the only required parameter is |url| containing the url to open inclusive
-//   of protocol.
-//   For application members of the Chrome Application Group,
-//   "app-group-command" command can be used. In that case, the paramaters are
-//   sent via the shared NSUserDefault dictionary.
-//
-// Note the protocol isn't hardcoded so we accept anything. Moreover, in iOS 6
-// SmartAppBanners can send any URL to the app without even needing the app
-// to be registered for that protocol.
-// If the string for the parsed URL is malformed (according to RFC 2396),
-// returns nil.
-+ (instancetype)newChromeAppStartupParametersWithURL:(NSURL*)url
-                               fromSourceApplication:(NSString*)appId;
-
-// Returns the MobileSessionCallerApp for the given bundle ID.
-- (MobileSessionCallerApp)callerApp;
-
-// Checks the parsed url and heuristically determine if it implies that the
-// current openURL: delegate call is the result of a user click on Smart App
-// Banner.
-- (first_run::ExternalLaunch)launchSource;
-
-@end
-
-@interface ChromeAppStartupParameters (Testing)
-
-+ (instancetype)newAppStartupParametersForCommand:(NSString*)command
-                                  withExternalURL:(NSString*)externalURL
-                                        withIndex:(NSNumber*)index
-                                          withURL:(NSURL*)url
-                            fromSourceApplication:(NSString*)appId
-                      fromSecureSourceApplication:(NSString*)secureSourceApp;
-
-@end
-
-#endif  // IOS_CHROME_APP_CHROME_APP_STARTUP_PARAMETERS_H_
diff --git a/ios/chrome/app/chrome_app_startup_parameters.mm b/ios/chrome/app/chrome_app_startup_parameters.mm
deleted file mode 100644
index 4db423c..0000000
--- a/ios/chrome/app/chrome_app_startup_parameters.mm
+++ /dev/null
@@ -1,398 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/app/chrome_app_startup_parameters.h"
-
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics_action.h"
-#include "base/strings/sys_string_conversions.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/common/app_group/app_group_constants.h"
-#include "ios/chrome/common/x_callback_url.h"
-#import "net/base/mac/url_conversions.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-// Key of the UMA Startup.MobileSessionStartAction histogram.
-const char kUMAMobileSessionStartActionHistogram[] =
-    "Startup.MobileSessionStartAction";
-
-const char kApplicationGroupCommandDelay[] =
-    "Startup.ApplicationGroupCommandDelay";
-
-// URL Query String parameter to indicate that this openURL: request arrived
-// here due to a Smart App Banner presentation on a Google.com page.
-NSString* const kSmartAppBannerKey = @"safarisab";
-
-const CGFloat kAppGroupTriggersVoiceSearchTimeout = 15.0;
-
-// Values of the UMA Startup.MobileSessionStartAction histogram.
-enum MobileSessionStartAction {
-  START_ACTION_OPEN_HTTP = 0,
-  START_ACTION_OPEN_HTTPS,
-  START_ACTION_OPEN_FILE,
-  START_ACTION_XCALLBACK_OPEN,
-  START_ACTION_XCALLBACK_OTHER,
-  START_ACTION_OTHER,
-  START_ACTION_XCALLBACK_APPGROUP_COMMAND,
-  MOBILE_SESSION_START_ACTION_COUNT,
-};
-
-// Values of the UMA iOS.SearchExtension.Action histogram.
-enum SearchExtensionAction {
-  ACTION_NO_ACTION,
-  ACTION_NEW_SEARCH,
-  ACTION_NEW_INCOGNITO_SEARCH,
-  ACTION_NEW_VOICE_SEARCH,
-  ACTION_NEW_QR_CODE_SEARCH,
-  ACTION_OPEN_URL,
-  SEARCH_EXTENSION_ACTION_COUNT,
-};
-
-}  // namespace
-
-@implementation ChromeAppStartupParameters {
-  NSString* _secureSourceApp;
-  NSString* _declaredSourceApp;
-  NSURL* _completeURL;
-}
-
-- (instancetype)initWithExternalURL:(const GURL&)externalURL
-                  declaredSourceApp:(NSString*)declaredSourceApp
-                    secureSourceApp:(NSString*)secureSourceApp
-                        completeURL:(NSURL*)completeURL {
-  self = [super initWithExternalURL:externalURL];
-  if (self) {
-    _declaredSourceApp = [declaredSourceApp copy];
-    _secureSourceApp = [secureSourceApp copy];
-    _completeURL = completeURL;
-  }
-  return self;
-}
-
-+ (instancetype)newChromeAppStartupParametersWithURL:(NSURL*)completeURL
-                               fromSourceApplication:(NSString*)appId {
-  GURL gurl = net::GURLWithNSURL(completeURL);
-
-  if (!gurl.is_valid() || gurl.scheme().length() == 0)
-    return nil;
-
-  // TODO(ios): Temporary fix for b/7174478
-  if (IsXCallbackURL(gurl)) {
-    NSString* action = [completeURL path];
-    // Currently only "open" and "extension-command" are supported.
-    // Other actions are being considered (see b/6914153).
-    if ([action
-            isEqualToString:
-                [NSString
-                    stringWithFormat:
-                        @"/%s", app_group::kChromeAppGroupXCallbackCommand]]) {
-      UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
-                                START_ACTION_XCALLBACK_APPGROUP_COMMAND,
-                                MOBILE_SESSION_START_ACTION_COUNT);
-      return [ChromeAppStartupParameters
-          newExtensionCommandAppStartupParametersFromWithURL:completeURL
-                                       fromSourceApplication:appId];
-    }
-
-    if (![action isEqualToString:@"/open"]) {
-      UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
-                                START_ACTION_XCALLBACK_OTHER,
-                                MOBILE_SESSION_START_ACTION_COUNT);
-      return nil;
-    }
-
-    UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
-                              START_ACTION_XCALLBACK_OPEN,
-                              MOBILE_SESSION_START_ACTION_COUNT);
-
-    std::map<std::string, std::string> parameters =
-        ExtractQueryParametersFromXCallbackURL(gurl);
-    GURL url = GURL(parameters["url"]);
-    if (!url.is_valid() ||
-        (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme))) {
-      return nil;
-    }
-
-    return [[ChromeAppStartupParameters alloc]
-        initWithExternalURL:url
-          declaredSourceApp:appId
-            secureSourceApp:nil
-                completeURL:completeURL];
-
-  } else if (gurl.SchemeIsFile()) {
-    UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
-                              START_ACTION_OPEN_FILE,
-                              MOBILE_SESSION_START_ACTION_COUNT);
-    // |url| is the path to a file received from another application.
-    GURL::Replacements replacements;
-    const std::string host(kChromeUIExternalFileHost);
-    std::string filename = gurl.ExtractFileName();
-    replacements.SetPathStr(filename);
-    replacements.SetSchemeStr(kChromeUIScheme);
-    replacements.SetHostStr(host);
-    GURL externalURL = gurl.ReplaceComponents(replacements);
-    if (!externalURL.is_valid())
-      return nil;
-    return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
-                                                 declaredSourceApp:appId
-                                                   secureSourceApp:nil
-                                                       completeURL:completeURL];
-  } else {
-    // Replace the scheme with https or http depending on whether the input
-    // |url| scheme ends with an 's'.
-    BOOL useHttps = gurl.scheme()[gurl.scheme().length() - 1] == 's';
-    MobileSessionStartAction action =
-        useHttps ? START_ACTION_OPEN_HTTPS : START_ACTION_OPEN_HTTP;
-    UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram, action,
-                              MOBILE_SESSION_START_ACTION_COUNT);
-    GURL::Replacements replace_scheme;
-    if (useHttps)
-      replace_scheme.SetSchemeStr(url::kHttpsScheme);
-    else
-      replace_scheme.SetSchemeStr(url::kHttpScheme);
-    GURL externalURL = gurl.ReplaceComponents(replace_scheme);
-    if (!externalURL.is_valid())
-      return nil;
-    return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
-                                                 declaredSourceApp:appId
-                                                   secureSourceApp:nil
-                                                       completeURL:completeURL];
-  }
-}
-
-+ (instancetype)newExtensionCommandAppStartupParametersFromWithURL:(NSURL*)url
-                                             fromSourceApplication:
-                                                 (NSString*)appId {
-  NSString* appGroup = app_group::ApplicationGroup();
-  NSUserDefaults* sharedDefaults =
-      [[NSUserDefaults alloc] initWithSuiteName:appGroup];
-
-  NSString* commandDictionaryPreference =
-      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference);
-  NSDictionary* commandDictionary = base::mac::ObjCCast<NSDictionary>(
-      [sharedDefaults objectForKey:commandDictionaryPreference]);
-
-  [sharedDefaults removeObjectForKey:commandDictionaryPreference];
-
-  // |sharedDefaults| is used for communication between apps. Synchronize to
-  // avoid synchronization issues (like removing the next order).
-  [sharedDefaults synchronize];
-
-  if (!commandDictionary) {
-    return nil;
-  }
-
-  NSString* commandCallerPreference =
-      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference);
-  NSString* commandCaller = base::mac::ObjCCast<NSString>(
-      [commandDictionary objectForKey:commandCallerPreference]);
-
-  NSString* commandPreference = base::SysUTF8ToNSString(
-      app_group::kChromeAppGroupCommandCommandPreference);
-  NSString* command = base::mac::ObjCCast<NSString>(
-      [commandDictionary objectForKey:commandPreference]);
-
-  NSString* commandTimePreference =
-      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference);
-  id commandTime = base::mac::ObjCCast<NSDate>(
-      [commandDictionary objectForKey:commandTimePreference]);
-
-  NSString* commandURLPreference =
-      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandURLPreference);
-  NSString* externalURL = base::mac::ObjCCast<NSString>(
-      [commandDictionary objectForKey:commandURLPreference]);
-
-  NSString* commandIndexPreference =
-      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandIndexPreference);
-  NSNumber* index = base::mac::ObjCCast<NSNumber>(
-      [commandDictionary objectForKey:commandIndexPreference]);
-
-  if (!commandCaller || !command || !commandTimePreference) {
-    return nil;
-  }
-
-  // Check the time of the last request to avoid app from intercepting old
-  // open url request and replay it later.
-  NSTimeInterval delay = [[NSDate date] timeIntervalSinceDate:commandTime];
-  UMA_HISTOGRAM_COUNTS_100(kApplicationGroupCommandDelay, delay);
-  if (delay > kAppGroupTriggersVoiceSearchTimeout)
-    return nil;
-  return [ChromeAppStartupParameters
-      newAppStartupParametersForCommand:command
-                        withExternalURL:externalURL
-                              withIndex:index
-                                withURL:url
-
-                  fromSourceApplication:appId
-            fromSecureSourceApplication:commandCaller];
-}
-
-+ (instancetype)newAppStartupParametersForCommand:(NSString*)command
-                                  withExternalURL:(NSString*)externalURL
-                                        withIndex:(NSNumber*)index
-                                          withURL:(NSURL*)url
-                            fromSourceApplication:(NSString*)appId
-                      fromSecureSourceApplication:(NSString*)secureSourceApp {
-  SearchExtensionAction action = ACTION_NO_ACTION;
-  ChromeAppStartupParameters* params = nil;
-
-  if ([command
-          isEqualToString:base::SysUTF8ToNSString(
-                              app_group::kChromeAppGroupVoiceSearchCommand)]) {
-    params = [[ChromeAppStartupParameters alloc]
-        initWithExternalURL:GURL(kChromeUINewTabURL)
-          declaredSourceApp:appId
-            secureSourceApp:secureSourceApp
-                completeURL:url];
-    [params setPostOpeningAction:START_VOICE_SEARCH];
-    action = ACTION_NEW_VOICE_SEARCH;
-  }
-
-  if ([command isEqualToString:base::SysUTF8ToNSString(
-                                   app_group::kChromeAppGroupNewTabCommand)]) {
-    params = [[ChromeAppStartupParameters alloc]
-        initWithExternalURL:GURL(kChromeUINewTabURL)
-          declaredSourceApp:appId
-            secureSourceApp:secureSourceApp
-                completeURL:url];
-    action = ACTION_NO_ACTION;
-  }
-
-  if ([command
-          isEqualToString:base::SysUTF8ToNSString(
-                              app_group::kChromeAppGroupFocusOmniboxCommand)]) {
-    params = [[ChromeAppStartupParameters alloc]
-        initWithExternalURL:GURL(kChromeUINewTabURL)
-          declaredSourceApp:appId
-            secureSourceApp:secureSourceApp
-                completeURL:url];
-    [params setPostOpeningAction:FOCUS_OMNIBOX];
-    action = ACTION_NEW_SEARCH;
-  }
-
-  if ([command isEqualToString:base::SysUTF8ToNSString(
-                                   app_group::kChromeAppGroupOpenURLCommand)]) {
-    if (!externalURL || ![externalURL isKindOfClass:[NSString class]])
-      return nil;
-    GURL externalGURL(base::SysNSStringToUTF8(externalURL));
-    if (!externalGURL.is_valid() || !externalGURL.SchemeIsHTTPOrHTTPS())
-      return nil;
-    params =
-        [[ChromeAppStartupParameters alloc] initWithExternalURL:externalGURL
-                                              declaredSourceApp:appId
-                                                secureSourceApp:secureSourceApp
-                                                    completeURL:url];
-    action = ACTION_OPEN_URL;
-  }
-
-  if ([command
-          isEqualToString:base::SysUTF8ToNSString(
-                              app_group::kChromeAppGroupQRScannerCommand)]) {
-    params = [[ChromeAppStartupParameters alloc]
-        initWithExternalURL:GURL(kChromeUINewTabURL)
-          declaredSourceApp:appId
-            secureSourceApp:secureSourceApp
-                completeURL:url];
-    [params setPostOpeningAction:START_QR_CODE_SCANNER];
-    action = ACTION_NEW_QR_CODE_SEARCH;
-  }
-
-  if ([command isEqualToString:
-                   base::SysUTF8ToNSString(
-                       app_group::kChromeAppGroupIncognitoSearchCommand)]) {
-    params = [[ChromeAppStartupParameters alloc]
-        initWithExternalURL:GURL(kChromeUINewTabURL)
-          declaredSourceApp:appId
-            secureSourceApp:secureSourceApp
-                completeURL:url];
-    [params setLaunchInIncognito:YES];
-    [params setPostOpeningAction:FOCUS_OMNIBOX];
-    action = ACTION_NEW_INCOGNITO_SEARCH;
-  }
-
-  if ([secureSourceApp
-          isEqualToString:app_group::kOpenCommandSourceSearchExtension]) {
-    UMA_HISTOGRAM_ENUMERATION("IOS.SearchExtension.Action", action,
-                              SEARCH_EXTENSION_ACTION_COUNT);
-  }
-  if ([secureSourceApp
-          isEqualToString:app_group::kOpenCommandSourceContentExtension] &&
-      index) {
-    UMA_HISTOGRAM_COUNTS_100("IOS.ContentExtension.Index",
-                             [index integerValue]);
-  }
-  return params;
-}
-
-- (MobileSessionCallerApp)callerApp {
-  if ([_secureSourceApp
-          isEqualToString:app_group::kOpenCommandSourceTodayExtension])
-    return CALLER_APP_GOOGLE_CHROME_TODAY_EXTENSION;
-
-  if (![_declaredSourceApp length])
-    return CALLER_APP_NOT_AVAILABLE;
-  if ([_declaredSourceApp isEqualToString:@"com.google.GoogleMobile"])
-    return CALLER_APP_GOOGLE_SEARCH;
-  if ([_declaredSourceApp isEqualToString:@"com.google.Gmail"])
-    return CALLER_APP_GOOGLE_GMAIL;
-  if ([_declaredSourceApp isEqualToString:@"com.google.GooglePlus"])
-    return CALLER_APP_GOOGLE_PLUS;
-  if ([_declaredSourceApp isEqualToString:@"com.google.Drive"])
-    return CALLER_APP_GOOGLE_DRIVE;
-  if ([_declaredSourceApp isEqualToString:@"com.google.b612"])
-    return CALLER_APP_GOOGLE_EARTH;
-  if ([_declaredSourceApp isEqualToString:@"com.google.ios.youtube"])
-    return CALLER_APP_GOOGLE_YOUTUBE;
-  if ([_declaredSourceApp isEqualToString:@"com.google.Maps"])
-    return CALLER_APP_GOOGLE_MAPS;
-  if ([_declaredSourceApp hasPrefix:@"com.google."])
-    return CALLER_APP_GOOGLE_OTHER;
-  if ([_declaredSourceApp isEqualToString:@"com.apple.mobilesafari"])
-    return CALLER_APP_APPLE_MOBILESAFARI;
-  if ([_declaredSourceApp hasPrefix:@"com.apple."])
-    return CALLER_APP_APPLE_OTHER;
-
-  return CALLER_APP_OTHER;
-}
-
-- (first_run::ExternalLaunch)launchSource {
-  if ([self callerApp] != CALLER_APP_APPLE_MOBILESAFARI) {
-    return first_run::LAUNCH_BY_OTHERS;
-  }
-
-  NSString* query = [_completeURL query];
-  // Takes care of degenerated case of no QUERY_STRING.
-  if (![query length])
-    return first_run::LAUNCH_BY_MOBILESAFARI;
-  // Look for |kSmartAppBannerKey| anywhere within the query string.
-  NSRange found = [query rangeOfString:kSmartAppBannerKey];
-  if (found.location == NSNotFound)
-    return first_run::LAUNCH_BY_MOBILESAFARI;
-  // |kSmartAppBannerKey| can be at the beginning or end of the query
-  // string and may also be optionally followed by a equal sign and a value.
-  // For now, just look for the presence of the key and ignore the value.
-  if (found.location + found.length < [query length]) {
-    // There are characters following the found location.
-    unichar charAfter =
-        [query characterAtIndex:(found.location + found.length)];
-    if (charAfter != '&' && charAfter != '=')
-      return first_run::LAUNCH_BY_MOBILESAFARI;
-  }
-  if (found.location > 0) {
-    unichar charBefore = [query characterAtIndex:(found.location - 1)];
-    if (charBefore != '&')
-      return first_run::LAUNCH_BY_MOBILESAFARI;
-  }
-  return first_run::LAUNCH_BY_SMARTAPPBANNER;
-}
-
-@end
diff --git a/ios/chrome/app/chrome_app_startup_parameters_unittest.mm b/ios/chrome/app/chrome_app_startup_parameters_unittest.mm
deleted file mode 100644
index 3d1845e..0000000
--- a/ios/chrome/app/chrome_app_startup_parameters_unittest.mm
+++ /dev/null
@@ -1,277 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/app/chrome_app_startup_parameters.h"
-
-#import <Foundation/Foundation.h>
-
-#include "base/strings/stringprintf.h"
-#include "ios/chrome/browser/app_startup_parameters.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/common/app_group/app_group_constants.h"
-#include "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-void CheckLaunchSourceForURL(first_run::ExternalLaunch expectedSource,
-                             NSString* urlString) {
-  NSURL* url = [NSURL URLWithString:urlString];
-  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
-      newChromeAppStartupParametersWithURL:url
-                     fromSourceApplication:@"com.apple.mobilesafari"];
-  EXPECT_EQ(expectedSource, [params launchSource]);
-}
-
-typedef PlatformTest AppStartupParametersTest;
-TEST_F(PlatformTest, ParseURLWithEmptyURL) {
-  NSURL* url = [NSURL URLWithString:@""];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-
-  EXPECT_FALSE(params);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithOneProtocol) {
-  NSURL* url = [NSURL URLWithString:@"protocol://www.google.com"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-  // Here "protocol" opens the app and no protocol is given for the parsed URL,
-  // which defaults to be "http".
-  EXPECT_EQ("http://www.google.com/", [params externalURL].spec());
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithEmptyParsedURL) {
-  // Test chromium://
-  NSURL* url = [NSURL URLWithString:@"chromium://"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-
-  EXPECT_FALSE(params);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithParsedURLDefaultToHttp) {
-  NSURL* url = [NSURL URLWithString:@"chromium://www.google.com"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-
-  EXPECT_EQ("http://www.google.com/", [params externalURL].spec());
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithInvalidParsedURL) {
-  NSURL* url = [NSURL URLWithString:@"http:google.com:foo"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-
-  EXPECT_FALSE(params);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithHttpsParsedURL) {
-  NSURL* url = [NSURL URLWithString:@"chromiums://www.google.com"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-
-  EXPECT_EQ("https://www.google.com/", [params externalURL].spec());
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithXCallbackURL) {
-  NSURL* url =
-      [NSURL URLWithString:@"chromium-x-callback://x-callback-url/open?"
-                            "url=https://www.google.com"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-  EXPECT_EQ("https://www.google.com/", [params externalURL].spec());
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithXCallbackURLAndExtraParams) {
-  NSURL* url =
-      [NSURL URLWithString:@"chromium-x-callback://x-callback-url/open?"
-                            "url=https://www.google.com&"
-                            "x-success=http://success"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-  EXPECT_EQ("https://www.google.com/", [params externalURL].spec());
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithMalformedXCallbackURL) {
-  NSURL* url = [NSURL
-      URLWithString:@"chromium-x-callback://x-callback-url/open?url=foobar&"
-                     "x-source=myapp&x-success=http://success"];
-  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
-      newChromeAppStartupParametersWithURL:url
-                     fromSourceApplication:@"com.myapp"];
-  EXPECT_FALSE(params);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithJavascriptURLInXCallbackURL) {
-  NSURL* url = [NSURL
-      URLWithString:
-          @"chromium-x-callback://x-callback-url/open?url="
-           "javascript:window.open()&x-source=myapp&x-success=http://success"];
-  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
-      newChromeAppStartupParametersWithURL:url
-                     fromSourceApplication:@"com.myapp"];
-  EXPECT_FALSE(params);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithChromeURLInXCallbackURL) {
-  NSURL* url =
-      [NSURL URLWithString:@"chromium-x-callback://x-callback-url/open?url="
-                            "chrome:passwords"];
-  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
-      newChromeAppStartupParametersWithURL:url
-                     fromSourceApplication:@"com.myapp"];
-  EXPECT_FALSE(params);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithFileParsedURL) {
-  NSURL* url = [NSURL URLWithString:@"file://localhost/path/to/file.pdf"];
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
-                                                 fromSourceApplication:nil];
-
-  std::string expectedUrlString = base::StringPrintf(
-      "%s://%s/file.pdf", kChromeUIScheme, kChromeUIExternalFileHost);
-
-  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithAppGroupVoiceSearch) {
-  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
-      newAppStartupParametersForCommand:@"voicesearch"
-                        withExternalURL:nil
-                              withIndex:0
-                                withURL:nil
-                  fromSourceApplication:nil
-            fromSecureSourceApplication:nil];
-
-  std::string expectedUrlString =
-      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
-
-  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
-  EXPECT_EQ([params postOpeningAction], START_VOICE_SEARCH);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithAppGroupQRCode) {
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newAppStartupParametersForCommand:@"qrscanner"
-                                                    withExternalURL:nil
-                                                          withIndex:0
-                                                            withURL:nil
-                                              fromSourceApplication:nil
-                                        fromSecureSourceApplication:nil];
-
-  std::string expectedUrlString =
-      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
-
-  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
-  EXPECT_EQ([params postOpeningAction], START_QR_CODE_SCANNER);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithAppGroupFocusOmbnibox) {
-  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
-      newAppStartupParametersForCommand:@"focusomnibox"
-                        withExternalURL:nil
-                              withIndex:0
-                                withURL:nil
-                  fromSourceApplication:nil
-            fromSecureSourceApplication:nil];
-
-  std::string expectedUrlString =
-      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
-
-  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
-  EXPECT_EQ([params postOpeningAction], FOCUS_OMNIBOX);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithAppGroupNewTab) {
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newAppStartupParametersForCommand:@"newtab"
-                                                    withExternalURL:nil
-                                                          withIndex:0
-                                                            withURL:nil
-                                              fromSourceApplication:nil
-                                        fromSecureSourceApplication:nil];
-  std::string expectedUrlString =
-      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
-
-  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
-  EXPECT_EQ([params postOpeningAction], NO_ACTION);
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithAppGroupOpenURL) {
-  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
-      newAppStartupParametersForCommand:@"openurl"
-                        withExternalURL:@"http://foo/bar"
-
-                              withIndex:0
-                                withURL:nil
-                  fromSourceApplication:nil
-            fromSecureSourceApplication:nil];
-
-  EXPECT_EQ("http://foo/bar", [params externalURL].spec());
-}
-
-TEST_F(AppStartupParametersTest, ParseURLWithAppGroupGarbage) {
-  ChromeAppStartupParameters* params =
-      [ChromeAppStartupParameters newAppStartupParametersForCommand:@"garbage"
-                                                    withExternalURL:nil
-                                                          withIndex:0
-                                                            withURL:nil
-                                              fromSourceApplication:nil
-                                        fromSecureSourceApplication:nil];
-  EXPECT_FALSE(params);
-}
-
-TEST_F(AppStartupParametersTest, FirstRunExternalLaunchSource) {
-  // Key at the beginning of query string.
-  CheckLaunchSourceForURL(
-      first_run::LAUNCH_BY_SMARTAPPBANNER,
-      @"http://www.google.com/search?safarisab=1&query=pony");
-  // Key at the end of query string.
-  CheckLaunchSourceForURL(
-      first_run::LAUNCH_BY_SMARTAPPBANNER,
-      @"http://www.google.com/search?query=pony&safarisab=1");
-  // Key in the middle of query string.
-  CheckLaunchSourceForURL(
-      first_run::LAUNCH_BY_SMARTAPPBANNER,
-      @"http://www.google.com/search?query=pony&safarisab=1&hl=en");
-  // Key without '=' sign at the beginning, end, and middle of query string.
-  CheckLaunchSourceForURL(first_run::LAUNCH_BY_SMARTAPPBANNER,
-                          @"http://www.google.com/search?safarisab&query=pony");
-  CheckLaunchSourceForURL(first_run::LAUNCH_BY_SMARTAPPBANNER,
-                          @"http://www.google.com/search?query=pony&safarisab");
-  CheckLaunchSourceForURL(
-      first_run::LAUNCH_BY_SMARTAPPBANNER,
-      @"http://www.google.com/search?query=pony&safarisab&hl=en");
-  // No query string in URL.
-  CheckLaunchSourceForURL(first_run::LAUNCH_BY_MOBILESAFARI,
-                          @"http://www.google.com/");
-  CheckLaunchSourceForURL(first_run::LAUNCH_BY_MOBILESAFARI,
-                          @"http://www.google.com/safarisab/foo/bar");
-  // Key not present in query string.
-  CheckLaunchSourceForURL(first_run::LAUNCH_BY_MOBILESAFARI,
-                          @"http://www.google.com/search?query=pony");
-  // Key is a substring of some other string.
-  CheckLaunchSourceForURL(
-      first_run::LAUNCH_BY_MOBILESAFARI,
-      @"http://www.google.com/search?query=pony&safarisabcdefg=1");
-  CheckLaunchSourceForURL(
-      first_run::LAUNCH_BY_MOBILESAFARI,
-      @"http://www.google.com/search?query=pony&notsafarisab=1&abc=def");
-}
-
-}  // namespace
diff --git a/ios/chrome/app/chrome_exe_main.mm b/ios/chrome/app/chrome_exe_main.mm
index 0a7fa10..5c49215 100644
--- a/ios/chrome/app/chrome_exe_main.mm
+++ b/ios/chrome/app/chrome_exe_main.mm
@@ -11,6 +11,7 @@
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
 #include "ios/chrome/browser/crash_report/crash_keys.h"
 #include "ios/chrome/common/channel_info.h"
+#include "ios/testing/perf/startupLoggers.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -59,6 +60,7 @@
 
 int main(int argc, char* argv[]) {
   IOSChromeMain::InitStartTime();
+  startup_loggers::RegisterAppStartTime();
 
   // Set NSUserDefaults keys to force pseudo-RTL if needed.
   SetTextDirectionIfPseudoRTLEnabled();
diff --git a/ios/chrome/app/main_application_delegate.mm b/ios/chrome/app/main_application_delegate.mm
index c059ab31a..1b1d41c 100644
--- a/ios/chrome/app/main_application_delegate.mm
+++ b/ios/chrome/app/main_application_delegate.mm
@@ -21,6 +21,7 @@
 #import "ios/chrome/app/main_controller.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
+#import "ios/testing/perf/startupLoggers.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -91,6 +92,7 @@
 // startup is fast, and the UI appears as soon as possible.
 - (BOOL)application:(UIApplication*)application
     didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+  startup_loggers::RegisterAppDidFinishLaunchingTime();
   // Main window must be ChromeOverlayWindow or a subclass of it.
   self.window = [[ChromeOverlayWindow alloc]
       initWithFrame:[[UIScreen mainScreen] bounds]];
@@ -102,6 +104,7 @@
 }
 
 - (void)applicationDidBecomeActive:(UIApplication*)application {
+  startup_loggers::RegisterAppDidBecomeActiveTime();
   if ([_appState isInSafeMode])
     return;
 
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 4a4c9cbb..50396ab 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -40,13 +40,13 @@
 #import "ios/chrome/app/application_delegate/metrics_mediator.h"
 #import "ios/chrome/app/application_delegate/url_opener.h"
 #include "ios/chrome/app/application_mode.h"
-#include "ios/chrome/app/chrome_app_startup_parameters.h"
 #import "ios/chrome/app/deferred_initialization_runner.h"
 #import "ios/chrome/app/main_controller_private.h"
 #import "ios/chrome/app/memory_monitor.h"
 #import "ios/chrome/app/safe_mode_crashing_modules_config.h"
 #import "ios/chrome/app/spotlight/spotlight_manager.h"
 #import "ios/chrome/app/spotlight/spotlight_util.h"
+#include "ios/chrome/app/startup/chrome_app_startup_parameters.h"
 #include "ios/chrome/app/startup/chrome_main_starter.h"
 #include "ios/chrome/app/startup/client_registration.h"
 #import "ios/chrome/app/startup/content_suggestions_scheduler_notifications.h"
@@ -1735,7 +1735,7 @@
     [currentTab setSnapshotCoalescingEnabled:NO];
   }));
 
-  [currentBVC prepareToEnterTabSwitcher:nil];
+  [currentTab updateSnapshotWithOverlay:YES visibleFrameOnly:YES];
 
   if (!_tabSwitcherController) {
     if (IsIPadIdiom()) {
diff --git a/ios/chrome/app/startup/BUILD.gn b/ios/chrome/app/startup/BUILD.gn
index 576e845..d2f1d09a 100644
--- a/ios/chrome/app/startup/BUILD.gn
+++ b/ios/chrome/app/startup/BUILD.gn
@@ -35,6 +35,8 @@
 
 source_set("startup") {
   sources = [
+    "chrome_app_startup_parameters.h",
+    "chrome_app_startup_parameters.mm",
     "client_registration.h",
     "client_registration.mm",
     "content_suggestions_scheduler_notifications.h",
@@ -54,9 +56,12 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser:browser_internal",
     "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/first_run",
     "//ios/chrome/browser/ntp_snippets",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web:web_internal",
+    "//ios/chrome/common",
+    "//ios/chrome/common/app_group",
     "//ios/net",
     "//ios/public/provider/chrome/browser",
     "//ios/web",
@@ -64,3 +69,19 @@
     ios_provider_target,
   ]
 }
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "chrome_app_startup_parameters_unittest.mm",
+  ]
+  deps = [
+    ":startup",
+    "//base",
+    "//ios/chrome/browser",
+    "//ios/chrome/common/app_group",
+    "//testing/gtest",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/app/startup/chrome_app_startup_parameters.h b/ios/chrome/app/startup/chrome_app_startup_parameters.h
new file mode 100644
index 0000000..f7216ff
--- /dev/null
+++ b/ios/chrome/app/startup/chrome_app_startup_parameters.h
@@ -0,0 +1,108 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_APP_STARTUP_CHROME_APP_STARTUP_PARAMETERS_H_
+#define IOS_CHROME_APP_STARTUP_CHROME_APP_STARTUP_PARAMETERS_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/app_startup_parameters.h"
+#import "ios/chrome/browser/first_run/first_run_metrics.h"
+
+// Values of the UMA Startup.MobileSessionCallerApp histogram.
+enum MobileSessionCallerApp {
+  CALLER_APP_GOOGLE_SEARCH = 0,
+  CALLER_APP_GOOGLE_GMAIL,
+  CALLER_APP_GOOGLE_PLUS,
+  CALLER_APP_GOOGLE_DRIVE,
+  CALLER_APP_GOOGLE_EARTH,
+  CALLER_APP_GOOGLE_OTHER,
+  CALLER_APP_OTHER,
+  CALLER_APP_APPLE_MOBILESAFARI,
+  CALLER_APP_APPLE_OTHER,
+  CALLER_APP_GOOGLE_YOUTUBE,
+  CALLER_APP_GOOGLE_MAPS,
+  CALLER_APP_NOT_AVAILABLE,  // Includes being launched from Smart App Banner.
+  CALLER_APP_GOOGLE_CHROME_TODAY_EXTENSION,
+  MOBILE_SESSION_CALLER_APP_COUNT,
+};
+
+@interface ChromeAppStartupParameters : AppStartupParameters
+
+- (instancetype)initWithExternalURL:(const GURL&)externalURL NS_UNAVAILABLE;
+
+- (instancetype)initWithExternalURL:(const GURL&)externalURL
+                  declaredSourceApp:(NSString*)declaredSourceApp
+                    secureSourceApp:(NSString*)secureSourceApp
+                        completeURL:(NSURL*)completeURL
+    NS_DESIGNATED_INITIALIZER;
+
+// Returns a ChromeAppStartupParameters instance containing the URL to
+// open (|externalURL|). In case the URL is conforming to the x-callback-url
+// specification, additional information are stored in the returned value.
+//
+// The forms of the URLs we expect are:
+//
+// - protocol0://url/goes/here
+//   Here protocol0s opens the app. The string for the
+//   parsed URL is "url/goes/here" with protocol
+//   "http", that is, the string for the parsed URL is
+//   "http://url/goes/here"
+//
+// - protocol0s://url/goes/here
+//   Here protocol0s opens the app. The string for the
+//   parsed URL is "url/goes/here" with protocol
+//   "https", that is, the string for the parsed URL is
+//   "https://url/goes/here"
+//
+// - url/goes/here
+//   No protocol is given. The string for the parsed URL is
+//   "url/goes/here", with protocol defaulting to "http",
+//   that is, the string for the parsed URL is
+//   "http://url/goes/here"
+//
+// - file://url/goes/here
+//   Here the received URL is a file. This is used in cases where the app
+//   receives a file from another app. The string for the parser URL is
+//   "chrome://external-file/url/goes/here"
+//
+// - x-<protocol>://x-callback-url/<action>?url=<url/goes/here>
+//   This forms is compliant with x-callback-url (x-callback-url.com).
+//   Currently the only action supported for external application is "open" and
+//   the only required parameter is |url| containing the url to open inclusive
+//   of protocol.
+//   For application members of the Chrome Application Group,
+//   "app-group-command" command can be used. In that case, the paramaters are
+//   sent via the shared NSUserDefault dictionary.
+//
+// Note the protocol isn't hardcoded so we accept anything. Moreover, in iOS 6
+// SmartAppBanners can send any URL to the app without even needing the app
+// to be registered for that protocol.
+// If the string for the parsed URL is malformed (according to RFC 2396),
+// returns nil.
++ (instancetype)newChromeAppStartupParametersWithURL:(NSURL*)url
+                               fromSourceApplication:(NSString*)appId;
+
+// Returns the MobileSessionCallerApp for the given bundle ID.
+- (MobileSessionCallerApp)callerApp;
+
+// Checks the parsed url and heuristically determine if it implies that the
+// current openURL: delegate call is the result of a user click on Smart App
+// Banner.
+- (first_run::ExternalLaunch)launchSource;
+
+@end
+
+@interface ChromeAppStartupParameters (Testing)
+
++ (instancetype)newAppStartupParametersForCommand:(NSString*)command
+                                  withExternalURL:(NSString*)externalURL
+                                        withIndex:(NSNumber*)index
+                                          withURL:(NSURL*)url
+                            fromSourceApplication:(NSString*)appId
+                      fromSecureSourceApplication:(NSString*)secureSourceApp;
+
+@end
+
+#endif  // IOS_CHROME_APP_STARTUP_CHROME_APP_STARTUP_PARAMETERS_H_
diff --git a/ios/chrome/app/startup/chrome_app_startup_parameters.mm b/ios/chrome/app/startup/chrome_app_startup_parameters.mm
new file mode 100644
index 0000000..371e5cc
--- /dev/null
+++ b/ios/chrome/app/startup/chrome_app_startup_parameters.mm
@@ -0,0 +1,397 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/app/startup/chrome_app_startup_parameters.h"
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/strings/sys_string_conversions.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/common/app_group/app_group_constants.h"
+#include "ios/chrome/common/x_callback_url.h"
+#import "net/base/mac/url_conversions.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+// Key of the UMA Startup.MobileSessionStartAction histogram.
+const char kUMAMobileSessionStartActionHistogram[] =
+    "Startup.MobileSessionStartAction";
+
+const char kApplicationGroupCommandDelay[] =
+    "Startup.ApplicationGroupCommandDelay";
+
+// URL Query String parameter to indicate that this openURL: request arrived
+// here due to a Smart App Banner presentation on a Google.com page.
+NSString* const kSmartAppBannerKey = @"safarisab";
+
+const CGFloat kAppGroupTriggersVoiceSearchTimeout = 15.0;
+
+// Values of the UMA Startup.MobileSessionStartAction histogram.
+enum MobileSessionStartAction {
+  START_ACTION_OPEN_HTTP = 0,
+  START_ACTION_OPEN_HTTPS,
+  START_ACTION_OPEN_FILE,
+  START_ACTION_XCALLBACK_OPEN,
+  START_ACTION_XCALLBACK_OTHER,
+  START_ACTION_OTHER,
+  START_ACTION_XCALLBACK_APPGROUP_COMMAND,
+  MOBILE_SESSION_START_ACTION_COUNT,
+};
+
+// Values of the UMA iOS.SearchExtension.Action histogram.
+enum SearchExtensionAction {
+  ACTION_NO_ACTION,
+  ACTION_NEW_SEARCH,
+  ACTION_NEW_INCOGNITO_SEARCH,
+  ACTION_NEW_VOICE_SEARCH,
+  ACTION_NEW_QR_CODE_SEARCH,
+  ACTION_OPEN_URL,
+  SEARCH_EXTENSION_ACTION_COUNT,
+};
+
+}  // namespace
+
+@implementation ChromeAppStartupParameters {
+  NSString* _secureSourceApp;
+  NSString* _declaredSourceApp;
+  NSURL* _completeURL;
+}
+
+- (instancetype)initWithExternalURL:(const GURL&)externalURL
+                  declaredSourceApp:(NSString*)declaredSourceApp
+                    secureSourceApp:(NSString*)secureSourceApp
+                        completeURL:(NSURL*)completeURL {
+  self = [super initWithExternalURL:externalURL];
+  if (self) {
+    _declaredSourceApp = [declaredSourceApp copy];
+    _secureSourceApp = [secureSourceApp copy];
+    _completeURL = completeURL;
+  }
+  return self;
+}
+
++ (instancetype)newChromeAppStartupParametersWithURL:(NSURL*)completeURL
+                               fromSourceApplication:(NSString*)appId {
+  GURL gurl = net::GURLWithNSURL(completeURL);
+
+  if (!gurl.is_valid() || gurl.scheme().length() == 0)
+    return nil;
+
+  // TODO(crbug.com/228098): Temporary fix.
+  if (IsXCallbackURL(gurl)) {
+    NSString* action = [completeURL path];
+    // Currently only "open" and "extension-command" are supported.
+    // Other actions are being considered (see b/6914153).
+    if ([action
+            isEqualToString:
+                [NSString
+                    stringWithFormat:
+                        @"/%s", app_group::kChromeAppGroupXCallbackCommand]]) {
+      UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+                                START_ACTION_XCALLBACK_APPGROUP_COMMAND,
+                                MOBILE_SESSION_START_ACTION_COUNT);
+      return [ChromeAppStartupParameters
+          newExtensionCommandAppStartupParametersFromWithURL:completeURL
+                                       fromSourceApplication:appId];
+    }
+
+    if (![action isEqualToString:@"/open"]) {
+      UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+                                START_ACTION_XCALLBACK_OTHER,
+                                MOBILE_SESSION_START_ACTION_COUNT);
+      return nil;
+    }
+
+    UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+                              START_ACTION_XCALLBACK_OPEN,
+                              MOBILE_SESSION_START_ACTION_COUNT);
+
+    std::map<std::string, std::string> parameters =
+        ExtractQueryParametersFromXCallbackURL(gurl);
+    GURL url = GURL(parameters["url"]);
+    if (!url.is_valid() ||
+        (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme))) {
+      return nil;
+    }
+
+    return [[ChromeAppStartupParameters alloc] initWithExternalURL:url
+                                                 declaredSourceApp:appId
+                                                   secureSourceApp:nil
+                                                       completeURL:completeURL];
+
+  } else if (gurl.SchemeIsFile()) {
+    UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram,
+                              START_ACTION_OPEN_FILE,
+                              MOBILE_SESSION_START_ACTION_COUNT);
+    // |url| is the path to a file received from another application.
+    GURL::Replacements replacements;
+    const std::string host(kChromeUIExternalFileHost);
+    std::string filename = gurl.ExtractFileName();
+    replacements.SetPathStr(filename);
+    replacements.SetSchemeStr(kChromeUIScheme);
+    replacements.SetHostStr(host);
+    GURL externalURL = gurl.ReplaceComponents(replacements);
+    if (!externalURL.is_valid())
+      return nil;
+    return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
+                                                 declaredSourceApp:appId
+                                                   secureSourceApp:nil
+                                                       completeURL:completeURL];
+  } else {
+    // Replace the scheme with https or http depending on whether the input
+    // |url| scheme ends with an 's'.
+    BOOL useHttps = gurl.scheme()[gurl.scheme().length() - 1] == 's';
+    MobileSessionStartAction action =
+        useHttps ? START_ACTION_OPEN_HTTPS : START_ACTION_OPEN_HTTP;
+    UMA_HISTOGRAM_ENUMERATION(kUMAMobileSessionStartActionHistogram, action,
+                              MOBILE_SESSION_START_ACTION_COUNT);
+    GURL::Replacements replace_scheme;
+    if (useHttps)
+      replace_scheme.SetSchemeStr(url::kHttpsScheme);
+    else
+      replace_scheme.SetSchemeStr(url::kHttpScheme);
+    GURL externalURL = gurl.ReplaceComponents(replace_scheme);
+    if (!externalURL.is_valid())
+      return nil;
+    return [[ChromeAppStartupParameters alloc] initWithExternalURL:externalURL
+                                                 declaredSourceApp:appId
+                                                   secureSourceApp:nil
+                                                       completeURL:completeURL];
+  }
+}
+
++ (instancetype)newExtensionCommandAppStartupParametersFromWithURL:(NSURL*)url
+                                             fromSourceApplication:
+                                                 (NSString*)appId {
+  NSString* appGroup = app_group::ApplicationGroup();
+  NSUserDefaults* sharedDefaults =
+      [[NSUserDefaults alloc] initWithSuiteName:appGroup];
+
+  NSString* commandDictionaryPreference =
+      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference);
+  NSDictionary* commandDictionary = base::mac::ObjCCast<NSDictionary>(
+      [sharedDefaults objectForKey:commandDictionaryPreference]);
+
+  [sharedDefaults removeObjectForKey:commandDictionaryPreference];
+
+  // |sharedDefaults| is used for communication between apps. Synchronize to
+  // avoid synchronization issues (like removing the next order).
+  [sharedDefaults synchronize];
+
+  if (!commandDictionary) {
+    return nil;
+  }
+
+  NSString* commandCallerPreference =
+      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandAppPreference);
+  NSString* commandCaller = base::mac::ObjCCast<NSString>(
+      [commandDictionary objectForKey:commandCallerPreference]);
+
+  NSString* commandPreference = base::SysUTF8ToNSString(
+      app_group::kChromeAppGroupCommandCommandPreference);
+  NSString* command = base::mac::ObjCCast<NSString>(
+      [commandDictionary objectForKey:commandPreference]);
+
+  NSString* commandTimePreference =
+      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandTimePreference);
+  id commandTime = base::mac::ObjCCast<NSDate>(
+      [commandDictionary objectForKey:commandTimePreference]);
+
+  NSString* commandURLPreference =
+      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandURLPreference);
+  NSString* externalURL = base::mac::ObjCCast<NSString>(
+      [commandDictionary objectForKey:commandURLPreference]);
+
+  NSString* commandIndexPreference =
+      base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandIndexPreference);
+  NSNumber* index = base::mac::ObjCCast<NSNumber>(
+      [commandDictionary objectForKey:commandIndexPreference]);
+
+  if (!commandCaller || !command || !commandTimePreference) {
+    return nil;
+  }
+
+  // Check the time of the last request to avoid app from intercepting old
+  // open url request and replay it later.
+  NSTimeInterval delay = [[NSDate date] timeIntervalSinceDate:commandTime];
+  UMA_HISTOGRAM_COUNTS_100(kApplicationGroupCommandDelay, delay);
+  if (delay > kAppGroupTriggersVoiceSearchTimeout)
+    return nil;
+  return [ChromeAppStartupParameters
+      newAppStartupParametersForCommand:command
+                        withExternalURL:externalURL
+                              withIndex:index
+                                withURL:url
+
+                  fromSourceApplication:appId
+            fromSecureSourceApplication:commandCaller];
+}
+
++ (instancetype)newAppStartupParametersForCommand:(NSString*)command
+                                  withExternalURL:(NSString*)externalURL
+                                        withIndex:(NSNumber*)index
+                                          withURL:(NSURL*)url
+                            fromSourceApplication:(NSString*)appId
+                      fromSecureSourceApplication:(NSString*)secureSourceApp {
+  SearchExtensionAction action = ACTION_NO_ACTION;
+  ChromeAppStartupParameters* params = nil;
+
+  if ([command
+          isEqualToString:base::SysUTF8ToNSString(
+                              app_group::kChromeAppGroupVoiceSearchCommand)]) {
+    params = [[ChromeAppStartupParameters alloc]
+        initWithExternalURL:GURL(kChromeUINewTabURL)
+          declaredSourceApp:appId
+            secureSourceApp:secureSourceApp
+                completeURL:url];
+    [params setPostOpeningAction:START_VOICE_SEARCH];
+    action = ACTION_NEW_VOICE_SEARCH;
+  }
+
+  if ([command isEqualToString:base::SysUTF8ToNSString(
+                                   app_group::kChromeAppGroupNewTabCommand)]) {
+    params = [[ChromeAppStartupParameters alloc]
+        initWithExternalURL:GURL(kChromeUINewTabURL)
+          declaredSourceApp:appId
+            secureSourceApp:secureSourceApp
+                completeURL:url];
+    action = ACTION_NO_ACTION;
+  }
+
+  if ([command
+          isEqualToString:base::SysUTF8ToNSString(
+                              app_group::kChromeAppGroupFocusOmniboxCommand)]) {
+    params = [[ChromeAppStartupParameters alloc]
+        initWithExternalURL:GURL(kChromeUINewTabURL)
+          declaredSourceApp:appId
+            secureSourceApp:secureSourceApp
+                completeURL:url];
+    [params setPostOpeningAction:FOCUS_OMNIBOX];
+    action = ACTION_NEW_SEARCH;
+  }
+
+  if ([command isEqualToString:base::SysUTF8ToNSString(
+                                   app_group::kChromeAppGroupOpenURLCommand)]) {
+    if (!externalURL || ![externalURL isKindOfClass:[NSString class]])
+      return nil;
+    GURL externalGURL(base::SysNSStringToUTF8(externalURL));
+    if (!externalGURL.is_valid() || !externalGURL.SchemeIsHTTPOrHTTPS())
+      return nil;
+    params =
+        [[ChromeAppStartupParameters alloc] initWithExternalURL:externalGURL
+                                              declaredSourceApp:appId
+                                                secureSourceApp:secureSourceApp
+                                                    completeURL:url];
+    action = ACTION_OPEN_URL;
+  }
+
+  if ([command
+          isEqualToString:base::SysUTF8ToNSString(
+                              app_group::kChromeAppGroupQRScannerCommand)]) {
+    params = [[ChromeAppStartupParameters alloc]
+        initWithExternalURL:GURL(kChromeUINewTabURL)
+          declaredSourceApp:appId
+            secureSourceApp:secureSourceApp
+                completeURL:url];
+    [params setPostOpeningAction:START_QR_CODE_SCANNER];
+    action = ACTION_NEW_QR_CODE_SEARCH;
+  }
+
+  if ([command isEqualToString:
+                   base::SysUTF8ToNSString(
+                       app_group::kChromeAppGroupIncognitoSearchCommand)]) {
+    params = [[ChromeAppStartupParameters alloc]
+        initWithExternalURL:GURL(kChromeUINewTabURL)
+          declaredSourceApp:appId
+            secureSourceApp:secureSourceApp
+                completeURL:url];
+    [params setLaunchInIncognito:YES];
+    [params setPostOpeningAction:FOCUS_OMNIBOX];
+    action = ACTION_NEW_INCOGNITO_SEARCH;
+  }
+
+  if ([secureSourceApp
+          isEqualToString:app_group::kOpenCommandSourceSearchExtension]) {
+    UMA_HISTOGRAM_ENUMERATION("IOS.SearchExtension.Action", action,
+                              SEARCH_EXTENSION_ACTION_COUNT);
+  }
+  if ([secureSourceApp
+          isEqualToString:app_group::kOpenCommandSourceContentExtension] &&
+      index) {
+    UMA_HISTOGRAM_COUNTS_100("IOS.ContentExtension.Index",
+                             [index integerValue]);
+  }
+  return params;
+}
+
+- (MobileSessionCallerApp)callerApp {
+  if ([_secureSourceApp
+          isEqualToString:app_group::kOpenCommandSourceTodayExtension])
+    return CALLER_APP_GOOGLE_CHROME_TODAY_EXTENSION;
+
+  if (![_declaredSourceApp length])
+    return CALLER_APP_NOT_AVAILABLE;
+  if ([_declaredSourceApp isEqualToString:@"com.google.GoogleMobile"])
+    return CALLER_APP_GOOGLE_SEARCH;
+  if ([_declaredSourceApp isEqualToString:@"com.google.Gmail"])
+    return CALLER_APP_GOOGLE_GMAIL;
+  if ([_declaredSourceApp isEqualToString:@"com.google.GooglePlus"])
+    return CALLER_APP_GOOGLE_PLUS;
+  if ([_declaredSourceApp isEqualToString:@"com.google.Drive"])
+    return CALLER_APP_GOOGLE_DRIVE;
+  if ([_declaredSourceApp isEqualToString:@"com.google.b612"])
+    return CALLER_APP_GOOGLE_EARTH;
+  if ([_declaredSourceApp isEqualToString:@"com.google.ios.youtube"])
+    return CALLER_APP_GOOGLE_YOUTUBE;
+  if ([_declaredSourceApp isEqualToString:@"com.google.Maps"])
+    return CALLER_APP_GOOGLE_MAPS;
+  if ([_declaredSourceApp hasPrefix:@"com.google."])
+    return CALLER_APP_GOOGLE_OTHER;
+  if ([_declaredSourceApp isEqualToString:@"com.apple.mobilesafari"])
+    return CALLER_APP_APPLE_MOBILESAFARI;
+  if ([_declaredSourceApp hasPrefix:@"com.apple."])
+    return CALLER_APP_APPLE_OTHER;
+
+  return CALLER_APP_OTHER;
+}
+
+- (first_run::ExternalLaunch)launchSource {
+  if ([self callerApp] != CALLER_APP_APPLE_MOBILESAFARI) {
+    return first_run::LAUNCH_BY_OTHERS;
+  }
+
+  NSString* query = [_completeURL query];
+  // Takes care of degenerated case of no QUERY_STRING.
+  if (![query length])
+    return first_run::LAUNCH_BY_MOBILESAFARI;
+  // Look for |kSmartAppBannerKey| anywhere within the query string.
+  NSRange found = [query rangeOfString:kSmartAppBannerKey];
+  if (found.location == NSNotFound)
+    return first_run::LAUNCH_BY_MOBILESAFARI;
+  // |kSmartAppBannerKey| can be at the beginning or end of the query
+  // string and may also be optionally followed by a equal sign and a value.
+  // For now, just look for the presence of the key and ignore the value.
+  if (found.location + found.length < [query length]) {
+    // There are characters following the found location.
+    unichar charAfter =
+        [query characterAtIndex:(found.location + found.length)];
+    if (charAfter != '&' && charAfter != '=')
+      return first_run::LAUNCH_BY_MOBILESAFARI;
+  }
+  if (found.location > 0) {
+    unichar charBefore = [query characterAtIndex:(found.location - 1)];
+    if (charBefore != '&')
+      return first_run::LAUNCH_BY_MOBILESAFARI;
+  }
+  return first_run::LAUNCH_BY_SMARTAPPBANNER;
+}
+
+@end
diff --git a/ios/chrome/app/startup/chrome_app_startup_parameters_unittest.mm b/ios/chrome/app/startup/chrome_app_startup_parameters_unittest.mm
new file mode 100644
index 0000000..939c2f27
--- /dev/null
+++ b/ios/chrome/app/startup/chrome_app_startup_parameters_unittest.mm
@@ -0,0 +1,278 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/app/startup/chrome_app_startup_parameters.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/strings/stringprintf.h"
+#include "ios/chrome/browser/app_startup_parameters.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/common/app_group/app_group_constants.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+void CheckLaunchSourceForURL(first_run::ExternalLaunch expectedSource,
+                             NSString* urlString) {
+  NSURL* url = [NSURL URLWithString:urlString];
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newChromeAppStartupParametersWithURL:url
+                     fromSourceApplication:@"com.apple.mobilesafari"];
+  EXPECT_EQ(expectedSource, [params launchSource]);
+}
+
+typedef PlatformTest AppStartupParametersTest;
+TEST_F(PlatformTest, ParseURLWithEmptyURL) {
+  NSURL* url = [NSURL URLWithString:@""];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+
+  EXPECT_FALSE(params);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithOneProtocol) {
+  NSURL* url = [NSURL URLWithString:@"protocol://www.google.com"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+  // Here "protocol" opens the app and no protocol is given for the parsed URL,
+  // which defaults to be "http".
+  EXPECT_EQ("http://www.google.com/", [params externalURL].spec());
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithEmptyParsedURL) {
+  // Test chromium://
+  NSURL* url = [NSURL URLWithString:@"chromium://"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+
+  EXPECT_FALSE(params);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithParsedURLDefaultToHttp) {
+  NSURL* url = [NSURL URLWithString:@"chromium://www.google.com"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+
+  EXPECT_EQ("http://www.google.com/", [params externalURL].spec());
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithInvalidParsedURL) {
+  NSURL* url = [NSURL URLWithString:@"http:google.com:foo"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+
+  EXPECT_FALSE(params);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithHttpsParsedURL) {
+  NSURL* url = [NSURL URLWithString:@"chromiums://www.google.com"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+
+  EXPECT_EQ("https://www.google.com/", [params externalURL].spec());
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithXCallbackURL) {
+  NSURL* url = [NSURL URLWithString:
+                          @"chromium-x-callback://x-callback-url/open?"
+                           "url=https://www.google.com"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+  EXPECT_EQ("https://www.google.com/", [params externalURL].spec());
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithXCallbackURLAndExtraParams) {
+  NSURL* url = [NSURL URLWithString:
+                          @"chromium-x-callback://x-callback-url/open?"
+                           "url=https://www.google.com&"
+                           "x-success=http://success"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+  EXPECT_EQ("https://www.google.com/", [params externalURL].spec());
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithMalformedXCallbackURL) {
+  NSURL* url =
+      [NSURL URLWithString:
+                 @"chromium-x-callback://x-callback-url/open?url=foobar&"
+                  "x-source=myapp&x-success=http://success"];
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newChromeAppStartupParametersWithURL:url
+                     fromSourceApplication:@"com.myapp"];
+  EXPECT_FALSE(params);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithJavascriptURLInXCallbackURL) {
+  NSURL* url = [NSURL
+      URLWithString:
+          @"chromium-x-callback://x-callback-url/open?url="
+           "javascript:window.open()&x-source=myapp&x-success=http://success"];
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newChromeAppStartupParametersWithURL:url
+                     fromSourceApplication:@"com.myapp"];
+  EXPECT_FALSE(params);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithChromeURLInXCallbackURL) {
+  NSURL* url = [NSURL URLWithString:
+                          @"chromium-x-callback://x-callback-url/open?url="
+                           "chrome:passwords"];
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newChromeAppStartupParametersWithURL:url
+                     fromSourceApplication:@"com.myapp"];
+  EXPECT_FALSE(params);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithFileParsedURL) {
+  NSURL* url = [NSURL URLWithString:@"file://localhost/path/to/file.pdf"];
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newChromeAppStartupParametersWithURL:url
+                                                 fromSourceApplication:nil];
+
+  std::string expectedUrlString = base::StringPrintf(
+      "%s://%s/file.pdf", kChromeUIScheme, kChromeUIExternalFileHost);
+
+  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithAppGroupVoiceSearch) {
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newAppStartupParametersForCommand:@"voicesearch"
+                        withExternalURL:nil
+                              withIndex:0
+                                withURL:nil
+                  fromSourceApplication:nil
+            fromSecureSourceApplication:nil];
+
+  std::string expectedUrlString =
+      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
+
+  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
+  EXPECT_EQ([params postOpeningAction], START_VOICE_SEARCH);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithAppGroupQRCode) {
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newAppStartupParametersForCommand:@"qrscanner"
+                                                    withExternalURL:nil
+                                                          withIndex:0
+                                                            withURL:nil
+                                              fromSourceApplication:nil
+                                        fromSecureSourceApplication:nil];
+
+  std::string expectedUrlString =
+      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
+
+  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
+  EXPECT_EQ([params postOpeningAction], START_QR_CODE_SCANNER);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithAppGroupFocusOmbnibox) {
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newAppStartupParametersForCommand:@"focusomnibox"
+                        withExternalURL:nil
+                              withIndex:0
+                                withURL:nil
+                  fromSourceApplication:nil
+            fromSecureSourceApplication:nil];
+
+  std::string expectedUrlString =
+      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
+
+  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
+  EXPECT_EQ([params postOpeningAction], FOCUS_OMNIBOX);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithAppGroupNewTab) {
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newAppStartupParametersForCommand:@"newtab"
+                                                    withExternalURL:nil
+                                                          withIndex:0
+                                                            withURL:nil
+                                              fromSourceApplication:nil
+                                        fromSecureSourceApplication:nil];
+  std::string expectedUrlString =
+      base::StringPrintf("%s://%s/", kChromeUIScheme, kChromeUINewTabHost);
+
+  EXPECT_EQ(expectedUrlString, [params externalURL].spec());
+  EXPECT_EQ([params postOpeningAction], NO_ACTION);
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithAppGroupOpenURL) {
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newAppStartupParametersForCommand:@"openurl"
+                        withExternalURL:@"http://foo/bar"
+
+                              withIndex:0
+                                withURL:nil
+                  fromSourceApplication:nil
+            fromSecureSourceApplication:nil];
+
+  EXPECT_EQ("http://foo/bar", [params externalURL].spec());
+}
+
+TEST_F(AppStartupParametersTest, ParseURLWithAppGroupGarbage) {
+  ChromeAppStartupParameters* params =
+      [ChromeAppStartupParameters newAppStartupParametersForCommand:@"garbage"
+                                                    withExternalURL:nil
+                                                          withIndex:0
+                                                            withURL:nil
+                                              fromSourceApplication:nil
+                                        fromSecureSourceApplication:nil];
+  EXPECT_FALSE(params);
+}
+
+TEST_F(AppStartupParametersTest, FirstRunExternalLaunchSource) {
+  // Key at the beginning of query string.
+  CheckLaunchSourceForURL(
+      first_run::LAUNCH_BY_SMARTAPPBANNER,
+      @"http://www.google.com/search?safarisab=1&query=pony");
+  // Key at the end of query string.
+  CheckLaunchSourceForURL(
+      first_run::LAUNCH_BY_SMARTAPPBANNER,
+      @"http://www.google.com/search?query=pony&safarisab=1");
+  // Key in the middle of query string.
+  CheckLaunchSourceForURL(
+      first_run::LAUNCH_BY_SMARTAPPBANNER,
+      @"http://www.google.com/search?query=pony&safarisab=1&hl=en");
+  // Key without '=' sign at the beginning, end, and middle of query string.
+  CheckLaunchSourceForURL(first_run::LAUNCH_BY_SMARTAPPBANNER,
+                          @"http://www.google.com/search?safarisab&query=pony");
+  CheckLaunchSourceForURL(first_run::LAUNCH_BY_SMARTAPPBANNER,
+                          @"http://www.google.com/search?query=pony&safarisab");
+  CheckLaunchSourceForURL(
+      first_run::LAUNCH_BY_SMARTAPPBANNER,
+      @"http://www.google.com/search?query=pony&safarisab&hl=en");
+  // No query string in URL.
+  CheckLaunchSourceForURL(first_run::LAUNCH_BY_MOBILESAFARI,
+                          @"http://www.google.com/");
+  CheckLaunchSourceForURL(first_run::LAUNCH_BY_MOBILESAFARI,
+                          @"http://www.google.com/safarisab/foo/bar");
+  // Key not present in query string.
+  CheckLaunchSourceForURL(first_run::LAUNCH_BY_MOBILESAFARI,
+                          @"http://www.google.com/search?query=pony");
+  // Key is a substring of some other string.
+  CheckLaunchSourceForURL(
+      first_run::LAUNCH_BY_MOBILESAFARI,
+      @"http://www.google.com/search?query=pony&safarisabcdefg=1");
+  CheckLaunchSourceForURL(
+      first_run::LAUNCH_BY_MOBILESAFARI,
+      @"http://www.google.com/search?query=pony&notsafarisab=1&abc=def");
+}
+
+}  // namespace
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 8c994d5..394d22bf 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1600,6 +1600,21 @@
       <message name="IDS_IOS_BOOKMARK_CONTEXT_BAR_MORE" desc="Text on the bookmarks context bar to show more context menu">
         More...
       </message>
+      <message name="IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN" desc="Text on the bookmarks context menu to open all selected bookmarks">
+        Open All
+      </message>
+      <message name="IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN_INCOGNITO" desc="Text on the bookmarks context menu to open selected bookmark in incognito">
+        Open in incognito
+      </message>
+      <message name="IDS_IOS_BOOKMARK_CONTEXT_MENU_MOVE" desc="Text on the bookmarks context menu to move selected bookmark">
+        Move
+      </message>
+      <message name="IDS_IOS_BOOKMARK_CONTEXT_MENU_EDIT" desc="Text on the bookmarks context menu to edit selected bookmark">
+        Edit Bookmark
+      </message>
+      <message name="IDS_IOS_BOOKMARK_CONTEXT_MENU_COPY" desc="Text on the bookmarks context menu to copy selected bookmark URL">
+        Copy URL
+      </message>
    </messages>
   </release>
 </grit>
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 2c5a052..7ed4da5 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -101,7 +101,6 @@
   "+ios/public/provider/chrome",
   "+ios/public/provider/components",
   "+ios/shared/chrome/browser",
-  "+ios/web/public",
   "+libxml/xmlwriter.h",
   "+net",
   "+rlz/features",
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index 8a850ed..b274d00b 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -77,6 +77,8 @@
     "autofill_agent.mm",
     "autofill_controller.h",
     "autofill_controller.mm",
+    "autofill_tab_helper.h",
+    "autofill_tab_helper.mm",
   ]
   deps = [
     ":autofill",
diff --git a/ios/chrome/browser/autofill/autofill_tab_helper.h b/ios/chrome/browser/autofill/autofill_tab_helper.h
new file mode 100644
index 0000000..3681fb8
--- /dev/null
+++ b/ios/chrome/browser/autofill/autofill_tab_helper.h
@@ -0,0 +1,48 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_TAB_HELPER_H_
+
+#include "base/macros.h"
+#import "ios/web/public/web_state/web_state_observer.h"
+#import "ios/web/public/web_state/web_state_user_data.h"
+
+@class AutofillController;
+@protocol FormSuggestionProvider;
+
+namespace password_manager {
+class PasswordGenerationManager;
+}
+
+// Class binding an AutofillController to a WebState.
+class AutofillTabHelper : public web::WebStateObserver,
+                          public web::WebStateUserData<AutofillTabHelper> {
+ public:
+  ~AutofillTabHelper() override;
+
+  // Create an AutofillTabHelper and attaches it to the given |web_state|.
+  static void CreateForWebState(
+      web::WebState* web_state,
+      password_manager::PasswordGenerationManager* password_generation_manager);
+
+  // Returns an object that can provide suggestions from the PasswordController.
+  // May return nil.
+  id<FormSuggestionProvider> GetSuggestionProvider();
+
+ private:
+  AutofillTabHelper(
+      web::WebState* web_state,
+      password_manager::PasswordGenerationManager* password_generation_manager);
+
+  // web::WebStateObserver implementation.
+  void WebStateDestroyed() override;
+
+  // The Objective-C autofill controller instance.
+  __strong AutofillController* controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillTabHelper);
+};
+
+#endif  // IOS_CHROME_BROWSER_AUTOFILL_AUTOFILL_TAB_HELPER_H_
diff --git a/ios/chrome/browser/autofill/autofill_tab_helper.mm b/ios/chrome/browser/autofill/autofill_tab_helper.mm
new file mode 100644
index 0000000..2fa9b57
--- /dev/null
+++ b/ios/chrome/browser/autofill/autofill_tab_helper.mm
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/autofill/autofill_tab_helper.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#import "ios/chrome/browser/autofill/autofill_controller.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+DEFINE_WEB_STATE_USER_DATA_KEY(AutofillTabHelper);
+
+AutofillTabHelper::~AutofillTabHelper() = default;
+
+// static
+void AutofillTabHelper::CreateForWebState(
+    web::WebState* web_state,
+    password_manager::PasswordGenerationManager* password_generation_manager) {
+  DCHECK(web_state);
+  DCHECK(!FromWebState(web_state));
+  web_state->SetUserData(UserDataKey(),
+                         base::WrapUnique(new AutofillTabHelper(
+                             web_state, password_generation_manager)));
+}
+
+id<FormSuggestionProvider> AutofillTabHelper::GetSuggestionProvider() {
+  return controller_.suggestionProvider;
+}
+
+AutofillTabHelper::AutofillTabHelper(
+    web::WebState* web_state,
+    password_manager::PasswordGenerationManager* password_generation_manager)
+    : web::WebStateObserver(web_state),
+      controller_([[AutofillController alloc]
+               initWithBrowserState:ios::ChromeBrowserState::FromBrowserState(
+                                        web_state->GetBrowserState())
+          passwordGenerationManager:password_generation_manager
+                           webState:web_state]) {
+  DCHECK(web::WebStateObserver::web_state());
+}
+
+void AutofillTabHelper::WebStateDestroyed() {
+  [controller_ detachFromWebState];
+  controller_ = nil;
+}
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state.mm b/ios/chrome/browser/browser_state/chrome_browser_state.mm
index 232e435..c27e3e3 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state.mm
@@ -4,6 +4,7 @@
 
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/files/file_path.h"
@@ -23,11 +24,19 @@
 #endif
 
 namespace ios {
+namespace {
+// All ChromeBrowserState will store a dummy base::SupportsUserData::Data
+// object with this key. It can be used to check that a web::BrowserState
+// is effectively a ChromeBrowserState when converting.
+const char kBrowserStateIsChromeBrowserState[] = "IsChromeBrowserState";
+}
 
 ChromeBrowserState::ChromeBrowserState(
     scoped_refptr<base::SequencedTaskRunner> io_task_runner)
     : io_task_runner_(std::move(io_task_runner)) {
   DCHECK(io_task_runner_);
+  SetUserData(kBrowserStateIsChromeBrowserState,
+              std::make_unique<base::SupportsUserData::Data>());
 }
 
 ChromeBrowserState::~ChromeBrowserState() {}
@@ -35,7 +44,13 @@
 // static
 ChromeBrowserState* ChromeBrowserState::FromBrowserState(
     web::BrowserState* browser_state) {
-  // This is safe; this is the only implementation of BrowserState.
+  if (!browser_state)
+    return nullptr;
+
+  // Check that the BrowserState is a ChromeBrowserState. It should always
+  // be true in production and during tests as the only BrowserState that
+  // should be used in ios/chrome inherits from ChromeBrowserState.
+  DCHECK(browser_state->GetUserData(kBrowserStateIsChromeBrowserState));
   return static_cast<ChromeBrowserState*>(browser_state);
 }
 
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index 8e998f4..4cd33ee 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -68,8 +68,11 @@
     "//base",
     "//base/test:test_support",
     "//components/browsing_data/core",
+    "//components/pref_registry",
     "//components/prefs",
     "//components/prefs:test_support",
+    "//components/sync_preferences",
+    "//components/sync_preferences:test_support",
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/web",
     "//ios/web/public/test",
diff --git a/ios/chrome/browser/browsing_data/cache_counter_unittest.cc b/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
index f6c41f8..f711bfa 100644
--- a/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
+++ b/ios/chrome/browser/browsing_data/cache_counter_unittest.cc
@@ -10,15 +10,18 @@
 
 #include "ios/chrome/browser/browsing_data/cache_counter.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/browsing_data/core/browsing_data_utils.h"
 #include "components/browsing_data/core/pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/testing_pref_service.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
+#include "components/sync_preferences/pref_service_mock_factory.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "ios/web/public/web_thread.h"
 #include "net/disk_cache/disk_cache.h"
@@ -27,26 +30,38 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
 
 namespace {
 
-class CacheCounterTest : public testing::Test {
+class CacheCounterTest : public PlatformTest {
  public:
   CacheCounterTest() {
-    prefs_.registry()->RegisterIntegerPref(
-        browsing_data::prefs::kDeleteTimePeriod,
-        static_cast<int>(browsing_data::TimePeriod::ALL_TIME));
-    prefs_.registry()->RegisterBooleanPref(browsing_data::prefs::kDeleteCache,
-                                           true);
+    TestChromeBrowserState::Builder builder;
+    builder.SetPrefService(CreatePrefService());
+    browser_state_ = builder.Build();
 
-    context_getter_ = browser_state_.GetRequestContext();
+    context_getter_ = browser_state_->GetRequestContext();
   }
 
   ~CacheCounterTest() override {}
 
-  web::TestBrowserState* browser_state() { return &browser_state_; }
+  ios::ChromeBrowserState* browser_state() { return browser_state_.get(); }
 
-  PrefService* prefs() { return &prefs_; }
+  PrefService* prefs() { return browser_state_->GetPrefs(); }
+
+  std::unique_ptr<sync_preferences::PrefServiceSyncable> CreatePrefService() {
+    sync_preferences::PrefServiceMockFactory factory;
+    scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
+        new user_prefs::PrefRegistrySyncable);
+    std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs =
+        factory.CreateSyncable(registry.get());
+    registry->RegisterIntegerPref(
+        browsing_data::prefs::kDeleteTimePeriod,
+        static_cast<int>(browsing_data::TimePeriod::ALL_TIME));
+    registry->RegisterBooleanPref(browsing_data::prefs::kDeleteCache, true);
+    return prefs;
+  }
 
   void SetCacheDeletionPref(bool value) {
     prefs()->SetBoolean(browsing_data::prefs::kDeleteCache, value);
@@ -218,6 +233,7 @@
 
   web::TestWebThreadBundle bundle_;
   std::unique_ptr<base::RunLoop> run_loop_;
+  std::unique_ptr<ios::ChromeBrowserState> browser_state_;
 
   CacheOperation current_operation_;
   CacheEntryCreationStep next_step_;
@@ -226,11 +242,8 @@
   disk_cache::Backend* backend_;
   disk_cache::Entry* entry_;
 
-  bool finished_;
+  bool finished_ = false;
   browsing_data::BrowsingDataCounter::ResultInt result_;
-
-  web::TestBrowserState browser_state_;
-  TestingPrefServiceSimple prefs_;
 };
 
 // Tests that for the empty cache, the result is zero.
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.h b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.h
index 688e31e..2f65e5de 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.h
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_coordinator.h
@@ -14,7 +14,6 @@
 
 @protocol ApplicationCommands;
 @protocol BrowserCommands;
-@protocol ChromeExecuteCommand;
 @class ContentSuggestionsHeaderViewController;
 @protocol OmniboxFocuser;
 @protocol UrlLoader;
@@ -32,7 +31,6 @@
 @property(nonatomic, assign) WebStateList* webStateList;
 @property(nonatomic, weak) id<ApplicationCommands,
                               BrowserCommands,
-                              ChromeExecuteCommand,
                               OmniboxFocuser,
                               UrlLoader>
     dispatcher;
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/content_suggestions/content_suggestions_header_view_controller.mm
index ba05298..87793baf 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_header_view_controller.mm
@@ -8,7 +8,6 @@
 #include "base/mac/foundation_util.h"
 #include "base/metrics/user_metrics.h"
 #include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index e3f0742b..8ee80da1 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -25,6 +25,8 @@
     "ios_chrome_save_password_infobar_delegate.mm",
     "ios_chrome_update_password_infobar_delegate.h",
     "ios_chrome_update_password_infobar_delegate.mm",
+    "js_credential_manager.h",
+    "js_credential_manager.mm",
     "js_password_manager.h",
     "js_password_manager.mm",
     "password_controller.h",
@@ -113,6 +115,7 @@
   sources = [
     "credential_manager_unittest.mm",
     "credential_manager_util_unittest.cc",
+    "js_credential_manager_unittest.mm",
     "password_controller_js_unittest.mm",
     "password_controller_off_the_record_unittest.mm",
     "password_controller_unittest.mm",
diff --git a/ios/chrome/browser/passwords/credential_manager.h b/ios/chrome/browser/passwords/credential_manager.h
index ea64084..3b6c288 100644
--- a/ios/chrome/browser/passwords/credential_manager.h
+++ b/ios/chrome/browser/passwords/credential_manager.h
@@ -17,7 +17,7 @@
 // 1. A command is sent from JavaScript to the browser.
 // 2. HandleScriptCommand is called, it parses the message and constructs a
 //     OnceCallback to be passed as parameter to proper CredentialManagerImpl
-//     method. |requestId| field from received JS message is bound to
+//     method. |promiseId| field from received JS message is bound to
 //     constructed OnceCallback.
 // 3. CredentialManagerImpl method is invoked, performs some logic with
 //     PasswordStore, calls passed OnceCallback with result.
@@ -37,13 +37,13 @@
 
   // Passed as callback to CredentialManagerImpl::Get.
   void SendGetResponse(
-      int request_id,
+      int promise_id,
       password_manager::CredentialManagerError error,
       const base::Optional<password_manager::CredentialInfo>& info);
   // Passed as callback to CredentialManagerImpl::PreventSilentAccess.
-  void SendPreventSilentAccessResponse(int request_id);
+  void SendPreventSilentAccessResponse(int promise_id);
   // Passed as callback to CredentialManagerImpl::Store.
-  void SendStoreResponse(int request_id);
+  void SendStoreResponse(int promise_id);
 
   password_manager::CredentialManagerImpl impl_;
 
diff --git a/ios/chrome/browser/passwords/credential_manager.mm b/ios/chrome/browser/passwords/credential_manager.mm
index d0acc31..3afea52 100644
--- a/ios/chrome/browser/passwords/credential_manager.mm
+++ b/ios/chrome/browser/passwords/credential_manager.mm
@@ -37,9 +37,9 @@
     return false;
   }
 
-  int request_id;
-  if (!json.GetInteger("requestId", &request_id)) {
-    DLOG(ERROR) << "RECEIVED BAD json - NO VALID 'requestId' FIELD";
+  int promise_id;
+  if (!json.GetInteger("promiseId", &promise_id)) {
+    DLOG(ERROR) << "RECEIVED BAD json - NO VALID 'promiseId' FIELD";
     return false;
   }
 
@@ -61,7 +61,7 @@
     }
     impl_.Get(mediation, include_passwords, federations,
               base::BindOnce(&CredentialManager::SendGetResponse,
-                             base::Unretained(this), request_id));
+                             base::Unretained(this), promise_id));
     return true;
   }
   if (command == "credentials.store") {
@@ -72,25 +72,25 @@
     }
     impl_.Store(credential,
                 base::BindOnce(&CredentialManager::SendStoreResponse,
-                               base::Unretained(this), request_id));
+                               base::Unretained(this), promise_id));
     return true;
   }
   if (command == "credentials.preventSilentAccess") {
     impl_.PreventSilentAccess(
         base::BindOnce(&CredentialManager::SendPreventSilentAccessResponse,
-                       base::Unretained(this), request_id));
+                       base::Unretained(this), promise_id));
     return true;
   }
   return false;
 }
 
 void CredentialManager::SendGetResponse(
-    int request_id,
+    int promise_id,
     CredentialManagerError error,
     const base::Optional<CredentialInfo>& info) {}
 
-void CredentialManager::SendPreventSilentAccessResponse(int request_id) {}
+void CredentialManager::SendPreventSilentAccessResponse(int promise_id) {}
 
-void CredentialManager::SendStoreResponse(int request_id) {}
+void CredentialManager::SendStoreResponse(int promise_id) {}
 
 }  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/js_credential_manager.h b/ios/chrome/browser/passwords/js_credential_manager.h
new file mode 100644
index 0000000..5d2db8b
--- /dev/null
+++ b/ios/chrome/browser/passwords/js_credential_manager.h
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_PASSWORDS_JS_CREDENTIAL_MANAGER_H_
+#define IOS_CHROME_BROWSER_PASSWORDS_JS_CREDENTIAL_MANAGER_H_
+
+#include "base/optional.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+
+namespace web {
+class WebState;
+}
+
+namespace credential_manager {
+
+// Resolves the Promise identified by |promise_id| with either Credential or
+// undefined. |promise_id| is unique number of a pending promise resolver stored
+// in |__gCrWeb.credentialManager|.
+void ResolvePromiseWithCredentialInfo(
+    web::WebState* web_state,
+    int promise_id,
+    const base::Optional<password_manager::CredentialInfo>& info);
+
+// Resolves the Promise identified by |promise_id| with undefined. |promise_id|
+// is unique number of a pending promise resolver stored in
+// |__gCrWeb.credentialManager|.
+void ResolvePromiseWithUndefined(web::WebState* web_state, int promise_id);
+
+// Rejects the Promise identified by |promise_id| with TypeError. This may be a
+// result of failed parsing of arguments passed to exposed API method.
+// |promise_id| is unique number of a pending promise rejecter stored in
+// |__gCrWeb.credentialManager|.
+void RejectPromiseWithTypeError(web::WebState* web_state,
+                                int promise_id,
+                                const base::StringPiece16& message);
+
+// Rejects the Promise identified by |promise_id| with InvalidStateError. This
+// should happen when credential manager is disabled or there is a pending 'get'
+// request. |promise_id| is unique number of a pending promise rejecter stored
+// in |__gCrWeb.credentialManager|.
+void RejectPromiseWithInvalidStateError(web::WebState* web_state,
+                                        int promise_id,
+                                        const base::StringPiece16& message);
+
+// Rejects the Promise identified by |promise_id| with NotSupportedError. This
+// should happen when password store is unavailable or an unknown error occurs.
+// |promise_id| is unique number of a pending promise rejecter stored in
+// |__gCrWeb.credentialManager|.
+void RejectPromiseWithNotSupportedError(web::WebState* web_state,
+                                        int promise_id,
+                                        const base::StringPiece16& message);
+
+}  // namespace credential_manager
+
+#endif  // IOS_CHROME_BROWSER_PASSWORDS_JS_CREDENTIAL_MANAGER_H_
diff --git a/ios/chrome/browser/passwords/js_credential_manager.mm b/ios/chrome/browser/passwords/js_credential_manager.mm
new file mode 100644
index 0000000..9d2c77ee
--- /dev/null
+++ b/ios/chrome/browser/passwords/js_credential_manager.mm
@@ -0,0 +1,114 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/passwords/js_credential_manager.h"
+
+#include "base/json/string_escape.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ios/web/public/web_state/web_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace credential_manager {
+
+namespace {
+
+// Takes CredentialInfo and returns string representing invocation of
+// Credential's constructor with proper values and type.
+std::string CredentialInfoToJsCredential(
+    const password_manager::CredentialInfo& info) {
+  if (info.type ==
+      password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED) {
+    return base::StringPrintf(
+        "new FederatedCredential({id: %s, name: %s, iconURL: %s, provider: "
+        "%s})",
+        base::GetQuotedJSONString(info.id).c_str(),
+        base::GetQuotedJSONString(info.name).c_str(),
+        base::GetQuotedJSONString(info.icon.spec()).c_str(),
+        base::GetQuotedJSONString(info.federation.GetURL().spec()).c_str());
+  }
+  if (info.type == password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD) {
+    return base::StringPrintf(
+        "new PasswordCredential({id: %s, name: %s, iconURL: %s, password: %s})",
+        base::GetQuotedJSONString(info.id).c_str(),
+        base::GetQuotedJSONString(info.name).c_str(),
+        base::GetQuotedJSONString(info.icon.spec()).c_str(),
+        base::GetQuotedJSONString(info.password).c_str());
+  }
+  NOTREACHED() << "Invalid CredentialType";
+  return std::string();
+}
+
+void ResolveOrRejectPromise(web::WebState* web_state,
+                            int promise_id,
+                            bool resolve,
+                            const std::string& script) {
+  DCHECK(web_state);
+  std::string js_code = base::StringPrintf(
+      "__gCrWeb.credentialManager.%s[%d](%s); delete "
+      "__gCrWeb.credentialManager.%s[%d];",
+      resolve ? "resolvers_" : "rejecters_", promise_id, script.c_str(),
+      resolve ? "resolvers_" : "rejecters_", promise_id);
+  web_state->ExecuteJavaScript(base::UTF8ToUTF16(js_code));
+}
+
+}  // namespace
+
+void ResolvePromiseWithCredentialInfo(
+    web::WebState* web_state,
+    int promise_id,
+    const base::Optional<password_manager::CredentialInfo>& info) {
+  DCHECK(web_state);
+  std::string credential_str = info.has_value()
+                                   ? CredentialInfoToJsCredential(info.value())
+                                   : std::string();
+  ResolveOrRejectPromise(web_state, promise_id, /*resolve=*/true,
+                         credential_str);
+}
+
+void ResolvePromiseWithUndefined(web::WebState* web_state, int promise_id) {
+  DCHECK(web_state);
+  ResolveOrRejectPromise(web_state, promise_id, /*resolve=*/true,
+                         std::string());
+}
+
+void RejectPromiseWithTypeError(web::WebState* web_state,
+                                int promise_id,
+                                const base::StringPiece16& message) {
+  DCHECK(web_state);
+  std::string type_error_str = base::StringPrintf(
+      "new TypeError(%s)", base::GetQuotedJSONString(message).c_str());
+  ResolveOrRejectPromise(web_state, promise_id, /*resolve=*/false,
+                         type_error_str);
+}
+
+void RejectPromiseWithInvalidStateError(web::WebState* web_state,
+                                        int promise_id,
+                                        const base::StringPiece16& message) {
+  DCHECK(web_state);
+  std::string invalid_state_err_str = base::StringPrintf(
+      "Object.create(DOMException.prototype, "
+      "{name:{value:DOMException.INVALID_STATE_ERR}, message:{value:%s}})",
+      base::GetQuotedJSONString(message).c_str());
+  ResolveOrRejectPromise(web_state, promise_id, /*resolve=*/false,
+                         invalid_state_err_str);
+}
+
+void RejectPromiseWithNotSupportedError(web::WebState* web_state,
+                                        int promise_id,
+                                        const base::StringPiece16& message) {
+  DCHECK(web_state);
+  std::string not_supported_err_str = base::StringPrintf(
+      "Object.create(DOMException.prototype, "
+      "{name:{value:DOMException.NOT_SUPPORTED_ERR}, message:{value:%s}})",
+      base::GetQuotedJSONString(message).c_str());
+  ResolveOrRejectPromise(web_state, promise_id, /*resolve=*/false,
+                         not_supported_err_str);
+}
+
+}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/js_credential_manager_unittest.mm b/ios/chrome/browser/passwords/js_credential_manager_unittest.mm
new file mode 100644
index 0000000..64a9e1c
--- /dev/null
+++ b/ios/chrome/browser/passwords/js_credential_manager_unittest.mm
@@ -0,0 +1,215 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/passwords/js_credential_manager.h"
+
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ios/web/public/test/web_js_test.h"
+#include "ios/web/public/test/web_test_with_web_state.h"
+#include "url/origin.h"
+
+namespace credential_manager {
+
+namespace {
+
+constexpr char kTestIconUrl[] = "https://www.google.com/favicon.ico";
+constexpr char kTestWebOrigin[] = "https://example.com";
+
+}  // namespace
+
+// Tests for js_credential_manager.mm file. Its functions RejectPromiseWith* and
+// ResolvePromiseWith* are tested as follows:
+// 1. |credential_manager| early script is injected to the page.
+// 2. A Promise is created. Depending on a test, it's |resolve| or |reject|
+//   function is expected to be called. That function stores the result or error
+//   in variable(s) with test_* prefix.
+// 3. To check if JavaScript executed by JsCredentialManager was correct, we
+//   check the values of test_* variable(s).
+class JsCredentialManagerTest
+    : public web::WebJsTest<web::WebTestWithWebState> {
+ public:
+  JsCredentialManagerTest()
+      : web::WebJsTest<web::WebTestWithWebState>(@[ @"credential_manager" ]) {}
+  void SetUp() override {
+    WebTestWithWebState::SetUp();
+
+    // Load empty HTML and inject |credential_manager| early script.
+    LoadHtmlAndInject(@"<html></html>");
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(JsCredentialManagerTest);
+};
+
+// Tests that ResolvePromiseWithCredentialInfo resolves the promise with
+// JavaScript PasswordCredential object containing correct values.
+TEST_F(JsCredentialManagerTest, ResolveWithPasswordCredential) {
+  // Let requestId be 3.
+  ExecuteJavaScript(
+      @"__gCrWeb.credentialManager.createPromise_(3)."
+       "then(function(result) {"
+       "  test_credential_ = result;"
+       "});");
+  password_manager::CredentialInfo credential;
+  credential.type = password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD;
+  credential.id = base::ASCIIToUTF16("test@google.com");
+  credential.name = base::ASCIIToUTF16("Test User");
+  credential.icon = GURL(base::ASCIIToUTF16(kTestIconUrl));
+  credential.password = base::ASCIIToUTF16("32njk \\4 s3cr3t \\n' 1");
+  ResolvePromiseWithCredentialInfo(web_state(), 3, credential);
+  // Wait for Promise to be resolved before checking the values.
+  WaitForCondition(^{
+    return static_cast<bool>(
+        [@"object" isEqual:ExecuteJavaScript(@"typeof test_credential_")]);
+  });
+  EXPECT_NSEQ(@"password", ExecuteJavaScript(@"test_credential_.type"));
+  EXPECT_NSEQ(@"test@google.com", ExecuteJavaScript(@"test_credential_.id"));
+  EXPECT_NSEQ(@"Test User", ExecuteJavaScript(@"test_credential_.name"));
+  EXPECT_NSEQ(base::SysUTF16ToNSString(base::ASCIIToUTF16(kTestIconUrl)),
+              ExecuteJavaScript(@"test_credential_.iconURL"));
+  EXPECT_NSEQ(@"32njk \\4 s3cr3t \\n' 1",
+              ExecuteJavaScript(@"test_credential_.password"));
+}
+
+// Tests that ResolvePromiseWithCredentialInfo resolves the promise with
+// JavaScript FederatedCredential object containing correct values.
+TEST_F(JsCredentialManagerTest, ResolveWithFederatedCredential) {
+  // Let requestId be 3.
+  ExecuteJavaScript(
+      @"__gCrWeb.credentialManager.createPromise_(3)."
+       "then(function(result) {"
+       "  test_credential_ = result;"
+       "});");
+  password_manager::CredentialInfo credential;
+  credential.type = password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED;
+  credential.id = base::ASCIIToUTF16("test@google.com");
+  credential.name = base::ASCIIToUTF16("Test User");
+  credential.icon = GURL(base::ASCIIToUTF16(kTestIconUrl));
+  credential.federation = url::Origin(GURL(kTestWebOrigin));
+  ResolvePromiseWithCredentialInfo(web_state(), 3, credential);
+  // Wait for Promise to be resolved before checking the values.
+  WaitForCondition(^{
+    return static_cast<bool>(
+        [@"object" isEqual:ExecuteJavaScript(@"typeof test_credential_")]);
+  });
+  EXPECT_NSEQ(@"federated", ExecuteJavaScript(@"test_credential_.type"));
+  EXPECT_NSEQ(@"test@google.com", ExecuteJavaScript(@"test_credential_.id"));
+  EXPECT_NSEQ(@"Test User", ExecuteJavaScript(@"test_credential_.name"));
+  EXPECT_NSEQ(base::SysUTF16ToNSString(base::ASCIIToUTF16(kTestIconUrl)),
+              ExecuteJavaScript(@"test_credential_.iconURL"));
+  EXPECT_NSEQ(base::SysUTF16ToNSString(base::ASCIIToUTF16(kTestWebOrigin)),
+              ExecuteJavaScript(@"test_credential_.provider"));
+}
+
+// Tests that ResolvePromiseWithCredentialInfo resolves the promise with void
+// when optional CredentialInfo is null.
+TEST_F(JsCredentialManagerTest, ResolveWithNullCredential) {
+  // Let requestId be 3.
+  ExecuteJavaScript(
+      @"__gCrWeb.credentialManager.createPromise_(3)."
+       "then(function(result) {"
+       "  test_result_ = (result == undefined);"
+       "});");
+  base::Optional<password_manager::CredentialInfo> null_credential;
+  ResolvePromiseWithCredentialInfo(web_state(), 3, null_credential);
+  // Wait for Promise to be resolved before checking the values.
+  WaitForCondition(^{
+    return static_cast<bool>(
+        [@"boolean" isEqual:ExecuteJavaScript(@"typeof test_result_")]);
+  });
+  EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_"));
+}
+
+// Tests that ResolvePromiseWithUndefined resolves the promise with no value.
+TEST_F(JsCredentialManagerTest, ResolveWithUndefined) {
+  // Let requestId be equal 5.
+  // Only when the promise is resolved with undefined, will the
+  // |test_result_| be true.
+  ExecuteJavaScript(
+      @"__gCrWeb.credentialManager.createPromise_(5)."
+       "then(function(result) {"
+       "  test_result_ = (result == undefined);"
+       "});");
+  ResolvePromiseWithUndefined(web_state(), 5);
+  // Wait for Promise to be resolved before checking the values.
+  WaitForCondition(^{
+    return static_cast<bool>(
+        [@"boolean" isEqual:ExecuteJavaScript(@"typeof test_result_")]);
+  });
+  EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_"));
+}
+
+// Tests that RejectPromiseWithTypeError rejects the promise with TypeError and
+// correct message.
+TEST_F(JsCredentialManagerTest, RejectWithTypeError) {
+  // Let requestId be equal 100.
+  ExecuteJavaScript(
+      @"__gCrWeb.credentialManager.createPromise_(100)."
+       "catch(function(reason) {"
+       "  test_result_valid_type_ = (reason instanceof TypeError);"
+       "  test_result_message_ = reason.message;"
+       "});");
+  RejectPromiseWithTypeError(
+      web_state(), 100, base::ASCIIToUTF16("message with \"quotation\" marks"));
+  // Wait for Promise to be rejected before checking the values.
+  WaitForCondition(^{
+    return static_cast<bool>(
+        [@"string" isEqual:ExecuteJavaScript(@"typeof test_result_message_")]);
+  });
+  EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_valid_type_"));
+  EXPECT_NSEQ(@"message with \"quotation\" marks",
+              ExecuteJavaScript(@"test_result_message_"));
+}
+
+// Tests that RejectPromiseWithInvalidStateError rejects the promise with
+// DOMException(message, INVALID_STATE_ERR), where |message| is correct message
+// taken as argument.
+TEST_F(JsCredentialManagerTest, RejectWithInvalidState) {
+  // Let requestId be 0.
+  ExecuteJavaScript(
+      @"__gCrWeb.credentialManager.createPromise_(0)."
+       "catch(function(reason) {"
+       "  test_result_valid_type_ ="
+       "    (reason.name == DOMException.INVALID_STATE_ERR);"
+       "  test_result_message_ = reason.message;"
+       "});");
+  RejectPromiseWithInvalidStateError(
+      web_state(), 0, base::ASCIIToUTF16("A 'get()' request is pending"));
+  // Wait for Promise to be rejected before checking the values.
+  WaitForCondition(^{
+    return static_cast<bool>(
+        [@"string" isEqual:ExecuteJavaScript(@"typeof test_result_message_")]);
+  });
+  EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_valid_type_"));
+  EXPECT_NSEQ(@"A 'get()' request is pending",
+              ExecuteJavaScript(@"test_result_message_"));
+}
+
+// Tests that RejectPromiseWithNotSupportedError rejects the promise with
+// DOMException(message, NOT_SUPPORTED_ERR), where |message| is correct message
+// taken as argument.
+TEST_F(JsCredentialManagerTest, RejectWithNotSupportedError) {
+  // Let requestId be 0.
+  ExecuteJavaScript(
+      @"__gCrWeb.credentialManager.createPromise_(0)."
+       "catch(function(reason) {"
+       "  test_result_valid_type_ ="
+       "    (reason.name == DOMException.NOT_SUPPORTED_ERR);"
+       "  test_result_message_ = reason.message;"
+       "});");
+  RejectPromiseWithNotSupportedError(
+      web_state(), 0,
+      base::ASCIIToUTF16(
+          "An error occured while talking to the credential manager."));
+  // Wait for Promise to be rejected before checking the values.
+  WaitForCondition(^{
+    return static_cast<bool>(
+        [@"string" isEqual:ExecuteJavaScript(@"typeof test_result_message_")]);
+  });
+  EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_valid_type_"));
+  EXPECT_NSEQ(@"An error occured while talking to the credential manager.",
+              ExecuteJavaScript(@"test_result_message_"));
+}
+
+}  // namespace credential_manager
diff --git a/ios/chrome/browser/payments/ios_can_make_payment_query_factory.cc b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.cc
index bbd68fc..b716d050 100644
--- a/ios/chrome/browser/payments/ios_can_make_payment_query_factory.cc
+++ b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.cc
@@ -16,6 +16,7 @@
   return base::Singleton<IOSCanMakePaymentQueryFactory>::get();
 }
 
+// static
 payments::CanMakePaymentQuery*
 IOSCanMakePaymentQueryFactory::GetForBrowserState(
     ios::ChromeBrowserState* browser_state) {
diff --git a/ios/chrome/browser/payments/ios_can_make_payment_query_factory.h b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.h
index e3549e38..8ccaa9d 100644
--- a/ios/chrome/browser/payments/ios_can_make_payment_query_factory.h
+++ b/ios/chrome/browser/payments/ios_can_make_payment_query_factory.h
@@ -28,7 +28,7 @@
 class IOSCanMakePaymentQueryFactory : public BrowserStateKeyedServiceFactory {
  public:
   static IOSCanMakePaymentQueryFactory* GetInstance();
-  payments::CanMakePaymentQuery* GetForBrowserState(
+  static payments::CanMakePaymentQuery* GetForBrowserState(
       ios::ChromeBrowserState* browser_state);
 
  private:
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_finder.h b/ios/chrome/browser/payments/ios_payment_instrument_finder.h
index 844b963..292ac03e96 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_finder.h
+++ b/ios/chrome/browser/payments/ios_payment_instrument_finder.h
@@ -93,7 +93,7 @@
       IOSPaymentInstrumentsFoundCallback callback);
 
  private:
-  friend class IOSPaymentInstrumentFinderTest;
+  friend class PaymentRequestIOSPaymentInstrumentFinderTest;
 
   // Filters out |queried_url_payment_method_identifiers| for any invalid
   // url payment method identifiers queried by the caller. An invalid url
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm b/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm
index 959027c..2d821f2 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm
+++ b/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm
@@ -31,9 +31,9 @@
   DISALLOW_COPY_AND_ASSIGN(TestIOSPaymentInstrumentFinder);
 };
 
-class IOSPaymentInstrumentFinderTest : public testing::Test {
+class PaymentRequestIOSPaymentInstrumentFinderTest : public testing::Test {
  public:
-  IOSPaymentInstrumentFinderTest()
+  PaymentRequestIOSPaymentInstrumentFinderTest()
       : scoped_task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::IO),
         context_getter_(new net::TestURLRequestContextGetter(
@@ -42,7 +42,7 @@
             base::MakeUnique<TestIOSPaymentInstrumentFinder>(
                 context_getter_.get())) {}
 
-  ~IOSPaymentInstrumentFinderTest() override {}
+  ~PaymentRequestIOSPaymentInstrumentFinderTest() override {}
 
   size_t num_instruments_to_find() {
     return ios_payment_instrument_finder_->num_instruments_to_find_;
@@ -122,15 +122,15 @@
   void FindInstrumentsWithMethods(std::vector<GURL>& url_methods) {
     ios_payment_instrument_finder_->CreateIOSPaymentInstrumentsForMethods(
         url_methods,
-        base::BindOnce(
-            &IOSPaymentInstrumentFinderTest::InstrumentsFoundCallback,
-            base::Unretained(this)));
+        base::BindOnce(&PaymentRequestIOSPaymentInstrumentFinderTest::
+                           InstrumentsFoundCallback,
+                       base::Unretained(this)));
   }
 
   void FindInstrumentsWithWebAppManifest(const GURL& method,
                                          const std::string& content) {
     ios_payment_instrument_finder_->callback_ = base::BindOnce(
-        &IOSPaymentInstrumentFinderTest::InstrumentsFoundCallback,
+        &PaymentRequestIOSPaymentInstrumentFinderTest::InstrumentsFoundCallback,
         base::Unretained(this));
     ios_payment_instrument_finder_->num_instruments_to_find_ = 1;
     ios_payment_instrument_finder_->OnWebAppManifestDownloaded(
@@ -152,79 +152,85 @@
   std::unique_ptr<base::RunLoop> run_loop_;
   std::vector<std::unique_ptr<IOSPaymentInstrument>> result_;
 
-  DISALLOW_COPY_AND_ASSIGN(IOSPaymentInstrumentFinderTest);
+  DISALLOW_COPY_AND_ASSIGN(PaymentRequestIOSPaymentInstrumentFinderTest);
 };
 
 // Payment method manifest parsing:
 
-TEST_F(IOSPaymentInstrumentFinderTest, NullPaymentMethodManifestIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       NullPaymentMethodManifestIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest(std::string());
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        NonJsonPaymentMethodManifestIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest("this is not json");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, StringPaymentMethodManifestIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       StringPaymentMethodManifestIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest("\"this is a string\"");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        EmptyDictionaryPaymentMethodManifestIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest("{}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, NullDefaultApplicationIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       NullDefaultApplicationIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": null}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, NumberDefaultApplicationIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       NumberDefaultApplicationIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": 0}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        ListOfNumbersDefaultApplicationIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": [0]}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        EmptyListOfDefaultApplicationsIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest("{\"default_applications\": []}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        ListOfEmptyDefaultApplicationsIsMalformed) {
   ExpectUnableToParsePaymentMethodManifest(
       "{\"default_applications\": [\"\"]}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        DefaultApplicationsShouldNotHaveNulCharacters) {
   ExpectUnableToParsePaymentMethodManifest(
       "{\"default_applications\": [\"https://bobpay.com/app\0json\"]}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, DefaultApplicationKeyShouldBeLowercase) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       DefaultApplicationKeyShouldBeLowercase) {
   ExpectUnableToParsePaymentMethodManifest(
       "{\"Default_Applications\": [\"https://bobpay.com/app.json\"]}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        DefaultApplicationsShouldHaveAbsoluteUrl) {
   ExpectUnableToParsePaymentMethodManifest(
       "{\"default_applications\": ["
       "\"app.json\"]}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, DefaultApplicationsShouldBeHttps) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       DefaultApplicationsShouldBeHttps) {
   ExpectUnableToParsePaymentMethodManifest(
       "{\"default_applications\": ["
       "\"http://bobpay.com/app.json\","
       "\"http://alicepay.com/app.json\"]}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        WellFormedPaymentMethodManifestWithApps) {
   ExpectParsedPaymentMethodManifest(
       "{\"default_applications\": ["
@@ -234,7 +240,7 @@
        GURL("https://alicepay.com/app.json")});
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        WellFormedPaymentMethodManifestWithDuplicateApps) {
   ExpectParsedPaymentMethodManifest(
       "{\"default_applications\": ["
@@ -247,23 +253,25 @@
 
 // Web app manifest parsing:
 
-TEST_F(IOSPaymentInstrumentFinderTest, NullContentIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest, NullContentIsMalformed) {
   ExpectUnableToParseWebAppManifest(std::string());
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, NonJsonContentIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       NonJsonContentIsMalformed) {
   ExpectUnableToParseWebAppManifest("this is not json");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, StringContentIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest, StringContentIsMalformed) {
   ExpectUnableToParseWebAppManifest("\"this is a string\"");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, EmptyDictionaryIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       EmptyDictionaryIsMalformed) {
   ExpectUnableToParseWebAppManifest("{}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        NullRelatedApplicationsSectionIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
@@ -275,7 +283,7 @@
       "  \"related_applications\": null");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        NumberRelatedApplicationSectionIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
@@ -288,7 +296,7 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        ListOfNumbersRelatedApplicationsSectionIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
@@ -301,7 +309,7 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        EmptyListRelatedApplicationsSectionIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
@@ -314,7 +322,7 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        ListOfEmptyDictionariesRelatedApplicationsSectionIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
@@ -327,7 +335,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, NoItunesPlatformIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       NoItunesPlatformIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -341,7 +350,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, NoUniversalLinkIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       NoUniversalLinkIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -355,7 +365,7 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, NoShortNameIsMalformed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest, NoShortNameIsMalformed) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"icons\": [{"
@@ -368,7 +378,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, PlatformShouldNotHaveNullCharacters) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       PlatformShouldNotHaveNullCharacters) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -382,7 +393,7 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        UniversalLinkShouldNotHaveNullCharacters) {
   ExpectUnableToParseWebAppManifest(
       "{"
@@ -398,7 +409,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, IconSourceShouldNotHaveNullCharacters) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       IconSourceShouldNotHaveNullCharacters) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -413,7 +425,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, IconSizesShouldNotHaveNullCharacters) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       IconSizesShouldNotHaveNullCharacters) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -428,7 +441,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, ShortNameShouldNotHaveNullCharacters) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       ShortNameShouldNotHaveNullCharacters) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bob\0pay\", "
@@ -443,7 +457,7 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, KeysShouldBeLowerCase) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest, KeysShouldBeLowerCase) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"Short_name\": \"Bobpay\", "
@@ -458,7 +472,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, UniversalLinkShouldHaveAbsoluteUrl) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       UniversalLinkShouldHaveAbsoluteUrl) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -473,7 +488,8 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, UniversalLinkShouldBeHttps) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       UniversalLinkShouldBeHttps) {
   ExpectUnableToParseWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -488,7 +504,7 @@
       "}");
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, WellFormed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest, WellFormed) {
   ExpectParsedWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -505,7 +521,8 @@
       GURL("https://bobpay.xyz/pay"));
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, RelativeIconPathWellFormed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       RelativeIconPathWellFormed) {
   ExpectParsedWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -522,7 +539,8 @@
       GURL("https://bobpay.xyz/pay"));
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest, RelativeIconPathForwardSlashWellFormed) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       RelativeIconPathForwardSlashWellFormed) {
   ExpectParsedWebAppManifest(
       "{"
       "  \"short_name\": \"Bobpay\", "
@@ -539,7 +557,7 @@
       GURL("https://bobpay.xyz/pay"));
 }
 
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        TwoRelatedApplicationsSecondIsWellFormed) {
   ExpectParsedWebAppManifest(
       "{"
@@ -563,7 +581,8 @@
 // Tests that supplying no methods to the IOSPaymentInstrumentFinder class still
 // invokes the caller's callback function and that the list of returned
 // instruments is empty.
-TEST_F(IOSPaymentInstrumentFinderTest, NoMethodsSuppliedNoInstruments) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       NoMethodsSuppliedNoInstruments) {
   std::vector<GURL> url_methods;
 
   FindInstrumentsWithMethods(url_methods);
@@ -575,7 +594,7 @@
 // Tests that supplying many invalid methods to the IOSPaymentInstrumentFinder
 // class still invokes the caller's callback function and that the list of
 // returned instruments is empty.
-TEST_F(IOSPaymentInstrumentFinderTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
        ManyInvalidMethodsSuppliedNoInstruments) {
   std::vector<GURL> url_methods;
   url_methods.push_back(GURL("https://fake-host-name/bobpay"));
@@ -592,7 +611,8 @@
 // Tests that supplying one valid method with a corresponding complete web
 // app manifest will result in one created IOSPaymentInstrument that is returned
 // to the caller.
-TEST_F(IOSPaymentInstrumentFinderTest, OneValidMethodSuppliedOneInstrument) {
+TEST_F(PaymentRequestIOSPaymentInstrumentFinderTest,
+       OneValidMethodSuppliedOneInstrument) {
   FindInstrumentsWithWebAppManifest(
       GURL("https://emerald-eon.appspot.com/bobpay"),
       "{"
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_launcher.h b/ios/chrome/browser/payments/ios_payment_instrument_launcher.h
index af4eeba..c1c113e 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_launcher.h
+++ b/ios/chrome/browser/payments/ios_payment_instrument_launcher.h
@@ -72,7 +72,7 @@
   std::string payment_request_id() { return payment_request_id_; }
 
  private:
-  friend class IOSPaymentInstrumentLauncherTest;
+  friend class PaymentRequestIOSPaymentInstrumentLauncherTest;
 
   // Returns the JSON-serialized dictionary from each method name the merchant
   // requested to the corresponding method data. |stringified_method_data| is
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_launcher_unittest.mm b/ios/chrome/browser/payments/ios_payment_instrument_launcher_unittest.mm
index 239232f8..2ae17aa6 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_launcher_unittest.mm
+++ b/ios/chrome/browser/payments/ios_payment_instrument_launcher_unittest.mm
@@ -71,9 +71,9 @@
 
 }  // namespace
 
-class IOSPaymentInstrumentLauncherTest : public testing::Test {
+class PaymentRequestIOSPaymentInstrumentLauncherTest : public testing::Test {
  protected:
-  IOSPaymentInstrumentLauncherTest()
+  PaymentRequestIOSPaymentInstrumentLauncherTest()
       : chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {}
 
   std::unique_ptr<base::DictionaryValue> SerializeMethodDataWrapper(
@@ -95,7 +95,8 @@
 
 // Tests that serializing empty stringified method data yields the expected
 // result.
-TEST_F(IOSPaymentInstrumentLauncherTest, EmptyStringifiedMethodDataDictionary) {
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
+       EmptyStringifiedMethodDataDictionary) {
   web::PaymentRequest web_payment_request;
   autofill::TestPersonalDataManager personal_data_manager;
   TestPaymentRequest payment_request(web_payment_request,
@@ -111,7 +112,7 @@
 
 // Tests that serializing populated stringified method data yields the expected
 // result.
-TEST_F(IOSPaymentInstrumentLauncherTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
        PopulatedStringifiedMethodDataDictionary) {
   web::PaymentRequest web_payment_request;
   PaymentMethodData method_datum1;
@@ -165,7 +166,7 @@
 
 // Tests that attempting to open an invalid universal link calls the
 // OnInstrumentDetailsError() function of the delegate.
-TEST_F(IOSPaymentInstrumentLauncherTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
        LaunchIOSPaymentInstrument_MalformedUniversalLink) {
   if (base::ios::IsRunningOnIOS10OrLater()) {
     std::unique_ptr<web::TestNavigationManager> navigation_manager =
@@ -198,7 +199,7 @@
 // Tests that if the response from the payment app is not a valid JSON
 // dictionary then the OnInstrumentDetailsError() function of the delegate
 // is called.
-TEST_F(IOSPaymentInstrumentLauncherTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
        ReceiveResponseFromIOSPaymentInstrument_ResponseNotDictionary) {
   FakePaymentInstrumentDelegate instrument_delegate;
   IOSPaymentInstrumentLauncher launcher;
@@ -220,7 +221,7 @@
 // Tests that if a payment app claims to have not been successful in
 // fulfilling its side of the transaction then OnInstrumentDetailsError()
 // is called.
-TEST_F(IOSPaymentInstrumentLauncherTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
        ReceiveResponseFromIOSPaymentInstrument_PaymentAppFailed) {
   FakePaymentInstrumentDelegate instrument_delegate;
   IOSPaymentInstrumentLauncher launcher;
@@ -247,7 +248,7 @@
 // Tests that if the response from the payment app does not contain a
 // method name then OnInstrumentDetailsError() of the delegate is
 // called.
-TEST_F(IOSPaymentInstrumentLauncherTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
        ReceiveResponseFromIOSPaymentInstrument_NoMethodName) {
   FakePaymentInstrumentDelegate instrument_delegate;
   IOSPaymentInstrumentLauncher launcher;
@@ -273,7 +274,7 @@
 // Tests that if the response from the payment app does not contain any
 // stringified details then OnInstrumentDetailsError() of the delegate is
 // called.
-TEST_F(IOSPaymentInstrumentLauncherTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
        ReceiveResponseFromIOSPaymentInstrument_NoDetails) {
   FakePaymentInstrumentDelegate instrument_delegate;
   IOSPaymentInstrumentLauncher launcher;
@@ -299,7 +300,7 @@
 // Tests that if the response from the payment app has all necessary
 // parameters with valid values then OnInstrumentDetailsReady() of the
 // delegate is called.
-TEST_F(IOSPaymentInstrumentLauncherTest,
+TEST_F(PaymentRequestIOSPaymentInstrumentLauncherTest,
        ReceiveResponseFromIOSPaymentInstrument_WellFormedResponse) {
   FakePaymentInstrumentDelegate instrument_delegate;
   IOSPaymentInstrumentLauncher launcher;
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm
index 43e341af..6eaaa80 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm
@@ -9,8 +9,8 @@
 #include "base/ios/ios_util.h"
 #include "base/run_loop.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/signin/gaia_auth_fetcher_ios_private.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -57,30 +57,32 @@
 // Tests fixture for GaiaAuthFetcherIOS
 class GaiaAuthFetcherIOSTest : public PlatformTest {
  protected:
-  void SetUp() override {
-    PlatformTest::SetUp();
-    web::BrowserState::GetActiveStateManager(&browser_state_)->SetActive(true);
+  GaiaAuthFetcherIOSTest() {
+    browser_state_ = TestChromeBrowserState::Builder().Build();
+
+    web::BrowserState::GetActiveStateManager(browser_state())->SetActive(true);
     gaia_auth_fetcher_.reset(new GaiaAuthFetcherIOS(&consumer_, std::string(),
-                                                    nullptr, &browser_state_));
+                                                    nullptr, browser_state()));
     gaia_auth_fetcher_->bridge_.reset(new FakeGaiaAuthFetcherIOSBridge(
-        gaia_auth_fetcher_.get(), &browser_state_));
+        gaia_auth_fetcher_.get(), browser_state()));
   }
 
-  void TearDown() override {
+  ~GaiaAuthFetcherIOSTest() override {
     gaia_auth_fetcher_.reset();
-    web::BrowserState::GetActiveStateManager(&browser_state_)->SetActive(false);
-    PlatformTest::TearDown();
+    web::BrowserState::GetActiveStateManager(browser_state())->SetActive(false);
   }
 
   GaiaAuthFetcherIOSBridge* GetBridge() {
     return gaia_auth_fetcher_->bridge_.get();
   }
 
+  ios::ChromeBrowserState* browser_state() { return browser_state_.get(); }
+
   id GetMockWKWebView() { return gaia_auth_fetcher_->bridge_->GetWKWebView(); }
 
   web::TestWebThreadBundle thread_bundle_;
   // BrowserState, required for WKWebView creation.
-  web::TestBrowserState browser_state_;
+  std::unique_ptr<ios::ChromeBrowserState> browser_state_;
   MockGaiaConsumer consumer_;
   std::unique_ptr<GaiaAuthFetcherIOS> gaia_auth_fetcher_;
 };
@@ -160,7 +162,7 @@
 // inactive.
 TEST_F(GaiaAuthFetcherIOSTest, OnInactive) {
   [[GetMockWKWebView() expect] stopLoading];
-  web::BrowserState::GetActiveStateManager(&browser_state_)->SetActive(false);
+  web::BrowserState::GetActiveStateManager(browser_state())->SetActive(false);
   EXPECT_OCMOCK_VERIFY(GetMockWKWebView());
 }
 
@@ -176,9 +178,9 @@
     GetBridge()->URLFetchSuccess("data");
   }]) loadRequest:[OCMArg any]];
 
-  web::BrowserState::GetActiveStateManager(&browser_state_)->SetActive(false);
+  web::BrowserState::GetActiveStateManager(browser_state())->SetActive(false);
   gaia_auth_fetcher_->StartMergeSession("uber_token", "");
-  web::BrowserState::GetActiveStateManager(&browser_state_)->SetActive(true);
+  web::BrowserState::GetActiveStateManager(browser_state())->SetActive(true);
   EXPECT_OCMOCK_VERIFY(GetMockWKWebView());
 }
 
@@ -196,7 +198,7 @@
   }]) loadRequest:[OCMArg any]];
 
   gaia_auth_fetcher_->StartMergeSession("uber_token", "");
-  web::BrowserState::GetActiveStateManager(&browser_state_)->SetActive(false);
-  web::BrowserState::GetActiveStateManager(&browser_state_)->SetActive(true);
+  web::BrowserState::GetActiveStateManager(browser_state())->SetActive(false);
+  web::BrowserState::GetActiveStateManager(browser_state())->SetActive(true);
   EXPECT_OCMOCK_VERIFY(GetMockWKWebView());
 }
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index b54a8f6..c2408bd0 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -118,7 +118,6 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/downloads",
     "//ios/chrome/browser/ui/overscroll_actions",
-    "//ios/chrome/browser/ui/sad_tab",
     "//ios/chrome/browser/ui/toolbar",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web",
diff --git a/ios/chrome/browser/tabs/tab.h b/ios/chrome/browser/tabs/tab.h
index a391ffb..1e2a500 100644
--- a/ios/chrome/browser/tabs/tab.h
+++ b/ios/chrome/browser/tabs/tab.h
@@ -12,7 +12,6 @@
 
 #import "components/signin/ios/browser/manage_accounts_delegate.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper_delegate.h"
-#import "ios/chrome/browser/web/sad_tab_tab_helper_delegate.h"
 #include "ios/net/request_tracker.h"
 #include "ios/web/public/user_agent.h"
 #include "ui/base/page_transition_types.h"
@@ -86,9 +85,8 @@
 // Chrome's WebContents in that it encapsulates rendering. Acts as the
 // delegate for the WebState in order to process info about pages having
 // loaded.
-@interface Tab : NSObject<ManageAccountsDelegate,
-                          PagePlaceholderTabHelperDelegate,
-                          SadTabTabHelperDelegate>
+@interface Tab
+    : NSObject<ManageAccountsDelegate, PagePlaceholderTabHelperDelegate>
 
 // Browser state associated with this Tab.
 @property(nonatomic, readonly) ios::ChromeBrowserState* browserState;
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index cdcebef..6869c9c 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -45,7 +45,7 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
 #include "ios/chrome/browser/application_context.h"
-#import "ios/chrome/browser/autofill/autofill_controller.h"
+#import "ios/chrome/browser/autofill/autofill_tab_helper.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h"
 #import "ios/chrome/browser/autofill/form_suggestion_controller.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
@@ -93,14 +93,12 @@
 #import "ios/chrome/browser/ui/open_in_controller.h"
 #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
 #import "ios/chrome/browser/ui/prerender_delegate.h"
-#import "ios/chrome/browser/ui/sad_tab/sad_tab_view.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/web/auto_reload_bridge.h"
 #import "ios/chrome/browser/web/external_app_launcher.h"
 #import "ios/chrome/browser/web/navigation_manager_util.h"
 #import "ios/chrome/browser/web/passkit_dialog_provider.h"
 #include "ios/chrome/browser/web/print_observer.h"
-#import "ios/chrome/browser/web/sad_tab_tab_helper.h"
 #import "ios/chrome/browser/web/tab_id_tab_helper.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
@@ -221,9 +219,6 @@
   // Manages the input accessory view during form input.
   FormInputAccessoryViewController* _inputAccessoryViewController;
 
-  // Handles autofill.
-  AutofillController* _autofillController;
-
   // Handles retrieving, generating and updating snapshots of CRWWebController's
   // web page.
   WebControllerSnapshotHelper* _webControllerSnapshotHelper;
@@ -439,11 +434,6 @@
   if (experimental_flags::IsAutoReloadEnabled())
     _autoReloadBridge = [[AutoReloadBridge alloc] initWithTab:self];
 
-  _autofillController = [[AutofillController alloc]
-           initWithBrowserState:_browserState
-      passwordGenerationManager:PasswordTabHelper::FromWebState(self.webState)
-                                    ->GetPasswordGenerationManager()
-                       webState:self.webState];
   _suggestionController = [[FormSuggestionController alloc]
       initWithWebState:self.webState
              providers:[self suggestionProviders]];
@@ -477,7 +467,8 @@
   NSMutableArray* providers = [NSMutableArray array];
   [providers addObject:PasswordTabHelper::FromWebState(self.webState)
                            ->GetSuggestionProvider()];
-  [providers addObject:[_autofillController suggestionProvider]];
+  [providers addObject:AutofillTabHelper::FromWebState(self.webState)
+                           ->GetSuggestionProvider()];
   return providers;
 }
 
@@ -869,8 +860,6 @@
   _faviconDriverObserverBridge.reset();
   [_openInController detachFromWebController];
   _openInController = nil;
-  [_autofillController detachFromWebState];
-  _autofillController = nil;
   [_suggestionController detachFromWebState];
   _suggestionController = nil;
   if (_fullScreenController)
@@ -1661,21 +1650,6 @@
       }];
 }
 
-#pragma mark - SadTabTabHelperDelegate
-
-- (void)sadTabHelper:(SadTabTabHelper*)tabHelper
-    presentSadTabForRepeatedFailure:(BOOL)repeatedFailure {
-  // Create a SadTabView so |webstate| presents it.
-  SadTabView* sadTabview = [[SadTabView alloc]
-           initWithMode:repeatedFailure ? SadTabViewMode::FEEDBACK
-                                        : SadTabViewMode::RELOAD
-      navigationManager:tabHelper->web_state()->GetNavigationManager()];
-  sadTabview.dispatcher = self.dispatcher;
-  CRWContentView* contentView =
-      [[CRWGenericContentView alloc] initWithView:sadTabview];
-  tabHelper->web_state()->ShowTransientContentView(contentView);
-}
-
 @end
 
 #pragma mark - TestingSupport
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index 1b97912c..2f27c9f 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -13,6 +13,7 @@
 #import "components/history/ios/browser/web_state_top_sites_observer.h"
 #include "components/keyed_service/core/service_access_type.h"
 #import "components/signin/ios/browser/account_consistency_service.h"
+#import "ios/chrome/browser/autofill/autofill_tab_helper.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/favicon/favicon_service_factory.h"
@@ -38,7 +39,6 @@
 #import "ios/chrome/browser/web/network_activity_indicator_tab_helper.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
 #import "ios/chrome/browser/web/repost_form_tab_helper.h"
-#import "ios/chrome/browser/web/sad_tab_tab_helper.h"
 #import "ios/chrome/browser/web/tab_id_tab_helper.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/web/public/web_state/web_state.h"
@@ -66,7 +66,6 @@
   BlockedPopupTabHelper::CreateForWebState(web_state);
   FindTabHelper::CreateForWebState(web_state, tab.findInPageControllerDelegate);
   StoreKitTabHelper::CreateForWebState(web_state);
-  SadTabTabHelper::CreateForWebState(web_state, tab);
   PagePlaceholderTabHelper::CreateForWebState(web_state, tab);
   CaptivePortalDetectorTabHelper::CreateForWebState(web_state);
 
@@ -97,6 +96,10 @@
   PasswordTabHelper::CreateForWebState(web_state,
                                        [[PasswordsUiDelegateImpl alloc] init]);
 
+  AutofillTabHelper::CreateForWebState(
+      web_state, PasswordTabHelper::FromWebState(web_state)
+                     ->GetPasswordGenerationManager());
+
   // Allow the embedder to attach tab helpers.
   ios::GetChromeBrowserProvider()->AttachTabHelpers(web_state, tab);
 
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index a30d4cd..5dc22a1 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -318,6 +318,7 @@
     "//ios/chrome/browser/ui/qr_scanner:coordinator",
     "//ios/chrome/browser/ui/qr_scanner/requirements",
     "//ios/chrome/browser/ui/reading_list",
+    "//ios/chrome/browser/ui/sad_tab:coordinator",
     "//ios/chrome/browser/ui/stack_view",
     "//ios/chrome/browser/ui/static_content",
     "//ios/chrome/browser/ui/sync",
diff --git a/ios/chrome/browser/ui/bookmarks/OWNERS b/ios/chrome/browser/ui/bookmarks/OWNERS
index f6480c4..16c3089 100644
--- a/ios/chrome/browser/ui/bookmarks/OWNERS
+++ b/ios/chrome/browser/ui/bookmarks/OWNERS
@@ -1,6 +1,7 @@
 noyau@chromium.org
 lpromero@chromium.org
 ramyasharma@chromium.org
+martiw@chromium.org
 
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 412ff9a..849db1c 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -420,16 +420,45 @@
   if (nodes.size() == 1) {
     const bookmarks::BookmarkNode* node = *nodes.begin();
     if (node->is_url()) {
-      [self setContextBarState:BookmarksContextBarSingleSelection];
+      [self setContextBarState:BookmarksContextBarSingleURLSelection];
     } else if (node->is_folder()) {
       [self setContextBarState:BookmarksContextBarSingleFolderSelection];
     }
     return;
   }
-  if (nodes.size() > 1) {
-    [self setContextBarState:BookmarksContextBarMultipleSelection];
+  BOOL foundURL = NO;
+  BOOL foundFolder = NO;
+  for (std::set<const bookmarks::BookmarkNode*>::iterator i = nodes.begin();
+       i != nodes.end(); ++i) {
+    const bookmarks::BookmarkNode* node = *i;
+    if (!foundURL && node->is_url()) {
+      foundURL = YES;
+    } else if (!foundFolder && node->is_folder()) {
+      foundFolder = YES;
+    }
+    // Break early, if we found both types of nodes.
+    if (foundURL && foundFolder) {
+      break;
+    }
+  }
+  // Only URLs are selected.
+  if (foundURL && !foundFolder) {
+    [self setContextBarState:BookmarksContextBarMultipleURLSelection];
     return;
   }
+  // Only Folders are selected.
+  if (!foundURL && foundFolder) {
+    [self setContextBarState:BookmarksContextBarMultipleFolderSelection];
+    return;
+  }
+  // Mixed selection.
+  if (foundURL && foundFolder) {
+    [self setContextBarState:BookmarksContextBarMixedSelection];
+    return;
+  }
+
+  NOTREACHED();
+  return;
 }
 
 #pragma mark - BookmarkFolderViewControllerDelegate
@@ -1057,9 +1086,11 @@
       // point.
       NOTREACHED();
       break;
-    case BookmarksContextBarSingleSelection:
-    case BookmarksContextBarMultipleSelection:
+    case BookmarksContextBarSingleURLSelection:
+    case BookmarksContextBarMultipleURLSelection:
     case BookmarksContextBarSingleFolderSelection:
+    case BookmarksContextBarMultipleFolderSelection:
+    case BookmarksContextBarMixedSelection:
       // Delete clicked.
       [self deleteNodes:nodes];
       break;
@@ -1068,10 +1099,54 @@
       NOTREACHED();
   }
 }
+
 // Called when the center button is clicked.
 - (void)centerButtonClicked {
-  // TODO(crbug.com/695749): Implement the button action here.
+  const std::set<const bookmarks::BookmarkNode*> nodes =
+      [self.bookmarksTableView editNodes];
+  // Center button is shown and is clickable only when at least
+  // one node is selected.
+  DCHECK(nodes.size() > 0);
+  switch (self.contextBarState) {
+    case BookmarksContextBarDefault:
+      // Center button is disabled in default state.
+      NOTREACHED();
+      break;
+    case BookmarksContextBarBeginSelection:
+      // Center button is disabled in start state.
+      NOTREACHED();
+      break;
+    case BookmarksContextBarSingleURLSelection:
+      // More clicked, show action sheet with context menu.
+      [self presentViewController:[self contextMenuForSingleBookmarkURL]
+                         animated:YES
+                       completion:nil];
+      break;
+    case BookmarksContextBarMultipleURLSelection:
+      // More clicked, show action sheet with context menu.
+      [self presentViewController:[self contextMenuForMultipleBookmarkURLs]
+                         animated:YES
+                       completion:nil];
+      break;
+    case BookmarksContextBarSingleFolderSelection:
+      // Edit clicked, open the editor.
+      [self editNode:*(nodes.begin())];
+      break;
+    case BookmarksContextBarMultipleFolderSelection:
+    case BookmarksContextBarMixedSelection:
+      // More clicked, show action sheet with context menu.
+      [self
+          presentViewController:[self
+                                    contextMenuForMixedAndMultiFolderSelection]
+                       animated:YES
+                     completion:nil];
+      break;
+    case BookmarksContextBarNone:
+    default:
+      NOTREACHED();
+  }
 }
+
 // Called when the trailing button, "Select" or "Cancel" is clicked.
 - (void)trailingButtonClicked {
   // Toggle edit mode.
@@ -1095,8 +1170,10 @@
         [self setBookmarksContextBarButtonsDefaultState];
       }
       break;
-    case BookmarksContextBarSingleSelection:
-    case BookmarksContextBarMultipleSelection:
+    case BookmarksContextBarSingleURLSelection:
+    case BookmarksContextBarMultipleURLSelection:
+    case BookmarksContextBarMultipleFolderSelection:
+    case BookmarksContextBarMixedSelection:
       // Reset to start state, and then override with customizations that apply.
       [self setBookmarksContextBarSelectionStartState];
       [self.contextBar setButtonEnabled:YES forButton:ContextBarCenterButton];
@@ -1162,6 +1239,97 @@
   [self.contextBar setButtonEnabled:YES forButton:ContextBarTrailingButton];
 }
 
+#pragma mark - Context Menu
+
+- (UIAlertController*)contextMenuForMultipleBookmarkURLs {
+  UIAlertController* alert = [UIAlertController
+      alertControllerWithTitle:nil
+                       message:nil
+                preferredStyle:UIAlertControllerStyleActionSheet];
+  alert.view.accessibilityIdentifier = @"bookmark_context_menu";
+
+  UIAlertAction* cancelAction =
+      [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+                               style:UIAlertActionStyleCancel
+                             handler:nil];
+
+  UIAlertAction* openAllAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN)
+                style:UIAlertActionStyleDefault
+              handler:nil];
+
+  UIAlertAction* openInIncognitoAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(
+                          IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN_INCOGNITO)
+                style:UIAlertActionStyleDefault
+              handler:nil];
+
+  UIAlertAction* moveAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_CONTEXT_MENU_MOVE)
+                style:UIAlertActionStyleDefault
+              handler:nil];
+  [alert addAction:openAllAction];
+  [alert addAction:openInIncognitoAction];
+  [alert addAction:moveAction];
+  [alert addAction:cancelAction];
+  return alert;
+}
+
+- (UIAlertController*)contextMenuForSingleBookmarkURL {
+  UIAlertController* alert = [UIAlertController
+      alertControllerWithTitle:nil
+                       message:nil
+                preferredStyle:UIAlertControllerStyleActionSheet];
+  alert.view.accessibilityIdentifier = @"bookmark_context_menu";
+
+  UIAlertAction* cancelAction =
+      [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+                               style:UIAlertActionStyleCancel
+                             handler:nil];
+
+  UIAlertAction* editAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_CONTEXT_MENU_EDIT)
+                style:UIAlertActionStyleDefault
+              handler:nil];
+
+  UIAlertAction* copyAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_CONTEXT_MENU_COPY)
+                style:UIAlertActionStyleDefault
+              handler:nil];
+
+  UIAlertAction* openInIncognitoAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(
+                          IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN_INCOGNITO)
+                style:UIAlertActionStyleDefault
+              handler:nil];
+  [alert addAction:editAction];
+  [alert addAction:copyAction];
+  [alert addAction:openInIncognitoAction];
+  [alert addAction:cancelAction];
+  return alert;
+}
+
+- (UIAlertController*)contextMenuForMixedAndMultiFolderSelection {
+  UIAlertController* alert = [UIAlertController
+      alertControllerWithTitle:nil
+                       message:nil
+                preferredStyle:UIAlertControllerStyleActionSheet];
+  alert.view.accessibilityIdentifier = @"bookmark_context_menu";
+
+  UIAlertAction* cancelAction =
+      [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+                               style:UIAlertActionStyleCancel
+                             handler:nil];
+
+  UIAlertAction* moveAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_CONTEXT_MENU_MOVE)
+                style:UIAlertActionStyleDefault
+              handler:nil];
+  [alert addAction:moveAction];
+  [alert addAction:cancelAction];
+  return alert;
+}
+
 @end
 
 @implementation BookmarkHomeViewController (ExposedForTesting)
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h
index cc0ae89..4efc97db 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_protected.h
@@ -33,9 +33,11 @@
   BookmarksContextBarBeginSelection,  // This is the clean start state,
                                       // selection is possible, but nothing is
                                       // selected yet.
-  BookmarksContextBarSingleSelection,        // Single URL selected state.
-  BookmarksContextBarMultipleSelection,      // Multiple URL /Folders selected.
-  BookmarksContextBarSingleFolderSelection,  // Single folder selected.
+  BookmarksContextBarSingleURLSelection,       // Single URL selected state.
+  BookmarksContextBarMultipleURLSelection,     // Multiple URLs selected state.
+  BookmarksContextBarSingleFolderSelection,    // Single folder selected.
+  BookmarksContextBarMultipleFolderSelection,  // Multiple folders selected.
+  BookmarksContextBarMixedSelection,  // Multiple URL / Folders selected.
 };
 
 // BookmarkHomeViewController class extension for protected read/write
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
index 8ba2ed9..27b1515e0 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
@@ -492,6 +492,8 @@
 
 - (void)resetEditNodes {
   _editNodes.clear();
+  // Also update viewcontroler that the edit nodes changed.
+  [self.delegate bookmarkTableView:self selectedEditNodes:_editNodes];
 }
 
 // Removes the sign-in promo view.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
index 7919473..c93a3ad 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
@@ -406,6 +406,280 @@
       assertWithMatcher:grey_allOf(grey_notNil(), grey_enabled(), nil)];
 }
 
+- (void)testContextMenuForSingleURLSelection {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Change to edit mode
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          @"context_bar_trailing_button")]
+      performAction:grey_tap()];
+
+  // Select URL.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Second URL")]
+      performAction:grey_tap()];
+
+  // Tap context menu.
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarMoreString])]
+      performAction:grey_tap()];
+
+  // Verify it shows the context menu.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"bookmark_context_menu")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Verify options on context menu.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_EDIT)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_COPY)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  [[EarlGrey selectElementWithMatcher:
+                 ButtonWithAccessibilityLabelId(
+                     IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN_INCOGNITO)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
+- (void)testContextMenuForMultipleURLSelection {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Change to edit mode
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          @"context_bar_trailing_button")]
+      performAction:grey_tap()];
+
+  // Select URLs.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Second URL")]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"First URL")]
+      performAction:grey_tap()];
+
+  // Tap context menu.
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarMoreString])]
+      performAction:grey_tap()];
+
+  // Verify it shows the context menu.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"bookmark_context_menu")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Verify options on context menu.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  [[EarlGrey selectElementWithMatcher:
+                 ButtonWithAccessibilityLabelId(
+                     IDS_IOS_BOOKMARK_CONTEXT_MENU_OPEN_INCOGNITO)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_MOVE)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
+- (void)testContextMenuForSingleFolderSelection {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Change to edit mode
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          @"context_bar_trailing_button")]
+      performAction:grey_tap()];
+
+  // Select URL.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Folder 1")]
+      performAction:grey_tap()];
+
+  // Center button is "Edit".
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarEditString])]
+      assertWithMatcher:grey_allOf(grey_notNil(), grey_enabled(), nil)];
+
+  [[EarlGrey
+      selectElementWithMatcher:ButtonWithAccessibilityLabelId(IDS_CANCEL)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Tap Edit menu.
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarEditString])]
+      performAction:grey_tap()];
+
+  // Verify it shows edit view controller.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Editor")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
+- (void)testContextMenuForMultipleFolderSelection {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Change to edit mode
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          @"context_bar_trailing_button")]
+      performAction:grey_tap()];
+
+  // Select Folders.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Folder 1")]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Folder 1.1")]
+      performAction:grey_tap()];
+
+  // Tap context menu.
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarMoreString])]
+      performAction:grey_tap()];
+
+  // Verify it shows the context menu.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"bookmark_context_menu")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Verify options on context menu.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_MOVE)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
+- (void)testContextMenuForMixedSelection {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Change to edit mode
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          @"context_bar_trailing_button")]
+      performAction:grey_tap()];
+
+  // Select URL and folder.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Second URL")]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Folder 1")]
+      performAction:grey_tap()];
+
+  // Tap context menu.
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarMoreString])]
+      performAction:grey_tap()];
+
+  // Verify it shows the context menu.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityID(@"bookmark_context_menu")]
+      assertWithMatcher:grey_sufficientlyVisible()];
+
+  // Verify options on context menu.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_CONTEXT_MENU_MOVE)]
+      assertWithMatcher:grey_sufficientlyVisible()];
+}
+
+// Try deleting a bookmark from the edit screen, then undoing that delete.
+- (void)testUndoDeleteBookmarkFromEditScreen {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  [BookmarksNewGenTestCase openMobileBookmarks];
+
+  // Change to edit mode
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          @"context_bar_trailing_button")]
+      performAction:grey_tap()];
+
+  // Select Folder.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"Folder 1")]
+      performAction:grey_tap()];
+
+  // Tap edit on context bar.
+  [[EarlGrey selectElementWithMatcher:ContextBarCenterButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarEditString])]
+      performAction:grey_tap()];
+
+  // Delete it.
+  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
+                                          IDS_IOS_BOOKMARK_GROUP_DELETE)]
+      performAction:grey_tap()];
+
+  // Wait until it's gone.
+  ConditionBlock condition = ^{
+    NSError* error = nil;
+    [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder 1")]
+        assertWithMatcher:grey_notVisible()
+                    error:&error];
+    return error == nil;
+  };
+  GREYAssert(testing::WaitUntilConditionOrTimeout(10, condition),
+             @"Waiting for bookmark to go away");
+
+  // Press undo
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Undo")]
+      performAction:grey_tap()];
+
+  // Verify it's back.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder 1")]
+      assertWithMatcher:grey_notNil()];
+
+  // Verify Delete is disabled.
+  [[EarlGrey selectElementWithMatcher:ContextBarLeadingButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarDeleteString])]
+      assertWithMatcher:grey_allOf(grey_notNil(),
+                                   grey_accessibilityTrait(
+                                       UIAccessibilityTraitNotEnabled),
+                                   nil)];
+}
+
 - (void)testDeleteSingleURLNode {
   if (IsIPadIdiom()) {
     EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
@@ -443,6 +717,15 @@
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Second URL")]
       assertWithMatcher:grey_notNil()];
 
+  // Verify Delete is disabled.
+  [[EarlGrey selectElementWithMatcher:ContextBarLeadingButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarDeleteString])]
+      assertWithMatcher:grey_allOf(grey_notNil(),
+                                   grey_accessibilityTrait(
+                                       UIAccessibilityTraitNotEnabled),
+                                   nil)];
+
   // Cancel edit mode.
   [[EarlGrey selectElementWithMatcher:ContextBarTrailingButtonWithLabel(
                                           [BookmarksNewGenTestCase
@@ -487,6 +770,15 @@
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder 1")]
       assertWithMatcher:grey_notNil()];
 
+  // Verify Delete is disabled.
+  [[EarlGrey selectElementWithMatcher:ContextBarLeadingButtonWithLabel(
+                                          [BookmarksNewGenTestCase
+                                              contextBarDeleteString])]
+      assertWithMatcher:grey_allOf(grey_notNil(),
+                                   grey_accessibilityTrait(
+                                       UIAccessibilityTraitNotEnabled),
+                                   nil)];
+
   // Cancel edit mode.
   [[EarlGrey selectElementWithMatcher:ContextBarTrailingButtonWithLabel(
                                           [BookmarksNewGenTestCase
@@ -814,6 +1106,9 @@
   NSString* folderTitle = @"Folder 1";
   const bookmarks::BookmarkNode* folder1 = bookmark_model->AddFolder(
       bookmark_model->mobile_node(), 0, base::SysNSStringToUTF16(folderTitle));
+  folderTitle = @"Folder 1.1";
+  bookmark_model->AddFolder(bookmark_model->mobile_node(), 0,
+                            base::SysNSStringToUTF16(folderTitle));
 
   folderTitle = @"Folder 2";
   const bookmarks::BookmarkNode* folder2 = bookmark_model->AddFolder(
diff --git a/ios/chrome/browser/ui/browser_view_controller.h b/ios/chrome/browser/ui/browser_view_controller.h
index cf8b3f5f..34c2682 100644
--- a/ios/chrome/browser/ui/browser_view_controller.h
+++ b/ios/chrome/browser/ui/browser_view_controller.h
@@ -20,7 +20,6 @@
 @protocol BrowserCommands;
 @class BrowserContainerView;
 @class BrowserViewControllerDependencyFactory;
-@protocol ChromeExecuteCommand;
 class GURL;
 @class Tab;
 @class TabModel;
@@ -64,7 +63,6 @@
 
 @property(nonatomic, readonly) id<ApplicationCommands,
                                   BrowserCommands,
-                                  ChromeExecuteCommand,
                                   OmniboxFocuser,
                                   UrlLoader,
                                   WebToolbarDelegate>
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 6da6db3..90ae2af4b 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -134,6 +134,8 @@
 #import "ios/chrome/browser/ui/history_popup/requirements/tab_history_presentation.h"
 #import "ios/chrome/browser/ui/history_popup/tab_history_legacy_coordinator.h"
 #import "ios/chrome/browser/ui/key_commands_provider.h"
+#import "ios/chrome/browser/ui/ntp/incognito_view_controller.h"
+#import "ios/chrome/browser/ui/ntp/modal_ntp.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_controller.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_coordinator.h"
 #include "ios/chrome/browser/ui/omnibox/page_info_model.h"
@@ -148,6 +150,7 @@
 #import "ios/chrome/browser/ui/reading_list/reading_list_coordinator.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_menu_notifier.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
+#import "ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h"
 #import "ios/chrome/browser/ui/side_swipe/side_swipe_controller.h"
 #import "ios/chrome/browser/ui/stack_view/card_view.h"
 #import "ios/chrome/browser/ui/stack_view/page_animation_util.h"
@@ -170,6 +173,7 @@
 #import "ios/chrome/browser/web/error_page_content.h"
 #import "ios/chrome/browser/web/passkit_dialog_provider.h"
 #import "ios/chrome/browser/web/repost_form_tab_helper.h"
+#import "ios/chrome/browser/web/sad_tab_tab_helper.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
@@ -355,6 +359,7 @@
                                     CRWWebStateDelegate,
                                     DialogPresenterDelegate,
                                     FullScreenControllerDelegate,
+                                    IncognitoViewControllerDelegate,
                                     IOSCaptivePortalBlockingPageDelegate,
                                     KeyCommandsPlumbing,
                                     MFMailComposeViewControllerDelegate,
@@ -537,6 +542,9 @@
 
   // Coordinator for Tab History Popup.
   LegacyTabHistoryCoordinator* _tabHistoryCoordinator;
+
+  // Coordinator for displaying Sad Tab.
+  SadTabLegacyCoordinator* _sadTabCoordinator;
 }
 
 // The browser's side swipe controller.  Lazily instantiated on the first call.
@@ -973,8 +981,6 @@
     [_dispatcher startDispatchingToTarget:self
                               forProtocol:@protocol(WebToolbarDelegate)];
     [_dispatcher startDispatchingToTarget:self
-                              forSelector:@selector(chromeExecuteCommand:)];
-    [_dispatcher startDispatchingToTarget:self
                               forProtocol:@protocol(BrowserCommands)];
     [_dispatcher startDispatchingToTarget:applicationCommandEndpoint
                               forProtocol:@protocol(ApplicationCommands)];
@@ -1032,13 +1038,11 @@
 
 - (id<ApplicationCommands,
       BrowserCommands,
-      ChromeExecuteCommand,
       OmniboxFocuser,
       UrlLoader,
       WebToolbarDelegate>)dispatcher {
-  return static_cast<
-      id<ApplicationCommands, BrowserCommands, ChromeExecuteCommand,
-         OmniboxFocuser, UrlLoader, WebToolbarDelegate>>(_dispatcher);
+  return static_cast<id<ApplicationCommands, BrowserCommands, OmniboxFocuser,
+                        UrlLoader, WebToolbarDelegate>>(_dispatcher);
 }
 
 - (void)setActive:(BOOL)active {
@@ -1590,8 +1594,16 @@
   // iPhones, this will get executed after the animation has finished.
   if (IsIPadIdiom()) {
     if (self.foregroundTabWasAddedCompletionBlock) {
-      self.foregroundTabWasAddedCompletionBlock();
-      self.foregroundTabWasAddedCompletionBlock = nil;
+      // This callback is called before webState is activated (on
+      // kTabModelNewTabWillOpenNotification notification). Dispatch the
+      // callback asynchronously to be sure the activation is complete.
+      dispatch_async(dispatch_get_main_queue(), ^() {
+        // Test existence again as the block may have been deleted.
+        if (self.foregroundTabWasAddedCompletionBlock) {
+          self.foregroundTabWasAddedCompletionBlock();
+          self.foregroundTabWasAddedCompletionBlock = nil;
+        }
+      });
     }
     return;
   }
@@ -1735,9 +1747,7 @@
 
 - (void)browserStateDestroyed {
   [self setActive:NO];
-  // Reset the toolbar opacity in case it was changed for contextual search.
-  [self updateToolbarControlsAlpha:1.0];
-  [self updateToolbarBackgroundAlpha:1.0];
+  [self setToolbarBackgroundAlpha:1.0];
   [_paymentRequestManager close];
   _paymentRequestManager = nil;
   [_toolbarController browserStateDestroyed];
@@ -1867,6 +1877,9 @@
   _tabHistoryCoordinator.presentationProvider = self;
   _tabHistoryCoordinator.tabHistoryUIUpdater = _toolbarController;
 
+  _sadTabCoordinator = [[SadTabLegacyCoordinator alloc] init];
+  _sadTabCoordinator.dispatcher = _dispatcher;
+
   if (base::FeatureList::IsEnabled(payments::features::kWebPayments)) {
     _paymentRequestManager = [[PaymentRequestManager alloc]
         initWithBaseViewController:self
@@ -2346,6 +2359,9 @@
   if (tabHelper)
     tabHelper->SetLauncher(self);
   tab.webState->SetDelegate(_webStateDelegate.get());
+  // BrowserViewController owns the coordinator that displays the Sad Tab.
+  if (!SadTabTabHelper::FromWebState(tab.webState))
+    SadTabTabHelper::CreateForWebState(tab.webState, _sadTabCoordinator);
 }
 
 - (void)uninstallDelegatesForTab:(Tab*)tab {
@@ -3266,7 +3282,7 @@
                                       ntpObserver:self
                                      browserState:_browserState
                                        colorCache:_dominantColorCache
-                               webToolbarDelegate:self
+                                  toolbarDelegate:self
                                          tabModel:_model
                              parentViewController:self
                                        dispatcher:self.dispatcher];
@@ -3855,16 +3871,6 @@
   return [[_model currentTab] webState];
 }
 
-// This is called from within an animation block.
-- (void)toolbarHeightChanged {
-  if ([self headerHeight] != 0) {
-    // Ensure full screen height is updated.
-    Tab* currentTab = [_model currentTab];
-    BOOL visible = self.isToolbarOnScreen;
-    [currentTab updateFullscreenWithToolbarVisible:visible];
-  }
-}
-
 // Load a new URL on a new page/tab.
 - (void)webPageOrderedOpen:(const GURL&)URL
                   referrer:(const web::Referrer&)referrer
@@ -3996,22 +4002,10 @@
   }
 }
 
-- (IBAction)prepareToEnterTabSwitcher:(id)sender {
-  [[_model currentTab] updateSnapshotWithOverlay:YES visibleFrameOnly:YES];
-}
-
 - (ToolbarModelIOS*)toolbarModelIOS {
   return _toolbarModelIOS.get();
 }
 
-- (void)updateToolbarBackgroundAlpha:(CGFloat)alpha {
-  [_toolbarController setBackgroundAlpha:alpha];
-}
-
-- (void)updateToolbarControlsAlpha:(CGFloat)alpha {
-  [_toolbarController setControlsAlpha:alpha];
-}
-
 - (void)willUpdateToolbarSnapshot {
   [[_model currentTab].overscrollActionsController clear];
 }
@@ -4423,7 +4417,7 @@
 }
 
 - (void)showBookmarksManager {
-  if (IsIPadIdiom()) {
+  if (!PresentNTPPanelModally()) {
     [self showAllBookmarks];
   } else {
     [self initializeBookmarkInteractionController];
@@ -4432,7 +4426,7 @@
 }
 
 - (void)showRecentTabs {
-  if (IsIPadIdiom()) {
+  if (!PresentNTPPanelModally()) {
     [self showNTPPanel:ntp_home::RECENT_TABS_PANEL];
   } else {
     if (!self.recentTabsCoordinator) {
@@ -4446,6 +4440,14 @@
   }
 }
 
+- (void)requestDesktopSite {
+  [[_model currentTab] reloadWithUserAgentType:web::UserAgentType::DESKTOP];
+}
+
+- (void)requestMobileSite {
+  [[_model currentTab] reloadWithUserAgentType:web::UserAgentType::MOBILE];
+}
+
 #pragma mark - Command Handling
 
 - (IBAction)chromeExecuteCommand:(id)sender {
@@ -4458,12 +4460,6 @@
     case IDC_SHOW_MAIL_COMPOSER:
       [self showMailComposer:sender];
       break;
-    case IDC_REQUEST_DESKTOP_SITE:
-      [[_model currentTab] reloadWithUserAgentType:web::UserAgentType::DESKTOP];
-      break;
-    case IDC_REQUEST_MOBILE_SITE:
-      [[_model currentTab] reloadWithUserAgentType:web::UserAgentType::MOBILE];
-      break;
     default:
       // Unknown commands get sent up the responder chain.
       [super chromeExecuteCommand:sender];
@@ -4739,6 +4735,10 @@
 
   [_paymentRequestManager setActiveWebState:newTab.webState];
 
+  // Update the Sad Tab coordinator webstate so it matches the current tab
+  // webstate.
+  _sadTabCoordinator.webState = newTab.webState;
+
   [self tabSelected:newTab];
   DCHECK_EQ(newTab, [model currentTab]);
   [self installDelegatesForTab:newTab];
@@ -5085,6 +5085,12 @@
   _rateThisAppDialog = nil;
 }
 
+#pragma mark - IncognitoViewControllerDelegate
+
+- (void)setToolbarBackgroundAlpha:(CGFloat)alpha {
+  [_toolbarController setBackgroundAlpha:alpha];
+}
+
 #pragma mark - VoiceSearchBarDelegate
 
 - (BOOL)isTTSEnabledForVoiceSearchBar:(id<VoiceSearchBar>)voiceSearchBar {
diff --git a/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h b/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h
index 67e6b1c..50c31f2 100644
--- a/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h
+++ b/ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h
@@ -20,11 +20,4 @@
 - (void)chromeExecuteCommand:(id)sender;
 @end
 
-@protocol ChromeExecuteCommand
-// Executes a Chrome command.  |sender| must implement the |-tag| method and
-// return the id of the command to execute.  The default implementation of this
-// method simply forwards the call to the next responder.
-- (IBAction)chromeExecuteCommand:(id)sender;
-@end
-
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_UIKIT_CHROMEEXECUTECOMMAND_H_
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h
index b65a511..334545e 100644
--- a/ios/chrome/browser/ui/commands/browser_commands.h
+++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -107,6 +107,12 @@
 // Shows recent tabs.
 - (void)showRecentTabs;
 
+// Requests the "desktop" version of the current page in the active tab.
+- (void)requestDesktopSite;
+
+// Requests the "mobile" version of the current page in the active tab.
+- (void)requestMobileSite;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index 1c0429f..ced3795 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -16,8 +16,6 @@
 #define IDC_SHOW_SIGNIN_IOS                            40905
 #define IDC_SHOW_ADD_ACCOUNT                           40910
 #define IDC_SHOW_SYNC_SETTINGS                         40914
-#define IDC_REQUEST_DESKTOP_SITE                       40921
-#define IDC_REQUEST_MOBILE_SITE                        40922
 #define IDC_CLEAR_BROWSING_DATA_IOS                    40924
 #define IDC_SHOW_MAIL_COMPOSER                         40926
 #define IDC_SHOW_SYNC_PASSPHRASE_SETTINGS              40952
diff --git a/ios/chrome/browser/ui/coordinators/browser_coordinator+internal.h b/ios/chrome/browser/ui/coordinators/browser_coordinator+internal.h
index 5244d57..b6e0c2b6 100644
--- a/ios/chrome/browser/ui/coordinators/browser_coordinator+internal.h
+++ b/ios/chrome/browser/ui/coordinators/browser_coordinator+internal.h
@@ -9,17 +9,6 @@
 
 // Internal API for subclasses and categories of BrowserCoordinator.
 
-// Enum for defining the "mode" of the coordinator -- the way that its view
-// controller is positioned in the view controller hierarchy. There's no
-// property in the base class for this value, but subclasses may define a 'mode'
-// property if they need to vary behavior or configuration based on the mode. In
-// that case, the default should always be UNDEFINED.
-typedef NS_ENUM(NSInteger, BrowserCoordinatorMode) {
-  UNDEFINED = 0,
-  PRESENTED,  // The view controller is presented.
-  CONTAINED   // The view controller is contained.
-};
-
 // This API can be used to create and manage 'overlay coordinators'.
 // Overlay coordinators are intended to be used for UI elements that
 // sit on top of the regular UI, and which may need to be dismissed
diff --git a/ios/chrome/browser/ui/coordinators/browser_coordinator.h b/ios/chrome/browser/ui/coordinators/browser_coordinator.h
index c7fa248..17e30588 100644
--- a/ios/chrome/browser/ui/coordinators/browser_coordinator.h
+++ b/ios/chrome/browser/ui/coordinators/browser_coordinator.h
@@ -9,6 +9,17 @@
 
 class Browser;
 
+// Enum for defining the "mode" of the coordinator -- the way that its view
+// controller is positioned in the view controller hierarchy. There's no
+// property in the base class for this value, but subclasses may define a 'mode'
+// property if they need to vary behavior or configuration based on the mode. In
+// that case, the default should always be UNDEFINED.
+typedef NS_ENUM(NSInteger, BrowserCoordinatorMode) {
+  UNDEFINED = 0,
+  PRESENTED,  // The view controller is presented.
+  CONTAINED   // The view controller is contained.
+};
+
 // An object that manages a UI component via a view controller.
 // This is the public interface to this class; subclasses should also import
 // the Internal category header (browser_coordinator+internal.h). This header
diff --git a/ios/chrome/browser/ui/coordinators/browser_coordinator_test.h b/ios/chrome/browser/ui/coordinators/browser_coordinator_test.h
index 4a7ff60..073872d 100644
--- a/ios/chrome/browser/ui/coordinators/browser_coordinator_test.h
+++ b/ios/chrome/browser/ui/coordinators/browser_coordinator_test.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/macros.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/platform_test.h"
 
@@ -22,8 +23,10 @@
 
  private:
   base::test::ScopedTaskEnvironment task_environment_;
-  std::unique_ptr<Browser> browser_;
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+  std::unique_ptr<Browser> browser_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserCoordinatorTest);
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_COORDINATORS_BROWSER_COORDINATOR_TEST_H_
diff --git a/ios/chrome/browser/ui/coordinators/browser_coordinator_test.mm b/ios/chrome/browser/ui/coordinators/browser_coordinator_test.mm
index bb4441b..85277aa 100644
--- a/ios/chrome/browser/ui/coordinators/browser_coordinator_test.mm
+++ b/ios/chrome/browser/ui/coordinators/browser_coordinator_test.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/coordinators/browser_coordinator_test.h"
 
-#include "base/memory/ptr_util.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/ui/browser_list/browser.h"
 
@@ -14,9 +13,8 @@
 
 BrowserCoordinatorTest::BrowserCoordinatorTest() {
   // Initialize the browser.
-  TestChromeBrowserState::Builder builder;
-  chrome_browser_state_ = builder.Build();
-  browser_ = base::MakeUnique<Browser>(chrome_browser_state_.get());
+  chrome_browser_state_ = TestChromeBrowserState::Builder().Build();
+  browser_ = std::make_unique<Browser>(chrome_browser_state_.get());
 }
 
 BrowserCoordinatorTest::~BrowserCoordinatorTest() = default;
diff --git a/ios/chrome/browser/ui/history/history_collection_view_controller.mm b/ios/chrome/browser/ui/history/history_collection_view_controller.mm
index fd8c1fe..0624b30 100644
--- a/ios/chrome/browser/ui/history/history_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_collection_view_controller.mm
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "base/mac/foundation_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
@@ -85,6 +86,8 @@
   __weak id<HistoryCollectionViewControllerDelegate> _delegate;
   // Backing ivar for URLLoader property.
   __weak id<UrlLoader> _URLLoader;
+  // Closure to request next page of history.
+  base::OnceClosure _query_history_continuation;
 }
 
 // Object to manage insertion of history entries into the collection view model.
@@ -112,10 +115,11 @@
 // YES if the collection should be filtered by the next received query result.
 @property(nonatomic, assign) BOOL filterQueryResult;
 
-// Fetches history prior to |time| for search text |query|. If |query| is nil or
-// the empty string, all history is fetched.
-- (void)fetchHistoryForQuery:(NSString*)query
-                 priorToTime:(const base::Time&)time;
+// Fetches history for search text |query|. If |query| is nil or the empty
+// string, all history is fetched. If continuation is false, then the most
+// recent results are fetched, otherwise the results more recent than the
+// previous query will be returned.
+- (void)fetchHistoryForQuery:(NSString*)query continuation:(BOOL)continuation;
 // Updates header section to provide relevant information about the currently
 // displayed history entries.
 - (void)updateEntriesStatusMessage;
@@ -224,7 +228,7 @@
 - (void)showHistoryMatchingQuery:(NSString*)query {
   self.finishedLoading = NO;
   self.currentQuery = query;
-  [self fetchHistoryForQuery:query priorToTime:base::Time::Now()];
+  [self fetchHistoryForQuery:query continuation:false];
 }
 
 - (void)deleteSelectedItemsFromHistory {
@@ -337,8 +341,10 @@
             (const std::vector<BrowsingHistoryService::HistoryEntry>&)results
                   queryResultsInfo:
                       (const BrowsingHistoryService::QueryResultsInfo&)
-                          queryResultsInfo {
+                          queryResultsInfo
+               continuationClosure:(base::OnceClosure)continuationClosure {
   self.loading = NO;
+  _query_history_continuation = std::move(continuationClosure);
 
   // If history sync is enabled and there hasn't been a response from synced
   // history, try fetching again.
@@ -360,9 +366,7 @@
     return;
   }
 
-  self.finishedLoading = queryResultsInfo.reached_beginning_of_local &&
-                         (!queryResultsInfo.has_synced_results ||
-                          queryResultsInfo.reached_beginning_of_sync);
+  self.finishedLoading = queryResultsInfo.reached_beginning;
   self.entriesType =
       queryResultsInfo.has_synced_results ? SYNCED_ENTRIES : LOCAL_ENTRIES;
 
@@ -546,36 +550,38 @@
     if (lastSection == 0 || lastItemIndex < 0) {
       return;
     }
-    NSIndexPath* indexPath =
-        [NSIndexPath indexPathForItem:lastItemIndex inSection:lastSection];
-    HistoryEntryItem* lastItem = base::mac::ObjCCastStrict<HistoryEntryItem>(
-        [self.collectionViewModel itemAtIndexPath:indexPath]);
-    [self fetchHistoryForQuery:_currentQuery priorToTime:lastItem.timestamp];
+
+    [self fetchHistoryForQuery:_currentQuery continuation:true];
   }
 }
 
 #pragma mark - Private methods
 
-- (void)fetchHistoryForQuery:(NSString*)query
-                 priorToTime:(const base::Time&)time {
+- (void)fetchHistoryForQuery:(NSString*)query continuation:(BOOL)continuation {
   self.loading = YES;
   // Add loading indicator if no items are shown.
   if (!self.hasHistoryEntries && !self.isSearching) {
     [self addLoadingIndicator];
   }
 
-  BOOL fetchAllHistory = !query || [query isEqualToString:@""];
-  base::string16 queryString =
-      fetchAllHistory ? base::string16() : base::SysNSStringToUTF16(query);
-  history::QueryOptions options;
-  options.end_time = time;
-  options.duplicate_policy =
-      fetchAllHistory ? history::QueryOptions::REMOVE_DUPLICATES_PER_DAY
-                      : history::QueryOptions::REMOVE_ALL_DUPLICATES;
-  options.max_count = kMaxFetchCount;
-  options.matching_algorithm =
-      query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH;
-  _browsingHistoryService->QueryHistory(queryString, options);
+  if (continuation) {
+    DCHECK(_query_history_continuation);
+    std::move(_query_history_continuation).Run();
+  } else {
+    _query_history_continuation.Reset();
+
+    BOOL fetchAllHistory = !query || [query isEqualToString:@""];
+    base::string16 queryString =
+        fetchAllHistory ? base::string16() : base::SysNSStringToUTF16(query);
+    history::QueryOptions options;
+    options.duplicate_policy =
+        fetchAllHistory ? history::QueryOptions::REMOVE_DUPLICATES_PER_DAY
+                        : history::QueryOptions::REMOVE_ALL_DUPLICATES;
+    options.max_count = kMaxFetchCount;
+    options.matching_algorithm =
+        query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH;
+    _browsingHistoryService->QueryHistory(queryString, options);
+  }
 }
 
 - (void)updateEntriesStatusMessage {
diff --git a/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm
index 3b264ce..71924b8a 100644
--- a/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/history/history_collection_view_controller_unittest.mm
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #import "base/test/ios/wait_util.h"
@@ -102,10 +103,11 @@
     std::vector<BrowsingHistoryService::HistoryEntry> results =
         QueryResultWithVisits(visits);
     BrowsingHistoryService::QueryResultsInfo query_results_info;
-    query_results_info.reached_beginning_of_local = true;
+    query_results_info.reached_beginning = true;
     [history_collection_view_controller_
         onQueryCompleteWithResults:results
-                  queryResultsInfo:query_results_info];
+                  queryResultsInfo:query_results_info
+               continuationClosure:base::OnceClosure()];
   }
 
  protected:
diff --git a/ios/chrome/browser/ui/history/ios_browsing_history_driver.h b/ios/chrome/browser/ui/history/ios_browsing_history_driver.h
index e625c1e4c..c5d7857 100644
--- a/ios/chrome/browser/ui/history/ios_browsing_history_driver.h
+++ b/ios/chrome/browser/ui/history/ios_browsing_history_driver.h
@@ -31,7 +31,8 @@
                 results
                   queryResultsInfo:
                       (const history::BrowsingHistoryService::QueryResultsInfo&)
-                          queryResultsInfo;
+                          queryResultsInfo
+               continuationClosure:(base::OnceClosure)continuationClosure;
 
 // Notifies the delegate that history entries have been deleted by a different
 // client and that the UI should be updated.
@@ -56,7 +57,8 @@
   void OnQueryComplete(
       const std::vector<history::BrowsingHistoryService::HistoryEntry>& results,
       const history::BrowsingHistoryService::QueryResultsInfo&
-          query_results_info) override;
+          query_results_info,
+      base::OnceClosure continuation_closure) override;
   void OnRemoveVisitsComplete() override;
   void OnRemoveVisitsFailed() override;
   void OnRemoveVisits(
diff --git a/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm b/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm
index 01a3770f..cde9ee3 100644
--- a/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm
+++ b/ios/chrome/browser/ui/history/ios_browsing_history_driver.mm
@@ -37,9 +37,11 @@
 
 void IOSBrowsingHistoryDriver::OnQueryComplete(
     const std::vector<BrowsingHistoryService::HistoryEntry>& results,
-    const BrowsingHistoryService::QueryResultsInfo& query_results_info) {
+    const BrowsingHistoryService::QueryResultsInfo& query_results_info,
+    base::OnceClosure continuation_closure) {
   [delegate_ onQueryCompleteWithResults:results
-                       queryResultsInfo:query_results_info];
+                       queryResultsInfo:query_results_info
+                    continuationClosure:std::move(continuation_closure)];
 }
 
 void IOSBrowsingHistoryDriver::OnRemoveVisitsComplete() {
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index 9853e9c..d29f338c 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -80,8 +80,12 @@
     "google_landing_mediator.mm",
     "google_landing_view_controller.h",
     "google_landing_view_controller.mm",
-    "incognito_panel_controller.h",
-    "incognito_panel_controller.mm",
+    "incognito_view.h",
+    "incognito_view.mm",
+    "incognito_view_controller.h",
+    "incognito_view_controller.mm",
+    "modal_ntp.h",
+    "modal_ntp.mm",
     "most_visited_cell.h",
     "most_visited_cell.mm",
     "most_visited_layout.h",
@@ -159,6 +163,7 @@
     "//components/suggestions",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/bookmarks:features",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/history",
diff --git a/ios/chrome/browser/ui/ntp/google_landing_mediator.h b/ios/chrome/browser/ui/ntp/google_landing_mediator.h
index b25f0c7..23e80ce4 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_mediator.h
+++ b/ios/chrome/browser/ui/ntp/google_landing_mediator.h
@@ -10,7 +10,6 @@
 #import "ios/chrome/browser/ui/ntp/google_landing_data_source.h"
 #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
 
-@protocol ChromeExecuteCommand;
 @protocol GoogleLandingConsumer;
 @protocol OmniboxFocuser;
 @protocol UrlLoader;
@@ -33,9 +32,7 @@
 @property(nonatomic, weak, nullable) id<GoogleLandingConsumer> consumer;
 
 // The dispatcher for this mediator.
-@property(nonatomic, weak, nullable)
-    id<BrowserCommands, ChromeExecuteCommand, UrlLoader>
-        dispatcher;
+@property(nonatomic, weak, nullable) id<BrowserCommands, UrlLoader> dispatcher;
 
 // Perform initial setup. Needs to be called before using this object.
 - (void)setUp;
diff --git a/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
index 576c4b1..3bb4a6e 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
@@ -10,7 +10,6 @@
 #include "base/metrics/user_metrics.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
diff --git a/ios/chrome/browser/ui/ntp/incognito_panel_controller.h b/ios/chrome/browser/ui/ntp/incognito_panel_controller.h
deleted file mode 100644
index 14a993f..0000000
--- a/ios/chrome/browser/ui/ntp/incognito_panel_controller.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_PANEL_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_PANEL_CONTROLLER_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/ntp/new_tab_page_panel_protocol.h"
-
-namespace ios {
-class ChromeBrowserState;
-}
-
-@protocol UrlLoader;
-@protocol WebToolbarDelegate;
-
-@interface IncognitoPanelController : NSObject<NewTabPagePanelProtocol>
-
-// The view that is displaying the incognito* panel.
-@property(nonatomic, readonly) UIView* view;
-
-// Init with the given loader object. |loader| may be nil, but isn't
-// retained so it must outlive this controller. |browserState| may not be null.
-// |webToolbarDelegate| is used to fade the toolbar views on page scroll.
-- (id)initWithLoader:(id<UrlLoader>)loader
-          browserState:(ios::ChromeBrowserState*)browserState
-    webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_PANEL_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm b/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
deleted file mode 100644
index 3547604..0000000
--- a/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
+++ /dev/null
@@ -1,352 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/ntp/incognito_panel_controller.h"
-
-#include <string>
-
-#include "components/google/core/browser/google_util.h"
-#include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/application_context.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
-#include "ios/chrome/browser/ui/ui_util.h"
-#import "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/chrome/browser/ui/url_loader.h"
-#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.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 "ios/web/public/referrer.h"
-#import "net/base/mac/url_conversions.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// The URL for the the Learn More page shown on incognito new tab.
-// Taken from ntp_resource_cache.cc.
-const char kLearnMoreIncognitoUrl[] =
-    "https://www.google.com/support/chrome/bin/answer.py?answer=95464";
-
-GURL GetUrlWithLang(const GURL& url) {
-  std::string locale = GetApplicationContext()->GetApplicationLocale();
-  return google_util::AppendGoogleLocaleParam(url, locale);
-}
-
-const CGFloat kDistanceToFadeToolbar = 50.0;
-const int kLinkColor = 0x03A9F4;
-}
-
-// The scrollview containing the views. Its content's size is constrained on its
-// superview's size.
-@interface IncognitoNTPView : UIScrollView
-
-// Returns an autoreleased label with the right format.
-- (UILabel*)labelWithString:(NSString*)string
-                       font:(UIFont*)font
-                      alpha:(float)alpha;
-
-// Triggers a navigation to the help page.
-- (void)learnMoreButtonPressed;
-
-@end
-
-@implementation IncognitoNTPView {
-  __weak id<UrlLoader> _loader;
-  UIView* _containerView;
-
-  // Constraint ensuring that |containerView| is at least as high as the
-  // superview of the IncognitoNTPView, i.e. the Incognito panel.
-  // This ensures that if the Incognito panel is higher than a compact
-  // |containerView|, the |containerView|'s |topGuide| and |bottomGuide| are
-  // forced to expand, centering the views in between them.
-  NSLayoutConstraint* _containerVerticalConstraint;
-
-  // Constraint ensuring that |containerView| is as wide as the superview of the
-  // the IncognitoNTPView, i.e. the Incognito panel.
-  NSLayoutConstraint* _containerHorizontalConstraint;
-}
-
-- (instancetype)initWithFrame:(CGRect)frame urlLoader:(id<UrlLoader>)loader {
-  self = [super initWithFrame:frame];
-  if (self) {
-    _loader = loader;
-
-    self.alwaysBounceVertical = YES;
-
-    // Container in which all the subviews (image, labels, button) are added.
-    _containerView = [[UIView alloc] initWithFrame:frame];
-    [_containerView setTranslatesAutoresizingMaskIntoConstraints:NO];
-
-    // Incognito image.
-    UIImageView* incognitoImage = [[UIImageView alloc]
-        initWithImage:[UIImage imageNamed:@"incognito_icon"]];
-    [incognitoImage setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_containerView addSubview:incognitoImage];
-
-    // Title.
-    UIFont* titleFont = [[MDCTypography fontLoader] lightFontOfSize:24];
-    UILabel* incognitoTabHeading =
-        [self labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_HEADING)
-                         font:titleFont
-                        alpha:0.8];
-    [_containerView addSubview:incognitoTabHeading];
-
-    // Description paragraph.
-    UIFont* regularFont = [[MDCTypography fontLoader] regularFontOfSize:14];
-    UILabel* incognitoTabDescription = [self
-        labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_DESCRIPTION)
-                   font:regularFont
-                  alpha:0.7];
-    [_containerView addSubview:incognitoTabDescription];
-
-    // Warning paragraph.
-    UILabel* incognitoTabWarning = [self
-        labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_MESSAGE_WARNING)
-                   font:regularFont
-                  alpha:0.7];
-    [_containerView addSubview:incognitoTabWarning];
-
-    // Learn more button.
-    MDCButton* learnMore = [[MDCFlatButton alloc] init];
-    UIColor* inkColor =
-        [[[MDCPalette greyPalette] tint300] colorWithAlphaComponent:0.25];
-    [learnMore setInkColor:inkColor];
-    [learnMore setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [learnMore setTitle:l10n_util::GetNSString(IDS_NEW_TAB_OTR_LEARN_MORE_LINK)
-               forState:UIControlStateNormal];
-    [learnMore setTitleColor:UIColorFromRGB(kLinkColor)
-                    forState:UIControlStateNormal];
-    UIFont* buttonFont = [[MDCTypography fontLoader] boldFontOfSize:14];
-    [[learnMore titleLabel] setFont:buttonFont];
-    [learnMore addTarget:self
-                  action:@selector(learnMoreButtonPressed)
-        forControlEvents:UIControlEventTouchUpInside];
-    [_containerView addSubview:learnMore];
-
-    // |topGuide| and |bottomGuide| exist to vertically center the sibling views
-    // located in between them.
-    UILayoutGuide* topGuide = [[UILayoutGuide alloc] init];
-    UILayoutGuide* bottomGuide = [[UILayoutGuide alloc] init];
-    [_containerView addLayoutGuide:topGuide];
-    [_containerView addLayoutGuide:bottomGuide];
-
-    NSDictionary* viewsDictionary = @{
-      @"topGuide" : topGuide,
-      @"image" : incognitoImage,
-      @"heading" : incognitoTabHeading,
-      @"description" : incognitoTabDescription,
-      @"warning" : incognitoTabWarning,
-      @"learnMoreButton" : learnMore,
-      @"bottomGuide" : bottomGuide,
-    };
-    NSArray* constraints = @[
-      @"V:|-0-[topGuide(>=12)]-[image]-24-[heading]-32-[description]",
-      @"V:[description]-32-[warning]-32-[learnMoreButton]",
-      @"V:[learnMoreButton]-[bottomGuide]-0-|",
-      @"H:|-(>=24)-[heading]-(>=24)-|",
-      @"H:|-(>=24)-[description(==416@999)]-(>=24)-|",
-      @"H:|-(>=24)-[warning(==416@999)]-(>=24)-|"
-    ];
-    ApplyVisualConstraintsWithOptions(constraints, viewsDictionary,
-                                      LayoutOptionForRTLSupport(),
-                                      _containerView);
-
-    AddSameCenterXConstraint(_containerView, incognitoImage);
-    AddSameCenterXConstraint(_containerView, incognitoTabHeading);
-    AddSameCenterXConstraint(_containerView, incognitoTabDescription);
-    AddSameCenterXConstraint(_containerView, incognitoTabWarning);
-    AddSameCenterXConstraint(_containerView, learnMore);
-
-    // The bottom guide is twice as big as the top guide.
-    [_containerView addConstraint:[NSLayoutConstraint
-                                      constraintWithItem:bottomGuide
-                                               attribute:NSLayoutAttributeHeight
-                                               relatedBy:NSLayoutRelationEqual
-                                                  toItem:topGuide
-                                               attribute:NSLayoutAttributeHeight
-                                              multiplier:2
-                                                constant:0]];
-
-    [self addSubview:_containerView];
-
-    // Constraints comunicating the size of the contentView to the scrollview.
-    // See UIScrollView autolayout information at
-    // https://developer.apple.com/library/ios/releasenotes/General/RN-iOSSDK-6_0/index.html
-    viewsDictionary = @{@"containerView" : _containerView};
-    constraints = @[
-      @"V:|-0-[containerView]-0-|",
-      @"H:|-0-[containerView]-0-|",
-    ];
-    ApplyVisualConstraintsWithOptions(constraints, viewsDictionary,
-                                      LayoutOptionForRTLSupport(), self);
-  }
-  return self;
-}
-
-- (UILabel*)labelWithString:(NSString*)string
-                       font:(UIFont*)font
-                      alpha:(float)alpha {
-  NSMutableAttributedString* attributedString =
-      [[NSMutableAttributedString alloc] initWithString:string];
-  NSMutableParagraphStyle* paragraphStyle =
-      [[NSMutableParagraphStyle alloc] init];
-  [paragraphStyle setLineSpacing:4];
-  [paragraphStyle setAlignment:NSTextAlignmentJustified];
-  [attributedString addAttribute:NSParagraphStyleAttributeName
-                           value:paragraphStyle
-                           range:NSMakeRange(0, string.length)];
-  UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
-  [label setTranslatesAutoresizingMaskIntoConstraints:NO];
-  [label setNumberOfLines:0];
-  [label setFont:font];
-  [label setAttributedText:attributedString];
-  [label setTextColor:[UIColor colorWithWhite:1.0 alpha:alpha]];
-  return label;
-}
-
-- (void)learnMoreButtonPressed {
-  GURL gurl = GetUrlWithLang(GURL(kLearnMoreIncognitoUrl));
-  [_loader loadURL:gurl
-               referrer:web::Referrer()
-             transition:ui::PAGE_TRANSITION_LINK
-      rendererInitiated:NO];
-}
-
-#pragma mark - UIView overrides
-
-- (void)didMoveToSuperview {
-  [super didMoveToSuperview];
-  _containerHorizontalConstraint =
-      [NSLayoutConstraint constraintWithItem:_containerView
-                                   attribute:NSLayoutAttributeWidth
-                                   relatedBy:NSLayoutRelationEqual
-                                      toItem:[self superview]
-                                   attribute:NSLayoutAttributeWidth
-                                  multiplier:1
-                                    constant:0];
-  _containerVerticalConstraint =
-      [NSLayoutConstraint constraintWithItem:_containerView
-                                   attribute:NSLayoutAttributeHeight
-                                   relatedBy:NSLayoutRelationGreaterThanOrEqual
-                                      toItem:[self superview]
-                                   attribute:NSLayoutAttributeHeight
-                                  multiplier:1
-                                    constant:0];
-  [[self superview] addConstraint:_containerHorizontalConstraint];
-  [[self superview] addConstraint:_containerVerticalConstraint];
-}
-
-- (void)willMoveToSuperview:(UIView*)newSuperview {
-  [[self superview] removeConstraint:_containerHorizontalConstraint];
-  [[self superview] removeConstraint:_containerVerticalConstraint];
-  _containerHorizontalConstraint = nil;
-  _containerVerticalConstraint = nil;
-  [super willMoveToSuperview:newSuperview];
-}
-
-@end
-
-@interface IncognitoPanelController ()<UIScrollViewDelegate>
-// Calculate the background alpha for the toolbar based on how much |scrollView|
-// has scrolled up.
-- (CGFloat)toolbarAlphaForScrollView:(UIScrollView*)scrollView;
-@end
-
-@implementation IncognitoPanelController {
-  // Delegate for updating the toolbar's background alpha.
-  __weak id<WebToolbarDelegate> _webToolbarDelegate;
-
-  // The scrollview containing the actual views.
-  IncognitoNTPView* _incognitoView;
-}
-
-// Property declared in NewTabPagePanelProtocol.
-@synthesize delegate = _delegate;
-@synthesize view = _view;
-
-- (id)initWithLoader:(id<UrlLoader>)loader
-          browserState:(ios::ChromeBrowserState*)browserState
-    webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate {
-  self = [super init];
-  if (self) {
-    _view = [[UIView alloc]
-        initWithFrame:[UIApplication sharedApplication].keyWindow.bounds];
-    [_view setAccessibilityIdentifier:@"NTP Incognito Panel"];
-    [_view setAutoresizingMask:UIViewAutoresizingFlexibleHeight |
-                               UIViewAutoresizingFlexibleWidth];
-    _incognitoView = [[IncognitoNTPView alloc]
-        initWithFrame:[UIApplication sharedApplication].keyWindow.bounds
-            urlLoader:loader];
-    [_incognitoView setAutoresizingMask:UIViewAutoresizingFlexibleHeight |
-                                        UIViewAutoresizingFlexibleWidth];
-
-    if (IsIPadIdiom()) {
-      [_incognitoView setBackgroundColor:[UIColor clearColor]];
-    } else {
-      [_incognitoView
-          setBackgroundColor:[UIColor colorWithWhite:34 / 255.0 alpha:1.0]];
-    }
-    if (!IsIPadIdiom()) {
-      [_incognitoView setDelegate:self];
-      _webToolbarDelegate = webToolbarDelegate;
-      [_webToolbarDelegate updateToolbarBackgroundAlpha:0];
-    }
-    [_view addSubview:_incognitoView];
-  }
-  return self;
-}
-
-- (CGFloat)toolbarAlphaForScrollView:(UIScrollView*)scrollView {
-  CGFloat alpha = scrollView.contentOffset.y / kDistanceToFadeToolbar;
-  return MAX(MIN(alpha, 1), 0);
-}
-
-- (void)dealloc {
-  [_webToolbarDelegate updateToolbarBackgroundAlpha:1];
-  [_incognitoView setDelegate:nil];
-  ;
-}
-
-#pragma mark -
-#pragma mark NewTabPagePanelProtocol
-
-- (void)reload {
-}
-
-- (void)wasShown {
-  CGFloat alpha = [self toolbarAlphaForScrollView:_incognitoView];
-  [_webToolbarDelegate updateToolbarBackgroundAlpha:alpha];
-}
-
-- (void)wasHidden {
-  [_webToolbarDelegate updateToolbarBackgroundAlpha:1];
-}
-
-- (void)dismissModals {
-}
-
-- (void)dismissKeyboard {
-}
-
-- (void)setScrollsToTop:(BOOL)enable {
-}
-
-- (CGFloat)alphaForBottomShadow {
-  return 0;
-}
-
-#pragma mark -
-#pragma mark UIScrollViewDelegate methods
-
-- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
-  CGFloat alpha = [self toolbarAlphaForScrollView:_incognitoView];
-  [_webToolbarDelegate updateToolbarBackgroundAlpha:alpha];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/ntp/incognito_view.h b/ios/chrome/browser/ui/ntp/incognito_view.h
new file mode 100644
index 0000000..dfd0ad0
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/incognito_view.h
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_H_
+#define IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_H_
+
+#import <UIKit/UIKit.h>
+
+@protocol UrlLoader;
+
+// The scrollview containing the views. Its content's size is constrained on its
+// superview's size.
+@interface IncognitoView : UIScrollView
+
+- (instancetype)initWithFrame:(CGRect)frame urlLoader:(id<UrlLoader>)loader;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_H_
diff --git a/ios/chrome/browser/ui/ntp/incognito_view.mm b/ios/chrome/browser/ui/ntp/incognito_view.mm
new file mode 100644
index 0000000..5deb4e7
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/incognito_view.mm
@@ -0,0 +1,239 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/ntp/incognito_view.h"
+
+#include "components/google/core/browser/google_util.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/application_context.h"
+#include "ios/chrome/browser/ui/rtl_geometry.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#import "ios/chrome/browser/ui/url_loader.h"
+#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
+#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.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 "ios/web/public/referrer.h"
+#import "net/base/mac/url_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// The URL for the the Learn More page shown on incognito new tab.
+// Taken from ntp_resource_cache.cc.
+const char kLearnMoreIncognitoUrl[] =
+    "https://www.google.com/support/chrome/bin/answer.py?answer=95464";
+
+GURL GetUrlWithLang(const GURL& url) {
+  std::string locale = GetApplicationContext()->GetApplicationLocale();
+  return google_util::AppendGoogleLocaleParam(url, locale);
+}
+
+const int kLinkColor = 0x03A9F4;
+}  // namespace
+
+@implementation IncognitoView {
+  __weak id<UrlLoader> _loader;
+  UIView* _containerView;
+
+  // Constraint ensuring that |containerView| is at least as high as the
+  // superview of the IncognitoNTPView, i.e. the Incognito panel.
+  // This ensures that if the Incognito panel is higher than a compact
+  // |containerView|, the |containerView|'s |topGuide| and |bottomGuide| are
+  // forced to expand, centering the views in between them.
+  NSLayoutConstraint* _containerVerticalConstraint;
+
+  // Constraint ensuring that |containerView| is as wide as the superview of the
+  // the IncognitoNTPView, i.e. the Incognito panel.
+  NSLayoutConstraint* _containerHorizontalConstraint;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame urlLoader:(id<UrlLoader>)loader {
+  self = [super initWithFrame:frame];
+  if (self) {
+    _loader = loader;
+
+    self.alwaysBounceVertical = YES;
+
+    // Container in which all the subviews (image, labels, button) are added.
+    _containerView = [[UIView alloc] initWithFrame:frame];
+    [_containerView setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+    // Incognito image.
+    UIImageView* incognitoImage = [[UIImageView alloc]
+        initWithImage:[UIImage imageNamed:@"incognito_icon"]];
+    [incognitoImage setTranslatesAutoresizingMaskIntoConstraints:NO];
+    [_containerView addSubview:incognitoImage];
+
+    // Title.
+    UIFont* titleFont = [[MDCTypography fontLoader] lightFontOfSize:24];
+    UILabel* incognitoTabHeading =
+        [self labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_HEADING)
+                         font:titleFont
+                        alpha:0.8];
+    [_containerView addSubview:incognitoTabHeading];
+
+    // Description paragraph.
+    UIFont* regularFont = [[MDCTypography fontLoader] regularFontOfSize:14];
+    UILabel* incognitoTabDescription = [self
+        labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_DESCRIPTION)
+                   font:regularFont
+                  alpha:0.7];
+    [_containerView addSubview:incognitoTabDescription];
+
+    // Warning paragraph.
+    UILabel* incognitoTabWarning = [self
+        labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_MESSAGE_WARNING)
+                   font:regularFont
+                  alpha:0.7];
+    [_containerView addSubview:incognitoTabWarning];
+
+    // Learn more button.
+    MDCButton* learnMore = [[MDCFlatButton alloc] init];
+    UIColor* inkColor =
+        [[[MDCPalette greyPalette] tint300] colorWithAlphaComponent:0.25];
+    [learnMore setInkColor:inkColor];
+    [learnMore setTranslatesAutoresizingMaskIntoConstraints:NO];
+    [learnMore setTitle:l10n_util::GetNSString(IDS_NEW_TAB_OTR_LEARN_MORE_LINK)
+               forState:UIControlStateNormal];
+    [learnMore setTitleColor:UIColorFromRGB(kLinkColor)
+                    forState:UIControlStateNormal];
+    UIFont* buttonFont = [[MDCTypography fontLoader] boldFontOfSize:14];
+    [[learnMore titleLabel] setFont:buttonFont];
+    [learnMore addTarget:self
+                  action:@selector(learnMoreButtonPressed)
+        forControlEvents:UIControlEventTouchUpInside];
+    [_containerView addSubview:learnMore];
+
+    // |topGuide| and |bottomGuide| exist to vertically center the sibling views
+    // located in between them.
+    UILayoutGuide* topGuide = [[UILayoutGuide alloc] init];
+    UILayoutGuide* bottomGuide = [[UILayoutGuide alloc] init];
+    [_containerView addLayoutGuide:topGuide];
+    [_containerView addLayoutGuide:bottomGuide];
+
+    NSDictionary* viewsDictionary = @{
+      @"topGuide" : topGuide,
+      @"image" : incognitoImage,
+      @"heading" : incognitoTabHeading,
+      @"description" : incognitoTabDescription,
+      @"warning" : incognitoTabWarning,
+      @"learnMoreButton" : learnMore,
+      @"bottomGuide" : bottomGuide,
+    };
+    NSArray* constraints = @[
+      @"V:|-0-[topGuide(>=12)]-[image]-24-[heading]-32-[description]",
+      @"V:[description]-32-[warning]-32-[learnMoreButton]",
+      @"V:[learnMoreButton]-[bottomGuide]-0-|",
+      @"H:|-(>=24)-[heading]-(>=24)-|",
+      @"H:|-(>=24)-[description(==416@999)]-(>=24)-|",
+      @"H:|-(>=24)-[warning(==416@999)]-(>=24)-|"
+    ];
+    ApplyVisualConstraintsWithOptions(constraints, viewsDictionary,
+                                      LayoutOptionForRTLSupport(),
+                                      _containerView);
+
+    AddSameCenterXConstraint(_containerView, incognitoImage);
+    AddSameCenterXConstraint(_containerView, incognitoTabHeading);
+    AddSameCenterXConstraint(_containerView, incognitoTabDescription);
+    AddSameCenterXConstraint(_containerView, incognitoTabWarning);
+    AddSameCenterXConstraint(_containerView, learnMore);
+
+    // The bottom guide is twice as big as the top guide.
+    [_containerView addConstraint:[NSLayoutConstraint
+                                      constraintWithItem:bottomGuide
+                                               attribute:NSLayoutAttributeHeight
+                                               relatedBy:NSLayoutRelationEqual
+                                                  toItem:topGuide
+                                               attribute:NSLayoutAttributeHeight
+                                              multiplier:2
+                                                constant:0]];
+
+    [self addSubview:_containerView];
+
+    // Constraints comunicating the size of the contentView to the scrollview.
+    // See UIScrollView autolayout information at
+    // https://developer.apple.com/library/ios/releasenotes/General/RN-iOSSDK-6_0/index.html
+    viewsDictionary = @{@"containerView" : _containerView};
+    constraints = @[
+      @"V:|-0-[containerView]-0-|",
+      @"H:|-0-[containerView]-0-|",
+    ];
+    ApplyVisualConstraintsWithOptions(constraints, viewsDictionary,
+                                      LayoutOptionForRTLSupport(), self);
+  }
+  return self;
+}
+
+#pragma mark - UIView overrides
+
+- (void)didMoveToSuperview {
+  [super didMoveToSuperview];
+  _containerHorizontalConstraint =
+      [NSLayoutConstraint constraintWithItem:_containerView
+                                   attribute:NSLayoutAttributeWidth
+                                   relatedBy:NSLayoutRelationEqual
+                                      toItem:[self superview]
+                                   attribute:NSLayoutAttributeWidth
+                                  multiplier:1
+                                    constant:0];
+  _containerVerticalConstraint =
+      [NSLayoutConstraint constraintWithItem:_containerView
+                                   attribute:NSLayoutAttributeHeight
+                                   relatedBy:NSLayoutRelationGreaterThanOrEqual
+                                      toItem:[self superview]
+                                   attribute:NSLayoutAttributeHeight
+                                  multiplier:1
+                                    constant:0];
+  [[self superview] addConstraint:_containerHorizontalConstraint];
+  [[self superview] addConstraint:_containerVerticalConstraint];
+}
+
+- (void)willMoveToSuperview:(UIView*)newSuperview {
+  [[self superview] removeConstraint:_containerHorizontalConstraint];
+  [[self superview] removeConstraint:_containerVerticalConstraint];
+  _containerHorizontalConstraint = nil;
+  _containerVerticalConstraint = nil;
+  [super willMoveToSuperview:newSuperview];
+}
+
+#pragma mark - Private
+
+// Returns an autoreleased label with the right format.
+- (UILabel*)labelWithString:(NSString*)string
+                       font:(UIFont*)font
+                      alpha:(float)alpha {
+  NSMutableAttributedString* attributedString =
+      [[NSMutableAttributedString alloc] initWithString:string];
+  NSMutableParagraphStyle* paragraphStyle =
+      [[NSMutableParagraphStyle alloc] init];
+  [paragraphStyle setLineSpacing:4];
+  [paragraphStyle setAlignment:NSTextAlignmentJustified];
+  [attributedString addAttribute:NSParagraphStyleAttributeName
+                           value:paragraphStyle
+                           range:NSMakeRange(0, string.length)];
+  UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
+  [label setTranslatesAutoresizingMaskIntoConstraints:NO];
+  [label setNumberOfLines:0];
+  [label setFont:font];
+  [label setAttributedText:attributedString];
+  [label setTextColor:[UIColor colorWithWhite:1.0 alpha:alpha]];
+  return label;
+}
+
+// Triggers a navigation to the help page.
+- (void)learnMoreButtonPressed {
+  GURL gurl = GetUrlWithLang(GURL(kLearnMoreIncognitoUrl));
+  [_loader loadURL:gurl
+               referrer:web::Referrer()
+             transition:ui::PAGE_TRANSITION_LINK
+      rendererInitiated:NO];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/ntp/incognito_view_controller.h b/ios/chrome/browser/ui/ntp/incognito_view_controller.h
new file mode 100644
index 0000000..af710a5e
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/incognito_view_controller.h
@@ -0,0 +1,29 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/ntp/new_tab_page_panel_protocol.h"
+
+@protocol UrlLoader;
+
+@protocol IncognitoViewControllerDelegate
+// Sets the alpha for the toolbar's background views.
+- (void)setToolbarBackgroundAlpha:(CGFloat)alpha;
+@end
+
+@interface IncognitoViewController : UIViewController<NewTabPagePanelProtocol>
+
+// Init with the given loader object. |loader| may be nil, but isn't
+// retained so it must outlive this controller.
+// |toolbarDelegate| is used to fade the toolbar views on page scroll.
+- (id)initWithLoader:(id<UrlLoader>)loader
+     toolbarDelegate:(id<IncognitoViewControllerDelegate>)toolbarDelegate;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/ntp/incognito_view_controller.mm b/ios/chrome/browser/ui/ntp/incognito_view_controller.mm
new file mode 100644
index 0000000..829f081
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/incognito_view_controller.mm
@@ -0,0 +1,123 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/ntp/incognito_view_controller.h"
+
+#include <string>
+
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
+#import "ios/chrome/browser/ui/ntp/incognito_view.h"
+#import "ios/chrome/browser/ui/ntp/modal_ntp.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#import "ios/chrome/browser/ui/url_loader.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+const CGFloat kDistanceToFadeToolbar = 50.0;
+}  // namespace
+
+@interface IncognitoViewController ()<UIScrollViewDelegate>
+// The scrollview containing the actual views.
+@property(nonatomic, strong) IncognitoView* incognitoView;
+
+@property(nonatomic, weak) id<IncognitoViewControllerDelegate> toolbarDelegate;
+@property(nonatomic, weak) id<UrlLoader> loader;
+@end
+
+@implementation IncognitoViewController
+
+@synthesize incognitoView = _incognitoView;
+@synthesize toolbarDelegate = _toolbarDelegate;
+@synthesize loader = _loader;
+
+// Property declared in NewTabPagePanelProtocol.
+@synthesize delegate = _delegate;
+
+- (id)initWithLoader:(id<UrlLoader>)loader
+     toolbarDelegate:(id<IncognitoViewControllerDelegate>)toolbarDelegate {
+  self = [super init];
+  if (self) {
+    _loader = loader;
+    if (!IsIPadIdiom()) {
+      _toolbarDelegate = toolbarDelegate;
+      [_toolbarDelegate setToolbarBackgroundAlpha:0];
+    }
+  }
+  return self;
+}
+
+- (void)viewDidLoad {
+  self.incognitoView = [[IncognitoView alloc]
+      initWithFrame:[UIApplication sharedApplication].keyWindow.bounds
+          urlLoader:self.loader];
+  [self.incognitoView setAutoresizingMask:UIViewAutoresizingFlexibleHeight |
+                                          UIViewAutoresizingFlexibleWidth];
+
+  if (!PresentNTPPanelModally()) {
+    [self.incognitoView setBackgroundColor:[UIColor clearColor]];
+  } else {
+    [self.incognitoView
+        setBackgroundColor:[UIColor colorWithWhite:34 / 255.0 alpha:1.0]];
+  }
+
+  if (!IsIPadIdiom()) {
+    [self.incognitoView setDelegate:self];
+  }
+
+  [self.view addSubview:self.incognitoView];
+}
+
+- (void)dealloc {
+  [_toolbarDelegate setToolbarBackgroundAlpha:1];
+  [_incognitoView setDelegate:nil];
+}
+
+#pragma mark - NewTabPagePanelProtocol
+
+- (void)reload {
+}
+
+- (void)wasShown {
+  CGFloat alpha = [self toolbarAlphaForScrollView:self.incognitoView];
+  [self.toolbarDelegate setToolbarBackgroundAlpha:alpha];
+}
+
+- (void)wasHidden {
+  [self.toolbarDelegate setToolbarBackgroundAlpha:1];
+}
+
+- (void)dismissModals {
+}
+
+- (void)dismissKeyboard {
+}
+
+- (void)setScrollsToTop:(BOOL)enable {
+}
+
+- (CGFloat)alphaForBottomShadow {
+  return 0;
+}
+
+#pragma mark - UIScrollViewDelegate methods
+
+- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
+  CGFloat alpha = [self toolbarAlphaForScrollView:self.incognitoView];
+  [self.toolbarDelegate setToolbarBackgroundAlpha:alpha];
+}
+
+#pragma mark - Private
+
+// Calculate the background alpha for the toolbar based on how much |scrollView|
+// has scrolled up.
+- (CGFloat)toolbarAlphaForScrollView:(UIScrollView*)scrollView {
+  CGFloat alpha = scrollView.contentOffset.y / kDistanceToFadeToolbar;
+  return MAX(MIN(alpha, 1), 0);
+}
+
+@end
diff --git a/ios/chrome/browser/ui/ntp/modal_ntp.h b/ios/chrome/browser/ui/ntp/modal_ntp.h
new file mode 100644
index 0000000..35951342
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/modal_ntp.h
@@ -0,0 +1,14 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_NTP_MODAL_NTP_H_
+#define IOS_CHROME_BROWSER_UI_NTP_MODAL_NTP_H_
+
+#include <Foundation/Foundation.h>
+
+// Whether the panel on the NTP (Bookmarks and Recent Tabs) should be presented
+// modally.
+BOOL PresentNTPPanelModally();
+
+#endif  // IOS_CHROME_BROWSER_UI_NTP_MODAL_NTP_H_
diff --git a/ios/chrome/browser/ui/ntp/modal_ntp.mm b/ios/chrome/browser/ui/ntp/modal_ntp.mm
new file mode 100644
index 0000000..e7489a3
--- /dev/null
+++ b/ios/chrome/browser/ui/ntp/modal_ntp.mm
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/ntp/modal_ntp.h"
+
+#include "ios/chrome/browser/bookmarks/bookmark_new_generation_features.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+BOOL PresentNTPPanelModally() {
+  return !IsIPadIdiom() || base::FeatureList::IsEnabled(kBookmarkNewGeneration);
+}
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm b/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm
index e64cc7e4..a546b7a 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_bar.mm
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
+#import "ios/chrome/browser/ui/ntp/modal_ntp.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_button.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
@@ -313,13 +314,13 @@
 }
 
 - (BOOL)useIconsInButtons {
-  return !IsIPadIdiom() || IsCompactTablet();
+  return PresentNTPPanelModally() || IsCompactTablet();
 }
 
 - (BOOL)showOverlay {
   // The bar buttons launch modal dialogs on tap on iPhone. Don't show overlay
   // in this case.
-  return IsIPadIdiom();
+  return !PresentNTPPanelModally();
 }
 
 @end
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
index ed4adf9..4a8238e 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
@@ -31,13 +31,12 @@
 @protocol ApplicationCommands;
 @class BookmarkHomeTabletNTPController;
 @protocol BrowserCommands;
-@protocol ChromeExecuteCommand;
 @protocol CRWSwipeRecognizerProvider;
 @class GoogleLandingViewController;
+@protocol IncognitoViewControllerDelegate;
 @protocol NewTabPagePanelProtocol;
 @protocol OmniboxFocuser;
 @class TabModel;
-@protocol WebToolbarDelegate;
 @protocol UrlLoader;
 
 // This protocol provides callbacks for when the NewTabPageController changes
@@ -84,12 +83,11 @@
              ntpObserver:(id<NewTabPageControllerObserver>)ntpObserver
             browserState:(ios::ChromeBrowserState*)browserState
               colorCache:(NSMutableDictionary*)colorCache
-      webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate
+         toolbarDelegate:(id<IncognitoViewControllerDelegate>)toolbarDelegate
                 tabModel:(TabModel*)tabModel
     parentViewController:(UIViewController*)parentViewController
               dispatcher:(id<ApplicationCommands,
                              BrowserCommands,
-                             ChromeExecuteCommand,
                              OmniboxFocuser,
                              UrlLoader>)dispatcher;
 
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
index e1a6a53..d8f3373 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -29,7 +29,8 @@
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
 #import "ios/chrome/browser/ui/ntp/google_landing_mediator.h"
 #import "ios/chrome/browser/ui/ntp/google_landing_view_controller.h"
-#import "ios/chrome/browser/ui/ntp/incognito_panel_controller.h"
+#import "ios/chrome/browser/ui/ntp/incognito_view_controller.h"
+#import "ios/chrome/browser/ui/ntp/modal_ntp.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_view.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
@@ -118,7 +119,7 @@
   __weak id<NewTabPageControllerObserver> _newTabPageObserver;
   BookmarkHomeTabletNTPController* _bookmarkController;
   GoogleLandingViewController* _googleLandingController;
-  id<NewTabPagePanelProtocol> _incognitoController;
+  IncognitoViewController* _incognitoController;
   // The currently visible controller, one of the above.
   __weak id<NewTabPagePanelProtocol> _currentController;
 
@@ -135,7 +136,7 @@
   __weak id<OmniboxFocuser> _focuser;
 
   // Delegate to fetch the ToolbarModel and current web state from.
-  __weak id<WebToolbarDelegate> _webToolbarDelegate;
+  __weak id<IncognitoViewControllerDelegate> _toolbarDelegate;
 
   TabModel* _tabModel;
 }
@@ -180,7 +181,6 @@
 // The command dispatcher.
 @property(nonatomic, weak) id<ApplicationCommands,
                               BrowserCommands,
-                              ChromeExecuteCommand,
                               OmniboxFocuser,
                               UrlLoader>
     dispatcher;
@@ -214,12 +214,11 @@
              ntpObserver:(id<NewTabPageControllerObserver>)ntpObserver
             browserState:(ios::ChromeBrowserState*)browserState
               colorCache:(NSMutableDictionary*)colorCache
-      webToolbarDelegate:(id<WebToolbarDelegate>)webToolbarDelegate
+         toolbarDelegate:(id<IncognitoViewControllerDelegate>)toolbarDelegate
                 tabModel:(TabModel*)tabModel
     parentViewController:(UIViewController*)parentViewController
               dispatcher:(id<ApplicationCommands,
                              BrowserCommands,
-                             ChromeExecuteCommand,
                              OmniboxFocuser,
                              UrlLoader>)dispatcher {
   self = [super initWithNibName:nil url:url];
@@ -231,7 +230,7 @@
     _parentViewController = parentViewController;
     _dispatcher = dispatcher;
     _focuser = focuser;
-    _webToolbarDelegate = webToolbarDelegate;
+    _toolbarDelegate = toolbarDelegate;
     _tabModel = tabModel;
     _dominantColorCache = colorCache;
     self.title = l10n_util::GetNSString(IDS_NEW_TAB_TITLE);
@@ -267,7 +266,7 @@
           newTabPageBarItemWithTitle:incognito
                           identifier:ntp_home::INCOGNITO_PANEL
                                image:[UIImage imageNamed:@"ntp_incognito"]];
-      if (IsIPadIdiom()) {
+      if (!PresentNTPPanelModally()) {
         // Only add the bookmarks tab item for Incognito.
         NewTabPageBarItem* bookmarksItem = [NewTabPageBarItem
             newTabPageBarItemWithTitle:bookmarks
@@ -288,7 +287,7 @@
                           identifier:ntp_home::BOOKMARKS_PANEL
                                image:[UIImage imageNamed:@"ntp_bookmarks"]];
       [tabBarItems addObject:bookmarksItem];
-      if (IsIPadIdiom()) {
+      if (!PresentNTPPanelModally()) {
         [tabBarItems addObject:homeItem];
       }
 
@@ -299,7 +298,7 @@
       [tabBarItems addObject:openTabsItem];
       self.ntpView.tabBar.items = tabBarItems;
 
-      if (!IsIPadIdiom()) {
+      if (PresentNTPPanelModally()) {
         itemToDisplay = homeItem;
       } else {
         PrefService* prefs = _browserState->GetPrefs();
@@ -333,10 +332,9 @@
   // This is not an ideal place to put view controller contaimnent, rather a
   // //web -wasDismissed method on CRWNativeContent would be more accurate. If
   // CRWNativeContent leaks, this will not be called.
-  // TODO(crbug.com/708319): Also call -removeFromParentViewController for
-  // open tabs and incognito here.
   [_googleLandingController removeFromParentViewController];
   [_bookmarkController removeFromParentViewController];
+  [_incognitoController removeFromParentViewController];
   [[self.contentSuggestionsCoordinator viewController]
       removeFromParentViewController];
   [[_openTabsCoordinator viewController] removeFromParentViewController];
@@ -356,12 +354,12 @@
   // This methods is called by //web immediately before |self|'s view is removed
   // from the view hierarchy, making it an ideal spot to intiate view controller
   // containment methods.
-  // TODO(crbug.com/708319): Also call -willMoveToParentViewController:nil for
-  // open tabs and incognito here.
   [_googleLandingController willMoveToParentViewController:nil];
   [_bookmarkController willMoveToParentViewController:nil];
+  [[_openTabsCoordinator viewController] willMoveToParentViewController:nil];
   [[self.contentSuggestionsCoordinator viewController]
       willMoveToParentViewController:nil];
+  [_incognitoController willMoveToParentViewController:nil];
 }
 
 - (void)reload {
@@ -570,9 +568,7 @@
 
 - (BOOL)loadPanel:(NewTabPageBarItem*)item {
   DCHECK(self.parentViewController);
-  UIView* view = nil;
   UIViewController* panelController = nil;
-  BOOL created = NO;
   // Only load the controllers once.
   if (item.identifier == ntp_home::BOOKMARKS_PANEL) {
     if (!_bookmarkController) {
@@ -583,7 +579,6 @@
                                                    loader:_loader];
     }
     panelController = _bookmarkController;
-    view = [_bookmarkController view];
     [_bookmarkController setDelegate:self];
   } else if (item.identifier == ntp_home::HOME_PANEL) {
     if (experimental_flags::IsSuggestionsUIEnabled()) {
@@ -619,9 +614,7 @@
       panelController = _googleLandingController;
       self.homePanel = _googleLandingController;
     }
-    view = panelController.view;
     [self.homePanel setDelegate:self];
-    [self.ntpView.tabBar setShadowAlpha:[self.homePanel alphaForBottomShadow]];
   } else if (item.identifier == ntp_home::RECENT_TABS_PANEL) {
     if (!_openTabsCoordinator) {
       _openTabsCoordinator =
@@ -631,23 +624,27 @@
       [_openTabsCoordinator start];
     }
     panelController = [_openTabsCoordinator viewController];
-    view = panelController.view;
     [_openTabsCoordinator setDelegate:self];
   } else if (item.identifier == ntp_home::INCOGNITO_PANEL) {
     if (!_incognitoController)
       _incognitoController =
-          [[IncognitoPanelController alloc] initWithLoader:_loader
-                                              browserState:_browserState
-                                        webToolbarDelegate:_webToolbarDelegate];
-    // TODO(crbug.com/708319): Also set panelController for incognito here.
-    view = [_incognitoController view];
+          [[IncognitoViewController alloc] initWithLoader:_loader
+                                          toolbarDelegate:_toolbarDelegate];
+    panelController = _incognitoController;
   } else {
     NOTREACHED();
     return NO;
   }
 
+  UIView* view = panelController.view;
+  if (item.identifier == ntp_home::HOME_PANEL) {
+    // Update the shadow for the toolbar after the view creation.
+    [self.ntpView.tabBar setShadowAlpha:[self.homePanel alphaForBottomShadow]];
+  }
+
   // Add the panel views to the scroll view in the proper location.
   NSUInteger index = [self tabBarItemIndex:item];
+  BOOL created = NO;
   if (view.superview == nil) {
     created = YES;
     view.frame = [self.ntpView panelFrameForItemAtIndex:index];
@@ -660,20 +657,17 @@
     // controller would be owned by a coordinator, in this case the old NTP
     // controller adds and removes child view controllers itself when a load
     // is initiated, and when WebController calls -willBeDismissed.
-    // TODO(crbug.com/708319):This 'if' can become a DCHECK once all panels move
-    // to panelControllers.
-    if (panelController)
-      [self.parentViewController addChildViewController:panelController];
+    DCHECK(panelController);
+    [self.parentViewController addChildViewController:panelController];
     [self.ntpView.scrollView addSubview:view];
-    if (panelController)
-      [panelController didMoveToParentViewController:self.parentViewController];
+    [panelController didMoveToParentViewController:self.parentViewController];
   }
   return created;
 }
 
 - (void)scrollToPanel:(NewTabPageBarItem*)item animate:(BOOL)animate {
   NSUInteger index = [self tabBarItemIndex:item];
-  if (IsIPadIdiom()) {
+  if (!PresentNTPPanelModally()) {
     CGRect itemFrame = [self.ntpView panelFrameForItemAtIndex:index];
     CGPoint point = CGPointMake(CGRectGetMinX(itemFrame), 0);
     [self.ntpView.scrollView setContentOffset:point animated:animate];
@@ -695,7 +689,7 @@
 // scroll view. None of this is applicable for iPhone.
 - (NSUInteger)tabBarItemIndex:(NewTabPageBarItem*)item {
   NSUInteger index = 0;
-  if (IsIPadIdiom()) {
+  if (!PresentNTPPanelModally()) {
     index = [self.ntpView.tabBar.items indexOfObject:item];
     DCHECK(index != NSNotFound);
   }
@@ -703,7 +697,7 @@
 }
 
 - (ntp_home::PanelIdentifier)selectedPanelID {
-  if (IsIPadIdiom()) {
+  if (!PresentNTPPanelModally()) {
     // |selectedIndex| isn't meaningful here with modal buttons on iPhone.
     NSUInteger index = self.ntpView.tabBar.selectedIndex;
     DCHECK(index != NSNotFound);
@@ -715,8 +709,9 @@
 
 - (void)updateCurrentController:(NewTabPageBarItem*)item
                           index:(NSUInteger)index {
-  if (!IsIPadIdiom() && (item.identifier == ntp_home::BOOKMARKS_PANEL ||
-                         item.identifier == ntp_home::RECENT_TABS_PANEL)) {
+  if (PresentNTPPanelModally() &&
+      (item.identifier == ntp_home::BOOKMARKS_PANEL ||
+       item.identifier == ntp_home::RECENT_TABS_PANEL)) {
     // Don't update |_currentController| for iPhone since Bookmarks and Recent
     // Tabs are presented in a modal view controller.
     return;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm
index fd6338f..63552e0a 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller_unittest.mm
@@ -75,7 +75,7 @@
                                       ntpObserver:nil
                                      browserState:chrome_browser_state_.get()
                                        colorCache:nil
-                               webToolbarDelegate:nil
+                                  toolbarDelegate:nil
                                          tabModel:tabModel_
                              parentViewController:parentViewController_
                                        dispatcher:nil];
@@ -88,7 +88,7 @@
                 browserState:chrome_browser_state_
                                  ->GetOffTheRecordChromeBrowserState()
                   colorCache:nil
-          webToolbarDelegate:nil
+             toolbarDelegate:nil
                     tabModel:nil
         parentViewController:parentViewController_
                   dispatcher:nil];
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_panel_protocol.h b/ios/chrome/browser/ui/ntp/new_tab_page_panel_protocol.h
index 1ceb02dad..8f9d5d82 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_panel_protocol.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_panel_protocol.h
@@ -40,9 +40,6 @@
 // Alpha value to use for the NewTabPageBar shadow.
 @property(nonatomic, readonly) CGFloat alphaForBottomShadow;
 
-// Main view.
-@property(nonatomic, readonly) UIView* view;
-
 // Reload any displayed data to ensure the view is up to date.
 - (void)reload;
 
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view.mm
index 7efc36a1..0d0455df 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_view.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_view.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/ntp/new_tab_page_view.h"
 
 #include "base/logging.h"
+#import "ios/chrome/browser/ui/ntp/modal_ntp.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
@@ -58,7 +59,7 @@
   [self updateScrollViewContentSize];
 
   // Set the frame of the laid out NTP panels on iPad.
-  if (IsIPadIdiom()) {
+  if (!PresentNTPPanelModally()) {
     NSUInteger index = 0;
     CGFloat selectedItemXOffset = 0;
     for (NewTabPageBarItem* item in self.tabBar.items) {
@@ -114,7 +115,7 @@
   CGSize contentSize = self.scrollView.bounds.size;
   // On iPhone, NTP doesn't scroll horizontally, as alternate panels are shown
   // modally. On iPad, panels are laid out side by side in the scroll view.
-  if (IsIPadIdiom()) {
+  if (!PresentNTPPanelModally()) {
     contentSize.width *= self.tabBar.items.count;
   }
   self.scrollView.contentSize = contentSize;
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h
index ea48d27..ecd23400 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h
@@ -47,8 +47,7 @@
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
     NS_UNAVAILABLE;
 
-// TODO(crbug.com/708319): Expose the view controller in preparation for a full
-// view controller conversion.
+// The view controller managed by this coordinator.
 - (UIViewController*)viewController;
 
 @end
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index c32d19a..7d445ea 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -23,7 +23,6 @@
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_configurator.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_consumer.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #include "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn
index d935766a..5145d75 100644
--- a/ios/chrome/browser/ui/omnibox/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -27,12 +27,16 @@
     "omnibox_popup_material_view_controller.h",
     "omnibox_popup_material_view_controller.mm",
     "omnibox_popup_positioner.h",
+    "omnibox_popup_presenter.h",
+    "omnibox_popup_presenter.mm",
     "omnibox_popup_view_ios.h",
     "omnibox_popup_view_ios.mm",
     "omnibox_popup_view_suggestions_delegate.h",
     "omnibox_text_field_delegate.h",
     "omnibox_text_field_ios.h",
     "omnibox_text_field_ios.mm",
+    "omnibox_text_field_paste_delegate.h",
+    "omnibox_text_field_paste_delegate.mm",
     "omnibox_view_ios.h",
     "omnibox_view_ios.mm",
     "page_info_model.cc",
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h
index 24b6c18..f4b097b 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h
@@ -13,7 +13,14 @@
 class IOSImageDataFetcherWrapper;
 }
 
-class OmniboxPopupViewIOS;
+class OmniboxPopupMaterialViewControllerDelegate {
+ public:
+  virtual bool IsStarredMatch(const AutocompleteMatch& match) const = 0;
+  virtual void OnMatchSelected(const AutocompleteMatch& match, size_t row) = 0;
+  virtual void OnMatchSelectedForAppending(const AutocompleteMatch& match) = 0;
+  virtual void OnMatchSelectedForDeletion(const AutocompleteMatch& match) = 0;
+  virtual void OnScroll() = 0;
+};
 
 // View controller used to display a list of omnibox autocomplete matches in the
 // omnibox popup.
@@ -24,9 +31,9 @@
 // Designated initializer.  Creates a table view with UITableViewStylePlain.
 // Takes ownership of |imageFetcher|.
 - (instancetype)
-initWithPopupView:(OmniboxPopupViewIOS*)view
-      withFetcher:(std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)
-                      imageFetcher;
+initWithFetcher:
+    (std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)imageFetcher
+       delegate:(OmniboxPopupMaterialViewControllerDelegate*)delegate;
 
 // Updates the current data and forces a redraw. If animation is YES, adds
 // CALayer animations to fade the OmniboxPopupMaterialRows in.
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
index ae9420e..3ba98de 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
@@ -19,7 +19,6 @@
 #include "components/omnibox/browser/suggestion_answer.h"
 #include "ios/chrome/browser/ui/animation_util.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.h"
-#import "ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #import "ios/chrome/browser/ui/omnibox/truncating_attributed_label.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
@@ -81,7 +80,7 @@
   // Alignment of omnibox text. Popup text should match this alignment.
   NSTextAlignment _alignment;
 
-  OmniboxPopupViewIOS* _popupView;  // weak, owns us
+  OmniboxPopupMaterialViewControllerDelegate* _delegate;  // weak
 
   // Fetcher for Answers in Suggest images.
   std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> imageFetcher_;
@@ -107,11 +106,11 @@
 #pragma mark Initialization
 
 - (instancetype)
-initWithPopupView:(OmniboxPopupViewIOS*)view
-      withFetcher:(std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)
-                      imageFetcher {
+initWithFetcher:
+    (std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)imageFetcher
+       delegate:(OmniboxPopupMaterialViewControllerDelegate*)delegate {
   if ((self = [super init])) {
-    _popupView = view;
+    _delegate = delegate;
     imageFetcher_ = std::move(imageFetcher);
 
     if (IsIPadIdiom()) {
@@ -382,7 +381,7 @@
   // iPad.
   if (IsIPadIdiom()) {
     int imageId = GetIconForAutocompleteMatchType(
-        match.type, _popupView->IsStarredMatch(match), _incognito);
+        match.type, _delegate->IsStarredMatch(match), _incognito);
     [row updateLeadingImage:imageId];
   }
 
@@ -658,10 +657,7 @@
         base::UserMetricsAction("MobileOmniboxRefineSuggestion.Url"));
   }
 
-  // Make a defensive copy of |match.contents|, as CopyToOmnibox() will trigger
-  // a new round of autocomplete and modify |_currentResult|.
-  base::string16 contents(match.contents);
-  _popupView->CopyToOmnibox(contents);
+  _delegate->OnMatchSelectedForAppending(match);
 }
 
 #pragma mark -
@@ -681,7 +677,7 @@
       return;
   }
 
-  _popupView->DidScroll();
+  _delegate->OnScroll();
   for (OmniboxPopupMaterialRow* row in _rows) {
     row.highlighted = NO;
   }
@@ -751,7 +747,17 @@
   DCHECK_EQ(0U, (NSUInteger)indexPath.section);
   DCHECK_LT((NSUInteger)indexPath.row, _currentResult.size());
   NSUInteger row = indexPath.row;
-  _popupView->OpenURLForRow(row);
+
+  // Crash reports tell us that |row| is sometimes indexed past the end of
+  // the results array. In those cases, just ignore the request and return
+  // early. See b/5813291.
+  if (row >= _currentResult.size())
+    return;
+
+  const AutocompleteMatch& match =
+      ((const AutocompleteResult&)_currentResult).match_at(row);
+
+  _delegate->OnMatchSelected(match, row);
 }
 
 #pragma mark -
@@ -807,7 +813,7 @@
     [_rows[indexPath.row] prepareForReuse];
     const AutocompleteMatch& match =
         ((const AutocompleteResult&)_currentResult).match_at(indexPath.row);
-    _popupView->DeleteMatch(match);
+    _delegate->OnMatchSelectedForDeletion(match);
   }
 }
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.h
new file mode 100644
index 0000000..dd91aaf1
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_PRESENTER_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_PRESENTER_H_
+
+#import <UIKit/UIKit.h>
+
+@protocol OmniboxPopupPositioner;
+
+@interface OmniboxPopupPresenter : NSObject
+
+- (instancetype)initWithPopupPositioner:(id<OmniboxPopupPositioner>)positioner
+                    popupViewController:(UITableViewController*)viewController;
+
+@property(nonatomic, weak) id<OmniboxPopupPositioner> positioner;
+@property(nonatomic, weak) UITableViewController* viewController;
+@property(nonatomic, strong) UIView* popupContainerView;
+
+// Updates appearance depending on the content size of the presented view
+// controller by changing the visible height of the popup. When the popup was
+// not previously shown, it will appear with "expansion" animation.
+- (void)updateHeightAndAnimateAppearanceIfNecessary;
+// Call this to hide the popup with animation.
+- (void)animateCollapse;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_PRESENTER_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.mm
new file mode 100644
index 0000000..1a0d4bca
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.mm
@@ -0,0 +1,200 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.h"
+
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_positioner.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_theme_resources.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+const CGFloat kExpandAnimationDuration = 0.1;
+const CGFloat kCollapseAnimationDuration = 0.05;
+const CGFloat kWhiteBackgroundHeight = 74;
+NS_INLINE CGFloat ShadowHeight() {
+  return IsIPadIdiom() ? 10 : 0;
+}
+}  // namespace
+
+@implementation OmniboxPopupPresenter
+@synthesize viewController = _viewController;
+@synthesize positioner = _positioner;
+@synthesize popupContainerView = _popupContainerView;
+
+- (instancetype)initWithPopupPositioner:(id<OmniboxPopupPositioner>)positioner
+                    popupViewController:(UITableViewController*)viewController {
+  self = [super init];
+  if (self) {
+    _positioner = positioner;
+    _viewController = viewController;
+
+    if (IsIPadIdiom()) {
+      _popupContainerView = [OmniboxPopupPresenter newBackgroundViewIpad];
+    } else {
+      _popupContainerView = [OmniboxPopupPresenter newBackgroundViewIPhone];
+    }
+
+    CGRect popupControllerFrame = viewController.view.frame;
+    popupControllerFrame.origin = CGPointZero;
+    viewController.view.frame = popupControllerFrame;
+    [_popupContainerView addSubview:viewController.view];
+  }
+  return self;
+}
+
+- (void)updateHeightAndAnimateAppearanceIfNecessary {
+  UIView* view = self.popupContainerView;
+  // Show |result.size| on iPad.  Since iPhone can dismiss keyboard, set
+  // height to frame height.
+  CGFloat height = [[self.viewController tableView] contentSize].height;
+  UIEdgeInsets insets = [[self.viewController tableView] contentInset];
+  // Note the calculation |insets.top * 2| is correct, it should not be
+  // insets.top + insets.bottom. |insets.bottom| will be larger than
+  // |insets.top| when the keyboard is visible, but |parentHeight| should stay
+  // the same.
+  CGFloat parentHeight = height + insets.top * 2 + ShadowHeight();
+  UIView* siblingView = [self.positioner popupAnchorView];
+  if (IsIPadIdiom()) {
+    [[siblingView superview] insertSubview:view aboveSubview:siblingView];
+  } else {
+    [view setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
+                              UIViewAutoresizingFlexibleHeight];
+    [[siblingView superview] insertSubview:view belowSubview:siblingView];
+  }
+
+  CGFloat currentHeight = view.layer.bounds.size.height;
+  if (currentHeight == 0)
+    [self animateAppearance:parentHeight];
+  else
+    [view setFrame:[self.positioner popupFrame:parentHeight]];
+
+  CGRect popupControllerFrame = self.viewController.view.frame;
+  popupControllerFrame.size.height = view.frame.size.height - ShadowHeight();
+  self.viewController.view.frame = popupControllerFrame;
+}
+
+- (void)animateAppearance:(CGFloat)parentHeight {
+  CGRect popupFrame = [self.positioner popupFrame:parentHeight];
+  CALayer* popupLayer = self.popupContainerView.layer;
+  CGRect bounds = popupLayer.bounds;
+  bounds.size.height = popupFrame.size.height;
+  popupLayer.bounds = bounds;
+
+  CGRect frame = self.popupContainerView.frame;
+  frame.size.width = popupFrame.size.width;
+  frame.origin.y = popupFrame.origin.y;
+  self.popupContainerView.frame = frame;
+
+  CABasicAnimation* growHeight =
+      [CABasicAnimation animationWithKeyPath:@"bounds.size.height"];
+  growHeight.fromValue = @0;
+  growHeight.toValue = [NSNumber numberWithFloat:popupFrame.size.height];
+  growHeight.duration = kExpandAnimationDuration;
+  growHeight.timingFunction =
+      [CAMediaTimingFunction functionWithControlPoints:0.4:0:0.2:1];
+  [popupLayer addAnimation:growHeight forKey:@"growHeight"];
+}
+
+- (void)animateCollapse {
+  CALayer* popupLayer = self.popupContainerView.layer;
+  CGRect bounds = popupLayer.bounds;
+  CGFloat currentHeight = bounds.size.height;
+  bounds.size.height = 0;
+  popupLayer.bounds = bounds;
+
+  UIView* retainedPopupView = self.popupContainerView;
+  [CATransaction begin];
+  [CATransaction setCompletionBlock:^{
+    [retainedPopupView removeFromSuperview];
+  }];
+  CABasicAnimation* shrinkHeight =
+      [CABasicAnimation animationWithKeyPath:@"bounds.size.height"];
+  shrinkHeight.fromValue = [NSNumber numberWithFloat:currentHeight];
+  shrinkHeight.toValue = @0;
+  shrinkHeight.duration = kCollapseAnimationDuration;
+  shrinkHeight.timingFunction =
+      [CAMediaTimingFunction functionWithControlPoints:0.4:0:1:1];
+  [popupLayer addAnimation:shrinkHeight forKey:@"shrinkHeight"];
+  [CATransaction commit];
+}
+
++ (UIView*)newBackgroundViewIpad {
+  UIView* view = [[UIView alloc] init];
+  [view setClipsToBounds:YES];
+
+  // Adjust popupView_'s anchor point and height so that it animates down
+  // from the top when it appears.
+  view.layer.anchorPoint = CGPointMake(0.5, 0);
+
+  [view setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
+  UIImageView* shadowView = [[UIImageView alloc]
+      initWithImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED)];
+  [shadowView setUserInteractionEnabled:NO];
+  [shadowView setTranslatesAutoresizingMaskIntoConstraints:NO];
+  [view addSubview:shadowView];
+
+  // Add constraints to position |shadowView| at the bottom of |view|
+  // with the same width as |view|.
+  NSDictionary* views = NSDictionaryOfVariableBindings(shadowView);
+  [view addConstraints:[NSLayoutConstraint
+                           constraintsWithVisualFormat:@"H:|[shadowView]|"
+                                               options:0
+                                               metrics:nil
+                                                 views:views]];
+  [view addConstraint:[NSLayoutConstraint
+                          constraintWithItem:shadowView
+                                   attribute:NSLayoutAttributeBottom
+                                   relatedBy:NSLayoutRelationEqual
+                                      toItem:view
+                                   attribute:NSLayoutAttributeBottom
+                                  multiplier:1
+                                    constant:0]];
+
+  return view;
+}
+
++ (UIView*)newBackgroundViewIPhone {
+  UIView* view = [[UIView alloc] init];
+
+  // Adjust popupView_'s anchor point and height so that it animates down
+  // from the top when it appears.
+  view.layer.anchorPoint = CGPointMake(0.5, 0);
+
+  // Add a white background to prevent seeing the logo scroll through the
+  // omnibox.
+  UIView* whiteBackground = [[UIView alloc] initWithFrame:CGRectZero];
+  [view addSubview:whiteBackground];
+  [whiteBackground setBackgroundColor:[UIColor whiteColor]];
+
+  // Set constraints to |whiteBackground|.
+  [whiteBackground setTranslatesAutoresizingMaskIntoConstraints:NO];
+  NSDictionary* metrics = @{ @"height" : @(kWhiteBackgroundHeight) };
+  NSDictionary* views = NSDictionaryOfVariableBindings(whiteBackground);
+  [view addConstraints:[NSLayoutConstraint
+                           constraintsWithVisualFormat:@"H:|[whiteBackground]|"
+                                               options:0
+                                               metrics:nil
+                                                 views:views]];
+  [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
+                                               @"V:[whiteBackground(==height)]"
+                                                               options:0
+                                                               metrics:metrics
+                                                                 views:views]];
+  [view addConstraint:[NSLayoutConstraint
+                          constraintWithItem:whiteBackground
+                                   attribute:NSLayoutAttributeBottom
+                                   relatedBy:NSLayoutRelationEqual
+                                      toItem:view
+                                   attribute:NSLayoutAttributeTop
+                                  multiplier:1
+                                    constant:0]];
+  return view;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
index 29a276d..bdc5428 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
@@ -12,6 +12,7 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 #include "components/omnibox/browser/omnibox_popup_view.h"
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h"
 
 class OmniboxEditModel;
 @class OmniboxPopupMaterialViewController;
@@ -19,13 +20,15 @@
 class OmniboxPopupViewSuggestionsDelegate;
 @protocol OmniboxPopupPositioner;
 struct AutocompleteMatch;
+@class OmniboxPopupPresenter;
 
 namespace ios {
 class ChromeBrowserState;
 }  // namespace ios
 
 // iOS implementation of AutocompletePopupView.
-class OmniboxPopupViewIOS : public OmniboxPopupView {
+class OmniboxPopupViewIOS : public OmniboxPopupView,
+                            public OmniboxPopupMaterialViewControllerDelegate {
  public:
   OmniboxPopupViewIOS(ios::ChromeBrowserState* browser_state,
                       OmniboxEditModel* edit_model,
@@ -43,26 +46,22 @@
   void PaintUpdatesNow() override {}
   void OnDragCanceled() override {}
 
-  void OpenURLForRow(size_t row);
-  void DidScroll();
   void UpdateEditViewIcon();
-  void CopyToOmnibox(const base::string16& text);
   void SetTextAlignment(NSTextAlignment alignment);
-  bool IsStarredMatch(const AutocompleteMatch& match) const;
-  void DeleteMatch(const AutocompleteMatch& match) const;
+
+  // OmniboxPopupMaterialViewControllerDelegate implementation.
+  bool IsStarredMatch(const AutocompleteMatch& match) const override;
+  void OnMatchSelected(const AutocompleteMatch& match, size_t row) override;
+  void OnMatchSelectedForAppending(const AutocompleteMatch& match) override;
+  void OnMatchSelectedForDeletion(const AutocompleteMatch& match) override;
+  void OnScroll() override;
 
  private:
   std::unique_ptr<OmniboxPopupModel> model_;
   OmniboxPopupViewSuggestionsDelegate* delegate_;  // weak
-  __weak id<OmniboxPopupPositioner> positioner_;
-  // View that contains the omnibox popup table view and shadow.
-  base::scoped_nsobject<UIView> popupView_;
+  base::scoped_nsobject<OmniboxPopupPresenter> presenter_;
   base::scoped_nsobject<OmniboxPopupMaterialViewController> popup_controller_;
   bool is_open_;
-  // Animate the appearance of the omnibox popup view.
-  void AnimateDropdownExpansion(CGFloat parentHeight);
-  // Animate the disappearance of the omnibox popup view.
-  void AnimateDropdownCollapse();
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_VIEW_IOS_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
index e9790f9..25af248 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
@@ -20,12 +20,13 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h"
-#import "ios/chrome/browser/ui/omnibox/omnibox_popup_positioner.h"
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_popup_view_suggestions_delegate.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
+#include "ios/web/public/web_thread.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -33,15 +34,6 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-const CGFloat kExpandAnimationDuration = 0.1;
-const CGFloat kCollapseAnimationDuration = 0.05;
-const CGFloat kWhiteBackgroundHeight = 74;
-NS_INLINE CGFloat ShadowHeight() {
-  return IsIPadIdiom() ? 10 : 0;
-}
-}  // namespace
-
 using base::UserMetricsAction;
 
 OmniboxPopupViewIOS::OmniboxPopupViewIOS(
@@ -51,7 +43,6 @@
     id<OmniboxPopupPositioner> positioner)
     : model_(new OmniboxPopupModel(this, edit_model)),
       delegate_(delegate),
-      positioner_(positioner),
       is_open_(false) {
   DCHECK(delegate);
   DCHECK(browser_state);
@@ -62,79 +53,12 @@
           browser_state->GetRequestContext());
 
   popup_controller_.reset([[OmniboxPopupMaterialViewController alloc]
-      initWithPopupView:this
-            withFetcher:std::move(imageFetcher)]);
+      initWithFetcher:std::move(imageFetcher)
+             delegate:this]);
   [popup_controller_ setIncognito:browser_state->IsOffTheRecord()];
-  popupView_.reset([[UIView alloc] initWithFrame:CGRectZero]);
-  [popupView_ setClipsToBounds:YES];
-  CALayer* popupLayer = [popupView_ layer];
-  // Adjust popupView_'s anchor point and height so that it animates down
-  // from the top when it appears.
-  popupLayer.anchorPoint = CGPointMake(0.5, 0);
-  UIView* popupControllerView = [popup_controller_ view];
-  CGRect popupControllerFrame = popupControllerView.frame;
-  popupControllerFrame.origin = CGPointZero;
-  popupControllerView.frame = popupControllerFrame;
-  [popupView_ addSubview:popupControllerView];
-  if (IsIPadIdiom()) {
-    [popupView_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
-    UIImageView* shadowView = [[UIImageView alloc]
-        initWithImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED)];
-    [shadowView setUserInteractionEnabled:NO];
-    [shadowView setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [popupView_ addSubview:shadowView];
-
-    // Add constraints to position |shadowView| at the bottom of |popupView_|
-    // with the same width as |popupView_|.
-    NSDictionary* views = NSDictionaryOfVariableBindings(shadowView);
-    [popupView_
-        addConstraints:[NSLayoutConstraint
-                           constraintsWithVisualFormat:@"H:|[shadowView]|"
-                                               options:0
-                                               metrics:nil
-                                                 views:views]];
-    [popupView_ addConstraint:[NSLayoutConstraint
-                                  constraintWithItem:shadowView
-                                           attribute:NSLayoutAttributeBottom
-                                           relatedBy:NSLayoutRelationEqual
-                                              toItem:popupView_
-                                           attribute:NSLayoutAttributeBottom
-                                          multiplier:1
-                                            constant:0]];
-  } else {
-    // Add a white background to prevent seeing the logo scroll through the
-    // omnibox.
-    UIView* whiteBackground = [[UIView alloc] initWithFrame:CGRectZero];
-    [popupView_ addSubview:whiteBackground];
-    [whiteBackground setBackgroundColor:[UIColor whiteColor]];
-
-    // Set constraints to |whiteBackground|.
-    [whiteBackground setTranslatesAutoresizingMaskIntoConstraints:NO];
-    NSDictionary* metrics = @{ @"height" : @(kWhiteBackgroundHeight) };
-    NSDictionary* views = NSDictionaryOfVariableBindings(whiteBackground);
-    [popupView_
-        addConstraints:[NSLayoutConstraint
-                           constraintsWithVisualFormat:@"H:|[whiteBackground]|"
-                                               options:0
-                                               metrics:nil
-                                                 views:views]];
-    [popupView_
-        addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
-                                               @"V:[whiteBackground(==height)]"
-                                                               options:0
-                                                               metrics:metrics
-                                                                 views:views]];
-    [popupView_ addConstraint:[NSLayoutConstraint
-                                  constraintWithItem:whiteBackground
-                                           attribute:NSLayoutAttributeBottom
-                                           relatedBy:NSLayoutRelationEqual
-                                              toItem:popupView_
-                                           attribute:NSLayoutAttributeTop
-                                          multiplier:1
-                                            constant:0]];
-    // |whiteBackground| extends out of |popupView_|
-    [popupView_ setClipsToBounds:NO];
-  }
+  presenter_.reset([[OmniboxPopupPresenter alloc]
+      initWithPopupPositioner:positioner
+          popupViewController:popup_controller_]);
 }
 
 OmniboxPopupViewIOS::~OmniboxPopupViewIOS() {
@@ -154,7 +78,6 @@
 
 void OmniboxPopupViewIOS::UpdatePopupAppearance() {
   const AutocompleteResult& result = model_->result();
-  UIView* view = popupView_;
 
   if (!is_open_ && !result.empty()) {
     // The popup is not currently open and there are results to display. Update
@@ -168,125 +91,44 @@
   is_open_ = !result.empty();
 
   if (is_open_) {
-    // Show |result.size| on iPad.  Since iPhone can dismiss keyboard, set
-    // height to frame height.
-    CGFloat height = [[popup_controller_ tableView] contentSize].height;
-    UIEdgeInsets insets = [[popup_controller_ tableView] contentInset];
-    // Note the calculation |insets.top * 2| is correct, it should not be
-    // insets.top + insets.bottom. |insets.bottom| will be larger than
-    // |insets.top| when the keyboard is visible, but |parentHeight| should stay
-    // the same.
-    CGFloat parentHeight = height + insets.top * 2 + ShadowHeight();
-    UIView* siblingView = [positioner_ popupAnchorView];
-    if (!IsIPadIdiom()) {
-      [view setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
-                                UIViewAutoresizingFlexibleHeight];
-      [[siblingView superview] insertSubview:view belowSubview:siblingView];
-    } else {
-      [[siblingView superview] insertSubview:view aboveSubview:siblingView];
-    }
-    CGFloat currentHeight = view.layer.bounds.size.height;
-    if (currentHeight == 0)
-      AnimateDropdownExpansion(parentHeight);
-    else
-      [view setFrame:[positioner_ popupFrame:parentHeight]];
-    UIView* popupControllerView = [popup_controller_ view];
-    CGRect popupControllerFrame = popupControllerView.frame;
-    popupControllerFrame.size.height = view.frame.size.height - ShadowHeight();
-    popupControllerView.frame = popupControllerFrame;
+    [presenter_ updateHeightAndAnimateAppearanceIfNecessary];
     UpdateEditViewIcon();
   } else {
-    AnimateDropdownCollapse();
+    [presenter_ animateCollapse];
   }
 
   delegate_->OnResultsChanged(result);
 }
 
-void OmniboxPopupViewIOS::AnimateDropdownExpansion(CGFloat parentHeight) {
-  CGRect popupFrame = [positioner_ popupFrame:parentHeight];
-  CALayer* popupLayer = [popupView_ layer];
-  CGRect bounds = popupLayer.bounds;
-  bounds.size.height = popupFrame.size.height;
-  popupLayer.bounds = bounds;
-
-  CGRect frame = [popupView_ frame];
-  frame.size.width = popupFrame.size.width;
-  frame.origin.y = popupFrame.origin.y;
-  [popupView_ setFrame:frame];
-
-  CABasicAnimation* growHeight =
-      [CABasicAnimation animationWithKeyPath:@"bounds.size.height"];
-  growHeight.fromValue = @0;
-  growHeight.toValue = [NSNumber numberWithFloat:popupFrame.size.height];
-  growHeight.duration = kExpandAnimationDuration;
-  growHeight.timingFunction =
-      [CAMediaTimingFunction functionWithControlPoints:0.4:0:0.2:1];
-  [popupLayer addAnimation:growHeight forKey:@"growHeight"];
-}
-
-void OmniboxPopupViewIOS::AnimateDropdownCollapse() {
-  CALayer* popupLayer = [popupView_ layer];
-  CGRect bounds = popupLayer.bounds;
-  CGFloat currentHeight = bounds.size.height;
-  bounds.size.height = 0;
-  popupLayer.bounds = bounds;
-
-  UIView* retainedPopupView = popupView_;
-  [CATransaction begin];
-  [CATransaction setCompletionBlock:^{
-    [retainedPopupView removeFromSuperview];
-  }];
-  CABasicAnimation* shrinkHeight =
-      [CABasicAnimation animationWithKeyPath:@"bounds.size.height"];
-  shrinkHeight.fromValue = [NSNumber numberWithFloat:currentHeight];
-  shrinkHeight.toValue = @0;
-  shrinkHeight.duration = kCollapseAnimationDuration;
-  shrinkHeight.timingFunction =
-      [CAMediaTimingFunction functionWithControlPoints:0.4:0:1:1];
-  [popupLayer addAnimation:shrinkHeight forKey:@"shrinkHeight"];
-  [CATransaction commit];
-}
-
 gfx::Rect OmniboxPopupViewIOS::GetTargetBounds() {
   return gfx::Rect();
 }
 
-// For phone, allow popup to take focus (and dismiss the keyboard) on scroll.
-void OmniboxPopupViewIOS::DidScroll() {
-  delegate_->OnPopupDidScroll();
-}
-
-// Puts omnibox back into focus with suggested search terms.
-void OmniboxPopupViewIOS::CopyToOmnibox(const base::string16& str) {
-  delegate_->OnSelectedMatchForAppending(str);
-}
-
 void OmniboxPopupViewIOS::SetTextAlignment(NSTextAlignment alignment) {
   [popup_controller_ setTextAlignment:alignment];
 }
 
+bool OmniboxPopupViewIOS::IsOpen() const {
+  return is_open_;
+}
+
+#pragma mark - OmniboxPopupMaterialViewControllerDelegate
+
 bool OmniboxPopupViewIOS::IsStarredMatch(const AutocompleteMatch& match) const {
   return model_->IsStarredMatch(match);
 }
 
-void OmniboxPopupViewIOS::DeleteMatch(const AutocompleteMatch& match) const {
-  model_->autocomplete_controller()->DeleteMatch(match);
-}
-
-void OmniboxPopupViewIOS::OpenURLForRow(size_t row) {
-  // Crash reports tell us that |row| is sometimes indexed past the end of
-  // the results array. In those cases, just ignore the request and return
-  // early. See b/5813291.
-  if (row >= model_->result().size())
-    return;
-
+void OmniboxPopupViewIOS::OnMatchSelected(
+    const AutocompleteMatch& selectedMatch,
+    size_t row) {
   WindowOpenDisposition disposition = WindowOpenDisposition::CURRENT_TAB;
   base::RecordAction(UserMetricsAction("MobileOmniboxUse"));
 
   // OpenMatch() may close the popup, which will clear the result set and, by
   // extension, |match| and its contents.  So copy the relevant match out to
   // make sure it stays alive until the call completes.
-  AutocompleteMatch match = model_->result().match_at(row);
+  AutocompleteMatch match = selectedMatch;
+
   if (match.type == AutocompleteMatchType::CLIPBOARD) {
     base::RecordAction(UserMetricsAction("MobileOmniboxClipboardToURL"));
     UMA_HISTOGRAM_LONG_TIMES_100(
@@ -297,6 +139,19 @@
                                        base::string16(), row);
 }
 
-bool OmniboxPopupViewIOS::IsOpen() const {
-  return is_open_;
+void OmniboxPopupViewIOS::OnMatchSelectedForAppending(
+    const AutocompleteMatch& match) {
+  // Make a defensive copy of |match.contents|, as CopyToOmnibox() will trigger
+  // a new round of autocomplete and modify |match|.
+  base::string16 contents(match.contents);
+  delegate_->OnSelectedMatchForAppending(contents);
+}
+
+void OmniboxPopupViewIOS::OnMatchSelectedForDeletion(
+    const AutocompleteMatch& match) {
+  model_->autocomplete_controller()->DeleteMatch(match);
+}
+
+void OmniboxPopupViewIOS::OnScroll() {
+  delegate_->OnPopupDidScroll();
 }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.h b/ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.h
new file mode 100644
index 0000000..917963c
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.h
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_TEXT_FIELD_PASTE_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_TEXT_FIELD_PASTE_DELEGATE_H_
+
+#import <UIKit/UIKit.h>
+
+// Implements UITextPasteDelegate to workaround http://crbug.com/755620.
+@interface OmniboxTextFieldPasteDelegate : NSObject
+@end
+
+@interface OmniboxTextFieldPasteDelegate (
+    UITextPasteDelegate)<UITextPasteDelegate>
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_TEXT_FIELD_PASTE_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.mm
new file mode 100644
index 0000000..b9b50f7
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.mm
@@ -0,0 +1,62 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.h"
+
+#import "base/mac/foundation_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface OmniboxTextFieldPasteDelegate ()
+
+@property(nonatomic, strong) NSURL* URL;
+
+@end
+
+@implementation OmniboxTextFieldPasteDelegate
+@synthesize URL = _URL;
+
+- (void)textPasteConfigurationSupporting:
+    (id<UITextPasteConfigurationSupporting>)textPasteConfigurationSupporting
+    transformPasteItem:(id<UITextPasteItem>)item
+    API_AVAILABLE(ios(11.0)) {
+  if ([item.itemProvider canLoadObjectOfClass:[NSURL class]]) {
+    [item.itemProvider
+        loadObjectOfClass:[NSURL class]
+        completionHandler:^(id<NSItemProviderReading> _Nullable object,
+                            NSError* _Nullable error) {
+          if (!error) {
+            self.URL = base::mac::ObjCCast<NSURL>(object);
+          }
+          [item setDefaultResult];
+        }];
+  } else {
+    [item setDefaultResult];
+  }
+}
+
+- (NSAttributedString*)textPasteConfigurationSupporting:
+    (id<UITextPasteConfigurationSupporting>)textPasteConfigurationSupporting
+    combineItemAttributedStrings:(NSArray<NSAttributedString*>*)itemStrings
+                        forRange:(UITextRange*)textRange
+    API_AVAILABLE(ios(11.0)) {
+  // If there's a cached URL, use that. Otherwise, use one of the item strings.
+  if (self.URL) {
+    NSString* URLString = [self.URL absoluteString];
+    self.URL = nil;
+    return [[NSAttributedString alloc] initWithString:URLString];
+  } else {
+    // Return only one item string to avoid repetition, for example when there
+    // are both a URL and a string in the pasteboard.
+    NSAttributedString* string = [itemStrings firstObject];
+    if (!string) {
+      string = [[NSAttributedString alloc] init];
+    }
+    return string;
+  }
+}
+
+@end
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
index 715c097..ef577f7 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
@@ -19,6 +19,7 @@
 @class AutocompleteTextFieldDelegate;
 class GURL;
 @class OmniboxTextFieldIOS;
+@class OmniboxTextFieldPasteDelegate;
 @protocol OmniboxPopupPositioner;
 class WebOmniboxEditController;
 class OmniboxPopupViewIOS;
@@ -169,6 +170,7 @@
   ios::ChromeBrowserState* browser_state_;
 
   base::scoped_nsobject<OmniboxTextFieldIOS> field_;
+  base::scoped_nsobject<OmniboxTextFieldPasteDelegate> paste_delegate_;
   WebOmniboxEditController* controller_;  // weak, owns us
   std::unique_ptr<OmniboxPopupViewIOS> popup_view_;
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
index 87fceb25..bb274616 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -26,6 +26,7 @@
 #include "ios/chrome/browser/prerender/preload_provider.h"
 #include "ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h"
+#include "ios/chrome/browser/ui/omnibox/omnibox_text_field_paste_delegate.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
@@ -177,6 +178,12 @@
       this->browser_state(), model(), this, positioner);
   field_delegate_.reset(
       [[AutocompleteTextFieldDelegate alloc] initWithEditView:this]);
+
+  if (@available(iOS 11.0, *)) {
+    paste_delegate_.reset([[OmniboxTextFieldPasteDelegate alloc] init]);
+    [field_ setPasteDelegate:paste_delegate_];
+  }
+
   [field_ setDelegate:field_delegate_];
   [field_ addTarget:field_delegate_
                 action:@selector(textFieldDidChange:)
diff --git a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm
index b1bc0b1..aa4f4007 100644
--- a/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_edit_view_controller.mm
@@ -578,9 +578,13 @@
   // present before the editor fields.
   NSInteger index = indexPath.section;
   if ([self.collectionViewModel
-          hasSectionForSectionIdentifier:SectionIdentifierHeader])
+          hasSectionForSectionIdentifier:SectionIdentifierHeader]) {
     index--;
-  DCHECK(index >= 0 && index < static_cast<NSInteger>(self.fields.count));
+  }
+  // Early return if the header or the footer sections are selected.
+  if (index < 0 || index >= static_cast<NSInteger>(self.fields.count))
+    return;
+
   EditorField* field = [self.fields objectAtIndex:index];
 
   // If a selector field is selected, blur the focused text field.
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index eddd2da..6483c0e2 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -390,8 +390,8 @@
 
 - (void)resetIOSPaymentInstrumentLauncherDelegate {
   payments::IOSPaymentInstrumentLauncher* paymentAppLauncher =
-      payments::IOSPaymentInstrumentLauncherFactory::GetInstance()
-          ->GetForBrowserState(_browserState);
+      payments::IOSPaymentInstrumentLauncherFactory::GetForBrowserState(
+          _browserState->GetOriginalChromeBrowserState());
   DCHECK(paymentAppLauncher);
   paymentAppLauncher->set_delegate(nullptr);
 }
@@ -713,8 +713,8 @@
   BOOL canMakePayment = paymentRequest->CanMakePayment();
 
   payments::CanMakePaymentQuery* canMakePaymentQuery =
-      IOSCanMakePaymentQueryFactory::GetInstance()->GetForBrowserState(
-          _browserState);
+      IOSCanMakePaymentQueryFactory::GetForBrowserState(
+          _browserState->GetOriginalChromeBrowserState());
   DCHECK(canMakePaymentQuery);
   // iOS PaymentRequest does not support iframes.
   if (canMakePaymentQuery->CanQuery(
@@ -960,8 +960,8 @@
   [_paymentRequestCoordinator setCancellable:YES];
 
   payments::IOSPaymentInstrumentLauncher* paymentAppLauncher =
-      payments::IOSPaymentInstrumentLauncherFactory::GetInstance()
-          ->GetForBrowserState(_browserState);
+      payments::IOSPaymentInstrumentLauncherFactory::GetForBrowserState(
+          _browserState->GetOriginalChromeBrowserState());
   DCHECK(paymentAppLauncher);
   if (!paymentAppLauncher->LaunchIOSPaymentInstrument(
           _pendingPaymentRequest, _activeWebState, universalLink, delegate)) {
diff --git a/ios/chrome/browser/ui/sad_tab/BUILD.gn b/ios/chrome/browser/ui/sad_tab/BUILD.gn
index 4b96b07..b54cb962 100644
--- a/ios/chrome/browser/ui/sad_tab/BUILD.gn
+++ b/ios/chrome/browser/ui/sad_tab/BUILD.gn
@@ -28,6 +28,19 @@
   libs = [ "UIKit.framework" ]
 }
 
+source_set("coordinator") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "sad_tab_legacy_coordinator.h",
+    "sad_tab_legacy_coordinator.mm",
+  ]
+  deps = [
+    ":sad_tab",
+    "//ios/chrome/browser/web:tab_helper_delegates",
+    "//ios/web",
+  ]
+}
+
 source_set("eg_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h
new file mode 100644
index 0000000..71620c6
--- /dev/null
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SAD_TAB_SAD_TAB_LEGACY_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_UI_SAD_TAB_SAD_TAB_LEGACY_COORDINATOR_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/chrome/browser/web/sad_tab_tab_helper_delegate.h"
+
+@class CommandDispatcher;
+
+namespace web {
+class WebState;
+}
+
+// Coordinator that displays a SadTab view.
+@interface SadTabLegacyCoordinator : NSObject<SadTabTabHelperDelegate>
+
+// The dispatcher for this Coordinator.
+@property(nonatomic, weak) CommandDispatcher* dispatcher;
+
+// The web state this SadTabLegacyCoordinator is handling. This might change
+// during the life of the Coordinator and might be null.
+@property(nonatomic, assign) web::WebState* webState;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SAD_TAB_SAD_TAB_LEGACY_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.mm
new file mode 100644
index 0000000..da410da
--- /dev/null
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.mm
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h"
+
+#import "ios/chrome/browser/ui/sad_tab/sad_tab_view.h"
+#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/web_state/ui/crw_generic_content_view.h"
+#include "ios/web/public/web_state/web_state.h"
+
+@implementation SadTabLegacyCoordinator
+@synthesize dispatcher = _dispatcher;
+@synthesize webState = _webState;
+
+#pragma mark - SadTabTabHelperDelegate
+
+- (void)presentSadTabForRepeatedFailure:(BOOL)repeatedFailure {
+  // Create a SadTabView so |webstate| presents it.
+  SadTabView* sadTabview = [[SadTabView alloc]
+           initWithMode:repeatedFailure ? SadTabViewMode::FEEDBACK
+                                        : SadTabViewMode::RELOAD
+      navigationManager:self.webState->GetNavigationManager()];
+  sadTabview.dispatcher = static_cast<id<ApplicationCommands>>(self.dispatcher);
+  CRWContentView* contentView =
+      [[CRWGenericContentView alloc] initWithView:sadTabview];
+  self.webState->ShowTransientContentView(contentView);
+}
+
+@end
diff --git a/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm
index 9eb6d2c..2b325f2 100644
--- a/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm
@@ -9,7 +9,6 @@
 #import "base/mac/foundation_util.h"
 
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
diff --git a/ios/chrome/browser/ui/tabs/tab_view.mm b/ios/chrome/browser/ui/tabs/tab_view.mm
index 63209fe68..afb41c0 100644
--- a/ios/chrome/browser/ui/tabs/tab_view.mm
+++ b/ios/chrome/browser/ui/tabs/tab_view.mm
@@ -15,7 +15,6 @@
 #include "ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h"
 #include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #import "ios/chrome/browser/ui/image_util.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
diff --git a/ios/chrome/browser/ui/toolbar/new_tab_button.mm b/ios/chrome/browser/ui/toolbar/new_tab_button.mm
index 4c06605..5522fbd 100644
--- a/ios/chrome/browser/ui/toolbar/new_tab_button.mm
+++ b/ios/chrome/browser/ui/toolbar/new_tab_button.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/toolbar/new_tab_button.h"
 
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/image_util.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
index bc93d48..9b91ea5 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
@@ -48,19 +48,9 @@
 - (IBAction)locationBarDidResignFirstResponder:(id)sender;
 // Called when the location bar receives a key press.
 - (IBAction)locationBarBeganEdit:(id)sender;
-// Called when the stack view controller is about to be shown.
-- (IBAction)prepareToEnterTabSwitcher:(id)sender;
 // Returns the WebState.
 - (web::WebState*)currentWebState;
-// Called when the toolbar height changes. Other elements, such as the web view,
-// may need to adjust accordingly. This is called from within an animation
-// block.
-- (void)toolbarHeightChanged;
 - (ToolbarModelIOS*)toolbarModelIOS;
-// Sets the alpha for the toolbar's background views.
-- (void)updateToolbarBackgroundAlpha:(CGFloat)backgroundAlpha;
-// Sets the alpha for the toolbar's background views.
-- (void)updateToolbarControlsAlpha:(CGFloat)controlsAlpha;
 @optional
 // Called before the toolbar screenshot gets updated.
 - (void)willUpdateToolbarSnapshot;
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h b/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
index dca87ad8..06a2625 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_constants.h
@@ -59,6 +59,8 @@
   TOOLS_SHOW_HELP_PAGE = -18,
   TOOLS_SHOW_BOOKMARKS = -19,
   TOOLS_SHOW_RECENT_TABS = -20,
+  TOOLS_REQUEST_DESKTOP_SITE = -21,
+  TOOLS_REQUEST_MOBILE_SITE = -22,
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_TOOLS_MENU_TOOLS_MENU_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
index 8c1ab19a..79f160a 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
@@ -8,7 +8,6 @@
 #include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/ui/commands/application_commands.h"
 #include "ios/chrome/browser/ui/commands/browser_commands.h"
-#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/tools_menu/new_tab_menu_view_item.h"
 #import "ios/chrome/browser/ui/tools_menu/reading_list_menu_view_item.h"
 #include "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
@@ -30,11 +29,6 @@
 // Declare all the possible items. If adding or removing items update
 // kToolsMenuNumberOfItems with the new total count.
 
-// Formatting note: While these items are being refactored to use selectors
-// and the dispatcher instead of ChromeExecuteCommand (see crbug.com/738881),
-// the |command_id| and |selector| fields are grouped together, since one will
-// be either 0 or nullptr. Once the refactor is complete, all of the
-// |command_id| values will be 0, and that struct field will be removed.
 const MenuItemInfo itemInfoList[kToolsMenuNumberOfItems] = {
     // clang-format off
   { IDS_IOS_TOOLS_MENU_NEW_TAB,           kToolsMenuNewTabId,
@@ -78,11 +72,13 @@
     0,                                    nil },
   { IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE,
     kToolsMenuRequestDesktopId,
-    IDC_REQUEST_DESKTOP_SITE, nullptr,    ToolbarTypeWebAll,
+    TOOLS_REQUEST_DESKTOP_SITE,
+    @selector(requestDesktopSite),    ToolbarTypeWebAll,
     0,                                    nil },
   { IDS_IOS_TOOLS_MENU_REQUEST_MOBILE_SITE,
     kToolsMenuRequestMobileId,
-    IDC_REQUEST_MOBILE_SITE, nullptr,     ToolbarTypeWebAll,
+    TOOLS_REQUEST_MOBILE_SITE,
+    @selector(requestMobileSite),     ToolbarTypeWebAll,
     0,                                    nil },
   { IDS_IOS_TOOLS_MENU_SETTINGS,          kToolsMenuSettingsId,
     TOOLS_SETTINGS_ITEM,
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
index d66c97b9..b53841d 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -16,7 +16,6 @@
 #include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/animation_util.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_menu_notification_delegate.h"
@@ -290,13 +289,13 @@
   // "Request Desktop Site" and "Request Mobile Site".
   switch (configuration.userAgentType) {
     case web::UserAgentType::NONE:
-      [self setItemEnabled:NO withTag:IDC_REQUEST_DESKTOP_SITE];
+      [self setItemEnabled:NO withTag:TOOLS_REQUEST_DESKTOP_SITE];
       break;
     case web::UserAgentType::MOBILE:
-      [self setItemEnabled:YES withTag:IDC_REQUEST_DESKTOP_SITE];
+      [self setItemEnabled:YES withTag:TOOLS_REQUEST_DESKTOP_SITE];
       break;
     case web::UserAgentType::DESKTOP:
-      [self setItemEnabled:YES withTag:IDC_REQUEST_MOBILE_SITE];
+      [self setItemEnabled:YES withTag:TOOLS_REQUEST_MOBILE_SITE];
       break;
   }
 
@@ -517,16 +516,12 @@
 #pragma mark - Button event handling
 
 - (void)buttonPressed:(id)sender {
-  int commandId = [sender tag];
-  DCHECK(commandId);
-  // Do not use -chromeExecuteCommand: for tags < 0 -- that is, items that have
-  // been refactored to use the dispatcher.
-  if (commandId > 0) {
-    [self chromeExecuteCommand:sender];
-  }
-
+  int commandID = [sender tag];
+  // All command IDs should have been refactored to be < 0, and not use
+  // ChromeExecuteCommand.
+  DCHECK(commandID < 0);
   // Do any metrics logging for the command, and then close the menu.
-  [_delegate commandWasSelected:commandId];
+  [_delegate commandWasSelected:commandID];
 }
 
 #pragma mark - UICollectionViewDelegate Implementation
@@ -594,13 +589,11 @@
   dispatch_after(
       _waitForInk ? delayTime : 0, dispatch_get_main_queue(), ^(void) {
         ToolsMenuViewItem* menuItem = [_menuItems objectAtIndex:item];
-        DCHECK([menuItem tag]);
+        // Tag values > 0, and use of the ChromeExecuteCommand pattern from the
+        // menu, is no longer supported.
+        DCHECK([menuItem tag] < 0);
         [_delegate commandWasSelected:[menuItem tag]];
-        if ([menuItem tag] > 0) {
-          [self chromeExecuteCommand:menuItem];
-        } else {
-          [menuItem executeCommandWithDispatcher:self.dispatcher];
-        }
+        [menuItem executeCommandWithDispatcher:self.dispatcher];
       });
 }
 
@@ -622,8 +615,8 @@
     ToolsMenuViewToolsCell* cell =
         [view dequeueReusableCellWithReuseIdentifier:kToolsItemCellID
                                         forIndexPath:path];
-    // Add specific target/action dispatch for buttons refactored away from
-    // ChromeExecuteCommand. These need to be added *before* -buttonPressed:,
+    // Add specific target/action dispatch for buttons.
+    // These need to be added *before* -buttonPressed:,
     // because -buttonPressed: closes the popup menu, which will usually
     // destroy the buttons before any other actions can be called.
     [cell.stopButton addTarget:self.dispatcher
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
index 0923da1a..74c0a72 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
@@ -6,8 +6,8 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "ios/chrome/browser/experimental_flags.h"
-#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/tools_menu/tools_menu_configuration.h"
+#import "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
 #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_item.h"
 #include "ios/web/public/user_agent.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -44,12 +44,12 @@
   [controller_ initializeMenuWithConfiguration:configuration_.get()];
 
   ToolsMenuViewItem* desktop_item =
-      GetToolsMenuViewItemWithTag(IDC_REQUEST_DESKTOP_SITE);
+      GetToolsMenuViewItemWithTag(TOOLS_REQUEST_DESKTOP_SITE);
   ASSERT_TRUE(desktop_item);
   EXPECT_FALSE(desktop_item.active);
 
   ToolsMenuViewItem* mobile_item =
-      GetToolsMenuViewItemWithTag(IDC_REQUEST_MOBILE_SITE);
+      GetToolsMenuViewItemWithTag(TOOLS_REQUEST_MOBILE_SITE);
   EXPECT_FALSE(mobile_item);
 }
 
@@ -61,12 +61,12 @@
   [controller_ initializeMenuWithConfiguration:configuration_.get()];
 
   ToolsMenuViewItem* desktop_item =
-      GetToolsMenuViewItemWithTag(IDC_REQUEST_DESKTOP_SITE);
+      GetToolsMenuViewItemWithTag(TOOLS_REQUEST_DESKTOP_SITE);
   ASSERT_TRUE(desktop_item);
   EXPECT_TRUE(desktop_item.active);
 
   ToolsMenuViewItem* mobile_item =
-      GetToolsMenuViewItemWithTag(IDC_REQUEST_MOBILE_SITE);
+      GetToolsMenuViewItemWithTag(TOOLS_REQUEST_MOBILE_SITE);
   EXPECT_FALSE(mobile_item);
 }
 
@@ -80,9 +80,9 @@
   [controller_ initializeMenuWithConfiguration:configuration_.get()];
 
   ToolsMenuViewItem* desktop_item =
-      GetToolsMenuViewItemWithTag(IDC_REQUEST_DESKTOP_SITE);
+      GetToolsMenuViewItemWithTag(TOOLS_REQUEST_DESKTOP_SITE);
   ToolsMenuViewItem* mobile_item =
-      GetToolsMenuViewItemWithTag(IDC_REQUEST_MOBILE_SITE);
+      GetToolsMenuViewItemWithTag(TOOLS_REQUEST_MOBILE_SITE);
 
   EXPECT_FALSE(desktop_item);
   ASSERT_TRUE(mobile_item);
diff --git a/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
index fff70340..8c7bdc4e 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_popup_controller.mm
@@ -9,7 +9,6 @@
 #include "base/logging.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
-#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_view.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/tools_menu/tools_menu_configuration.h"
@@ -193,10 +192,10 @@
     case TOOLS_SHARE_ITEM:
       base::RecordAction(UserMetricsAction("MobileMenuShare"));
       break;
-    case IDC_REQUEST_DESKTOP_SITE:
+    case TOOLS_REQUEST_DESKTOP_SITE:
       base::RecordAction(UserMetricsAction("MobileMenuRequestDesktopSite"));
       break;
-    case IDC_REQUEST_MOBILE_SITE:
+    case TOOLS_REQUEST_MOBILE_SITE:
       base::RecordAction(UserMetricsAction("MobileMenuRequestMobileSite"));
       break;
     case TOOLS_SHOW_BOOKMARKS:
diff --git a/ios/chrome/browser/upgrade/upgrade_center.mm b/ios/chrome/browser/upgrade/upgrade_center.mm
index 5baf55e0..9b12d171 100644
--- a/ios/chrome/browser/upgrade/upgrade_center.mm
+++ b/ios/chrome/browser/upgrade/upgrade_center.mm
@@ -18,7 +18,6 @@
 #include "components/infobars/core/infobar_manager.h"
 #include "components/version_info/version_info.h"
 #import "ios/chrome/browser/open_url_util.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index e98ea99..3c09af9 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -95,6 +95,7 @@
     "//base:base",
     "//base/test:test_support",
     "//components/strings:components_strings_grit",
+    "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/ui:ui",
     "//ios/chrome/test:test_support",
     "//ios/web:web",
@@ -307,10 +308,11 @@
   ]
   deps = [
     "//base",
+    "//base/test:test_support",
+    "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/test/base:perf_test_support",
     "//ios/web",
     "//ios/web/public/test",
-    "//ios/web/public/test/fakes",
   ]
   libs = [ "WebKit.framework" ]
 }
diff --git a/ios/chrome/browser/web/chrome_web_client_unittest.mm b/ios/chrome/browser/web/chrome_web_client_unittest.mm
index 9c43c5f3..0f3dcbe 100644
--- a/ios/chrome/browser/web/chrome_web_client_unittest.mm
+++ b/ios/chrome/browser/web/chrome_web_client_unittest.mm
@@ -13,15 +13,16 @@
 #include "base/strings/string_split.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
 #include "components/payments/core/features.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/passwords/credential_manager_features.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/public/test/js_test_util.h"
 #include "ios/web/public/test/scoped_testing_web_client.h"
-#include "ios/web/public/test/web_test.h"
 #import "ios/web/public/web_view_creation_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -29,8 +30,22 @@
 
 namespace {
 
-// Test fixture for testing ChromeWebClient.
-typedef web::WebTest ChromeWebClientTest;
+class ChromeWebClientTest : public PlatformTest {
+ public:
+  ChromeWebClientTest() {
+    browser_state_ = TestChromeBrowserState::Builder().Build();
+  }
+
+  ~ChromeWebClientTest() override = default;
+
+  ios::ChromeBrowserState* browser_state() { return browser_state_.get(); }
+
+ private:
+  base::test::ScopedTaskEnvironment environment_;
+  std::unique_ptr<ios::ChromeBrowserState> browser_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeWebClientTest);
+};
 
 TEST_F(ChromeWebClientTest, UserAgent) {
   std::vector<std::string> pieces;
@@ -77,12 +92,11 @@
 // Tests that ChromeWebClient provides print script for WKWebView.
 TEST_F(ChromeWebClientTest, WKWebViewEarlyPageScriptPrint) {
   // Chrome scripts rely on __gCrWeb object presence.
-  web::TestBrowserState browser_state;
-  WKWebView* web_view = web::BuildWKWebView(CGRectZero, &browser_state);
+  WKWebView* web_view = web::BuildWKWebView(CGRectZero, browser_state());
   web::ExecuteJavaScript(web_view, @"__gCrWeb = {};");
 
   web::ScopedTestingWebClient web_client(base::MakeUnique<ChromeWebClient>());
-  NSString* script = web_client.Get()->GetEarlyPageScript(&browser_state);
+  NSString* script = web_client.Get()->GetEarlyPageScript(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"object",
               web::ExecuteJavaScript(web_view, @"typeof __gCrWeb.print"));
@@ -92,12 +106,11 @@
 // if and only if the feature is enabled.
 TEST_F(ChromeWebClientTest, WKWebViewEarlyPageScriptCredentialManager) {
   // Chrome scripts rely on __gCrWeb object presence.
-  web::TestBrowserState browser_state;
-  WKWebView* web_view = web::BuildWKWebView(CGRectZero, &browser_state);
+  WKWebView* web_view = web::BuildWKWebView(CGRectZero, browser_state());
   web::ExecuteJavaScript(web_view, @"__gCrWeb = {};");
 
   web::ScopedTestingWebClient web_client(base::MakeUnique<ChromeWebClient>());
-  NSString* script = web_client.Get()->GetEarlyPageScript(&browser_state);
+  NSString* script = web_client.Get()->GetEarlyPageScript(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"undefined", web::ExecuteJavaScript(
                                 web_view, @"typeof navigator.credentials"));
@@ -105,7 +118,7 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
       credential_manager::features::kCredentialManager);
-  script = web_client.Get()->GetEarlyPageScript(&browser_state);
+  script = web_client.Get()->GetEarlyPageScript(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"object", web::ExecuteJavaScript(
                              web_view, @"typeof navigator.credentials"));
@@ -115,19 +128,18 @@
 // WKWebView unless the feature is enabled.
 TEST_F(ChromeWebClientTest, WKWebViewEarlyPageScriptPaymentRequest) {
   // Chrome scripts rely on __gCrWeb object presence.
-  web::TestBrowserState browser_state;
-  WKWebView* web_view = web::BuildWKWebView(CGRectZero, &browser_state);
+  WKWebView* web_view = web::BuildWKWebView(CGRectZero, browser_state());
   web::ExecuteJavaScript(web_view, @"__gCrWeb = {};");
 
   web::ScopedTestingWebClient web_client(base::MakeUnique<ChromeWebClient>());
-  NSString* script = web_client.Get()->GetEarlyPageScript(&browser_state);
+  NSString* script = web_client.Get()->GetEarlyPageScript(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"undefined", web::ExecuteJavaScript(
                                 web_view, @"typeof window.PaymentRequest"));
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(payments::features::kWebPayments);
-  script = web_client.Get()->GetEarlyPageScript(&browser_state);
+  script = web_client.Get()->GetEarlyPageScript(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"function", web::ExecuteJavaScript(
                                web_view, @"typeof window.PaymentRequest"));
diff --git a/ios/chrome/browser/web/early_page_script_perftest.mm b/ios/chrome/browser/web/early_page_script_perftest.mm
index 7851e54..50a4121 100644
--- a/ios/chrome/browser/web/early_page_script_perftest.mm
+++ b/ios/chrome/browser/web/early_page_script_perftest.mm
@@ -3,9 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/mac/bundle_locations.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/timer/elapsed_timer.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/test/base/perf_test_ios.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/public/test/js_test_util.h"
 #import "ios/web/public/web_view_creation_util.h"
 #import "ios/web/web_state/js/page_script_util.h"
@@ -24,16 +25,19 @@
 class EarlyPageScriptPerfTest : public PerfTest {
  protected:
   EarlyPageScriptPerfTest() : PerfTest("Early Page Script for WKWebView") {
-    web_view_ = web::BuildWKWebView(CGRectZero, &browser_state_);
+    browser_state_ = TestChromeBrowserState::Builder().Build();
+    web_view_ = web::BuildWKWebView(CGRectZero, browser_state());
   }
 
   // Injects early script into WKWebView.
   void InjectEarlyScript() {
-    web::ExecuteJavaScript(web_view_, web::GetEarlyPageScript(&browser_state_));
+    web::ExecuteJavaScript(web_view_, web::GetEarlyPageScript(browser_state()));
   }
 
+  ios::ChromeBrowserState* browser_state() { return browser_state_.get(); }
+
   // BrowserState required for web view creation.
-  web::TestBrowserState browser_state_;
+  std::unique_ptr<ios::ChromeBrowserState> browser_state_;
   // WKWebView to test scripts injections.
   WKWebView* web_view_;
 };
@@ -43,7 +47,7 @@
   RepeatTimedRuns("Loading",
                   ^base::TimeDelta(int) {
                     base::ElapsedTimer timer;
-                    web::GetEarlyPageScript(&browser_state_);
+                    web::GetEarlyPageScript(browser_state());
                     return timer.Elapsed();
                   },
                   nil);
diff --git a/ios/chrome/browser/web/features.mm b/ios/chrome/browser/web/features.mm
index 778d3d5..80a2047 100644
--- a/ios/chrome/browser/web/features.mm
+++ b/ios/chrome/browser/web/features.mm
@@ -12,4 +12,4 @@
 // Feature flag to prompt user to choose a mail client app. Change the default
 // value here to enable or disable this feature.
 const base::Feature kMailtoPromptForUserChoice{
-    "MailtoPromptForUserChoice", base::FEATURE_DISABLED_BY_DEFAULT};
+    "MailtoPromptForUserChoice", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/web/resources/credential_manager.js b/ios/chrome/browser/web/resources/credential_manager.js
index 72857b0..700d527 100644
--- a/ios/chrome/browser/web/resources/credential_manager.js
+++ b/ios/chrome/browser/web/resources/credential_manager.js
@@ -28,7 +28,7 @@
 __gCrWeb.credentialManager = {
 
   /**
-   * Used to apply unique requestId fields to messages sent to host.
+   * Used to apply unique promiseId fields to messages sent to host.
    * Those IDs can be later used to call a corresponding resolver/rejecter.
    * @private {number}
    */
@@ -37,7 +37,7 @@
   /**
    * Stores the functions for resolving Promises returned by
    * navigator.credentials method calls. A resolver for a call with
-   * requestId: |id| is stored at resolvers_[id].
+   * promiseId: |id| is stored at resolvers_[id].
    * @type {!Object<number, function(?Credential)|function()>}
    * @private
    */
@@ -46,7 +46,7 @@
   /**
    * Stores the functions for rejecting Promises returned by
    * navigator.credentials method calls. A rejecter for a call with
-   * requestId: |id| is stored at rejecters_[id].
+   * promiseId: |id| is stored at rejecters_[id].
    * @type {!Object<number, function(?Error)>}
    * @private
    */
@@ -56,19 +56,19 @@
 __gCrWeb['credentialManager'] = __gCrWeb.credentialManager;
 
 /**
- * Creates and returns a Promise with given |requestId|. The Promise's executor
+ * Creates and returns a Promise with given |promiseId|. The Promise's executor
  * function stores resolver and rejecter functions in
- * __gCrWeb['credentialManager'] under the key |requestId| so they can be called
+ * __gCrWeb['credentialManager'] under the key |promiseId| so they can be called
  * from the host after executing app side code.
- * @param {number} requestId The number assigned to newly created Promise.
+ * @param {number} promiseId The number assigned to newly created Promise.
  * @return {!Promise<?Credential>|!Promise<!Credential>|!Promise<void>}
  *     The created Promise.
  * @private
  */
-__gCrWeb.credentialManager.createPromise_ = function(requestId) {
+__gCrWeb.credentialManager.createPromise_ = function(promiseId) {
   return new Promise(function(resolve, reject) {
-    __gCrWeb.credentialManager.resolvers_[requestId] = resolve;
-    __gCrWeb.credentialManager.rejecters_[requestId] = reject;
+    __gCrWeb.credentialManager.resolvers_[promiseId] = resolve;
+    __gCrWeb.credentialManager.rejecters_[promiseId] = reject;
   });
 };
 
@@ -82,16 +82,16 @@
  * @private
  */
 __gCrWeb.credentialManager.invokeOnHost_ = function(command, options) {
-  var requestId = __gCrWeb.credentialManager.nextId_++;
+  var promiseId = __gCrWeb.credentialManager.nextId_++;
   var message = {
     'command': command,
-    'requestId': requestId
+    'promiseId': promiseId
   };
   if (options) {
     Object.assign(message, options);
   }
   __gCrWeb.message.invokeOnHost(message);
-  return __gCrWeb.credentialManager.createPromise_(requestId);
+  return __gCrWeb.credentialManager.createPromise_(promiseId);
 };
 
 /**
diff --git a/ios/chrome/browser/web/sad_tab_tab_helper.mm b/ios/chrome/browser/web/sad_tab_tab_helper.mm
index e9966367..d575077 100644
--- a/ios/chrome/browser/web/sad_tab_tab_helper.mm
+++ b/ios/chrome/browser/web/sad_tab_tab_helper.mm
@@ -120,8 +120,7 @@
       (url_causing_failure.EqualsIgnoringRef(last_failed_url_) &&
        seconds_since_last_failure < repeat_failure_interval_);
 
-  [delegate_ sadTabHelper:this
-      presentSadTabForRepeatedFailure:repeated_failure];
+  [delegate_ presentSadTabForRepeatedFailure:repeated_failure];
 
   last_failed_url_ = url_causing_failure;
   last_failed_timer_ = base::MakeUnique<base::ElapsedTimer>();
diff --git a/ios/chrome/browser/web/sad_tab_tab_helper_delegate.h b/ios/chrome/browser/web/sad_tab_tab_helper_delegate.h
index 8309ae3..9b489587 100644
--- a/ios/chrome/browser/web/sad_tab_tab_helper_delegate.h
+++ b/ios/chrome/browser/web/sad_tab_tab_helper_delegate.h
@@ -7,14 +7,11 @@
 
 #import <Foundation/Foundation.h>
 
-class SadTabTabHelper;
-
 // Delegate for SadTabTabHelper.
 @protocol SadTabTabHelperDelegate<NSObject>
 
 // Asks the delegate to present a SadTabView.
-- (void)sadTabHelper:(SadTabTabHelper*)tabHelper
-    presentSadTabForRepeatedFailure:(BOOL)repeatedFailure;
+- (void)presentSadTabForRepeatedFailure:(BOOL)repeatedFailure;
 
 @end
 
diff --git a/ios/chrome/browser/web/sad_tab_tab_helper_unittest.mm b/ios/chrome/browser/web/sad_tab_tab_helper_unittest.mm
index db2f7866..4ac50c7c 100644
--- a/ios/chrome/browser/web/sad_tab_tab_helper_unittest.mm
+++ b/ios/chrome/browser/web/sad_tab_tab_helper_unittest.mm
@@ -6,10 +6,11 @@
 
 #include <memory>
 
+#include "base/test/scoped_task_environment.h"
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper.h"
 #import "ios/chrome/browser/web/page_placeholder_tab_helper_delegate.h"
 #import "ios/chrome/browser/web/sad_tab_tab_helper_delegate.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #import "ios/web/public/web_state/ui/crw_generic_content_view.h"
@@ -33,8 +34,7 @@
 @synthesize sadTabShown = sadTabShown;
 @synthesize repeatedFailure = _repeatedFailure;
 
-- (void)sadTabHelper:(SadTabTabHelper*)tabHelper
-    presentSadTabForRepeatedFailure:(BOOL)repeatedFailure {
+- (void)presentSadTabForRepeatedFailure:(BOOL)repeatedFailure {
   self.sadTabShown = YES;
   self.repeatedFailure = repeatedFailure;
 }
@@ -48,6 +48,8 @@
         sad_tab_delegate_([[SadTabTabHelperTestDelegate alloc] init]),
         page_placeholder_delegate_([OCMockObject
             mockForProtocol:@protocol(PagePlaceholderTabHelperDelegate)]) {
+    browser_state_ = TestChromeBrowserState::Builder().Build();
+
     SadTabTabHelper::CreateForWebState(&web_state_, sad_tab_delegate_);
     PagePlaceholderTabHelper::CreateForWebState(&web_state_,
                                                 page_placeholder_delegate_);
@@ -56,13 +58,15 @@
     // Setup navigation manager.
     std::unique_ptr<web::TestNavigationManager> navigation_manager =
         base::MakeUnique<web::TestNavigationManager>();
-    navigation_manager->SetBrowserState(&browser_state_);
+    navigation_manager->SetBrowserState(browser_state_.get());
     navigation_manager_ = navigation_manager.get();
     web_state_.SetNavigationManager(std::move(navigation_manager));
   }
 
   ~SadTabTabHelperTest() override { [application_ stopMocking]; }
-  web::TestBrowserState browser_state_;
+
+  base::test::ScopedTaskEnvironment environment_;
+  std::unique_ptr<ios::ChromeBrowserState> browser_state_;
   web::TestWebState web_state_;
   web::TestNavigationManager* navigation_manager_;
   id application_;
diff --git a/ios/chrome/common/OWNERS b/ios/chrome/common/OWNERS
new file mode 100644
index 0000000..b67c133
--- /dev/null
+++ b/ios/chrome/common/OWNERS
@@ -0,0 +1,4 @@
+lod@chromium.org
+olivierrobin@chromium.org
+# TEAM: ios-directory-owners@chromium.org
+# OS: iOS
diff --git a/ios/chrome/common/physical_web/DEPS b/ios/chrome/common/physical_web/DEPS
index 306b209..894d7dc2 100644
--- a/ios/chrome/common/physical_web/DEPS
+++ b/ios/chrome/common/physical_web/DEPS
@@ -4,5 +4,4 @@
 include_rules = [
   "+device/bluetooth/uribeacon",
   "+google_apis",
-  "+ios/web/public",
 ]
diff --git a/ios/chrome/content_widget_extension/OWNERS b/ios/chrome/content_widget_extension/OWNERS
index 2b72d62..b67c133 100644
--- a/ios/chrome/content_widget_extension/OWNERS
+++ b/ios/chrome/content_widget_extension/OWNERS
@@ -1,3 +1,4 @@
 lod@chromium.org
+olivierrobin@chromium.org
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/search_widget_extension/OWNERS b/ios/chrome/search_widget_extension/OWNERS
index 2b72d62..b67c133 100644
--- a/ios/chrome/search_widget_extension/OWNERS
+++ b/ios/chrome/search_widget_extension/OWNERS
@@ -1,3 +1,4 @@
 lod@chromium.org
+olivierrobin@chromium.org
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/share_extension/OWNERS b/ios/chrome/share_extension/OWNERS
index 56360bb..b67c133 100644
--- a/ios/chrome/share_extension/OWNERS
+++ b/ios/chrome/share_extension/OWNERS
@@ -1,4 +1,4 @@
+lod@chromium.org
 olivierrobin@chromium.org
-
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 04e031f..52ed31c 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -130,6 +130,7 @@
     "//ios/chrome/app/application_delegate:unit_tests",
     "//ios/chrome/app/safe_mode:unit_tests",
     "//ios/chrome/app/spotlight:unit_tests",
+    "//ios/chrome/app/startup:unit_tests",
     "//ios/chrome/browser:unit_tests",
     "//ios/chrome/browser/autofill:unit_tests",
     "//ios/chrome/browser/browsing_data:unit_tests",
diff --git a/ios/chrome/test/DEPS b/ios/chrome/test/DEPS
index 8fa7387..651885c3 100644
--- a/ios/chrome/test/DEPS
+++ b/ios/chrome/test/DEPS
@@ -20,7 +20,6 @@
   "+ios/chrome/browser",
   "+ios/public/provider/chrome",
   "+ios/public/test",
-  "+ios/web/public",
   "+net/url_request",
   "+third_party/google_toolbox_for_mac",
   "+ui",
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 19aabb0..8a8eea9 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -12,6 +12,7 @@
     ":ios_chrome_flaky_egtests",
     ":ios_chrome_integration_egtests",
     ":ios_chrome_multitasking_egtests",
+    ":ios_chrome_perf_egtests",
     ":ios_chrome_reading_list_egtests",
     ":ios_chrome_settings_egtests",
     ":ios_chrome_smoke_egtests",
@@ -111,6 +112,12 @@
   eg_main_application_delegate = "MultitaskingTestApplicationDelegate"
 }
 
+chrome_ios_eg_test("ios_chrome_perf_egtests") {
+  deps = [
+    "//ios/chrome/test/perf:eg_tests",
+  ]
+}
+
 chrome_ios_eg_test("ios_chrome_device_check_egtests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
diff --git a/ios/chrome/test/perf/BUILD.gn b/ios/chrome/test/perf/BUILD.gn
new file mode 100644
index 0000000..445c761
--- /dev/null
+++ b/ios/chrome/test/perf/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("eg_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "chrome_perf_egtests.mm",
+  ]
+  deps = [
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing/perf:startup",
+  ]
+}
diff --git a/ios/chrome/test/perf/chrome_perf_egtests.mm b/ios/chrome/test/perf/chrome_perf_egtests.mm
new file mode 100644
index 0000000..c90e37d
--- /dev/null
+++ b/ios/chrome/test/perf/chrome_perf_egtests.mm
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <XCTest/XCTest.h>
+
+#import "ios/testing/perf/startupLoggers.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Test class for chrome performance tests.
+@interface ChromePerfTestCase : XCTestCase
+@end
+
+@implementation ChromePerfTestCase
+
+- (void)testChromeColdStartup {
+  XCTAssertTrue(startup_loggers::LogData(@"testChromeColdStartup"));
+}
+
+@end
diff --git a/ios/clean/chrome/DEPS b/ios/clean/chrome/DEPS
index d9539617..f0762f8 100644
--- a/ios/clean/chrome/DEPS
+++ b/ios/clean/chrome/DEPS
@@ -5,8 +5,13 @@
   "+ios/shared",
   "+ios/testing/perf",
   "+ios/third_party",
-  "+ios/web",
 
   # Strings and resources.
   "+components/strings/grit",
+
+  # All code in ios/clean/chrome assumes that web::BrowserState* can be safely
+  # casted to ios::ChromeBrowserState*. This mean that no code should use
+  # web::TestBrowserState in ios/clean/chrome.
+  "+ios/web/public",
+  "-ios/web/public/test/fakes/test_browser_state.h",
 ]
diff --git a/ios/clean/chrome/app/BUILD.gn b/ios/clean/chrome/app/BUILD.gn
index 580d9ea..ef91046 100644
--- a/ios/clean/chrome/app/BUILD.gn
+++ b/ios/clean/chrome/app/BUILD.gn
@@ -80,7 +80,6 @@
     ":app",
     "//base",
     "//components/crash/core/common",
-    "//ios/chrome/app:app_internal",
     "//ios/chrome/app/startup",
     "//ios/chrome/app/startup:startup_basic",
     "//ios/chrome/browser",
@@ -123,9 +122,11 @@
   deps = [
     ":application_state",
     "//base",
+    "//ios/chrome/app/startup",
     "//ios/clean/chrome/app/steps:step_runner",
     "//ios/clean/chrome/app/steps:steps",
     "//ios/clean/chrome/browser",
     "//ios/testing/perf:startup",
+    "//net",
   ]
 }
diff --git a/ios/clean/chrome/app/app_delegate.mm b/ios/clean/chrome/app/app_delegate.mm
index bc319283..2dbcff7 100644
--- a/ios/clean/chrome/app/app_delegate.mm
+++ b/ios/clean/chrome/app/app_delegate.mm
@@ -6,9 +6,11 @@
 
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
+#include "ios/chrome/app/startup/chrome_app_startup_parameters.h"
 #import "ios/clean/chrome/app/application_state.h"
 #import "ios/clean/chrome/browser/url_opening.h"
 #import "ios/testing/perf/startupLoggers.h"
+#include "net/base/mac/url_conversions.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -104,7 +106,13 @@
 - (BOOL)application:(UIApplication*)application
             openURL:(NSURL*)url
             options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options {
-  [self.applicationState.URLOpener openURL:url];
+  NSString* sourceApplication =
+      options[UIApplicationOpenURLOptionsSourceApplicationKey];
+  ChromeAppStartupParameters* params = [ChromeAppStartupParameters
+      newChromeAppStartupParametersWithURL:url
+                     fromSourceApplication:sourceApplication];
+  [self.applicationState.URLOpener
+      openURL:net::NSURLWithGURL(params.externalURL)];
   return YES;
 }
 
diff --git a/ios/clean/chrome/browser/ui/adaptor/browser_commands_adaptor.mm b/ios/clean/chrome/browser/ui/adaptor/browser_commands_adaptor.mm
index 819617c5..08a73a8 100644
--- a/ios/clean/chrome/browser/ui/adaptor/browser_commands_adaptor.mm
+++ b/ios/clean/chrome/browser/ui/adaptor/browser_commands_adaptor.mm
@@ -142,6 +142,14 @@
   [self showAlert:@"navigateToHistoryItem:"];
 }
 
+- (void)requestDesktopSite {
+  [self showAlert:@"requestDesktopSite"];
+}
+
+- (void)requestMobileSite {
+  [self showAlert:@"requestMobileSite"];
+}
+
 #pragma mark - Private
 
 // TODO(crbug.com/740793): Remove this method once no method is using it.
diff --git a/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.h b/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.h
index 70e90da..85f66a2 100644
--- a/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.h
+++ b/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.h
@@ -13,8 +13,8 @@
 // own or inside the NTP.
 @interface BookmarksCoordinator : BrowserCoordinator
 
-// Whether the ViewController created by this coordinator will be contained.
-@property(nonatomic, assign) BOOL contained;
+// The presentation mode of this coordinator. Needs to be set before |-start|.
+@property(nonatomic, assign) BrowserCoordinatorMode mode;
 
 @end
 
diff --git a/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm b/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
index 2f0ac40..05b41157 100644
--- a/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
@@ -17,7 +17,6 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.h"
 #import "ios/chrome/browser/ui/browser_list/browser.h"
 #import "ios/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
-#include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/clean/chrome/browser/ui/adaptor/url_loader_adaptor.h"
 #include "ios/web/public/referrer.h"
 
@@ -34,7 +33,7 @@
 @end
 
 @implementation BookmarksCoordinator
-@synthesize contained = _contained;
+@synthesize mode = _mode;
 @synthesize viewController = _viewController;
 @synthesize bookmarkBrowser = _bookmarkBrowser;
 @synthesize loader = _loader;
@@ -43,8 +42,10 @@
   if (self.started)
     return;
 
+  DCHECK(self.mode != UNDEFINED);
+
   self.loader = [[URLLoaderAdaptor alloc] init];
-  if (!self.contained) {
+  if (self.mode == PRESENTED) {
     BookmarkControllerFactory* bookmarkControllerFactory =
         [[BookmarkControllerFactory alloc] init];
     self.bookmarkBrowser = [bookmarkControllerFactory
diff --git a/ios/clean/chrome/browser/ui/dialogs/dialog_coordinator_unittest.mm b/ios/clean/chrome/browser/ui/dialogs/dialog_coordinator_unittest.mm
index 50f6efd5..0c3c99de 100644
--- a/ios/clean/chrome/browser/ui/dialogs/dialog_coordinator_unittest.mm
+++ b/ios/clean/chrome/browser/ui/dialogs/dialog_coordinator_unittest.mm
@@ -17,7 +17,6 @@
 #import "ios/clean/chrome/browser/ui/dialogs/dialog_view_controller.h"
 #import "ios/clean/chrome/browser/ui/dialogs/test_helpers/test_dialog_mediator.h"
 #import "ios/clean/chrome/browser/ui/overlays/test_helpers/overlay_coordinator_test.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/ios/clean/chrome/browser/ui/dialogs/dialog_mediator_unittest.mm b/ios/clean/chrome/browser/ui/dialogs/dialog_mediator_unittest.mm
index 64f52f1c..b9db00e 100644
--- a/ios/clean/chrome/browser/ui/dialogs/dialog_mediator_unittest.mm
+++ b/ios/clean/chrome/browser/ui/dialogs/dialog_mediator_unittest.mm
@@ -17,7 +17,6 @@
 #import "ios/clean/chrome/browser/ui/dialogs/test_helpers/test_dialog_mediator.h"
 #import "ios/clean/chrome/browser/ui/dialogs/test_helpers/test_dialog_view_controller.h"
 #import "ios/clean/chrome/browser/ui/overlays/test_helpers/test_overlay_queue.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
diff --git a/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.h b/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.h
index 910ae6e4..805a1ccd 100644
--- a/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.h
+++ b/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.h
@@ -7,30 +7,24 @@
 
 #import <Foundation/Foundation.h>
 
+#import "ios/chrome/browser/ui/browser_list/browser_user_data.h"
 #include "ios/web/public/java_script_dialog_presenter.h"
-#import "ios/web/public/web_state/web_state_user_data.h"
 
 class OverlayService;
 
 // A concrete subclass of web::JavaScriptDialogPresenter that is associated with
-// a WebState via its UserData.  It uses OverlayService to present dialogs.
+// a Browser via its UserData.  It uses OverlayService to present dialogs.
 class JavaScriptDialogOverlayPresenter
-    : public web::JavaScriptDialogPresenter,
-      public web::WebStateUserData<JavaScriptDialogOverlayPresenter> {
+    : public BrowserUserData<JavaScriptDialogOverlayPresenter>,
+      public web::JavaScriptDialogPresenter {
  public:
-  // Factory method for a presenter that uses |overlay_service| to show dialogs.
-  static void CreateForWebState(web::WebState* web_state,
-                                OverlayService* overlay_service);
-
   ~JavaScriptDialogOverlayPresenter() override;
 
  private:
-  friend class web::WebStateUserData<JavaScriptDialogOverlayPresenter>;
+  friend class BrowserUserData<JavaScriptDialogOverlayPresenter>;
 
-  // Private constructor.  New instances should be created via
-  // CreateForWebState() and accessed via FromWebState().
-  explicit JavaScriptDialogOverlayPresenter(web::WebState* web_state,
-                                            OverlayService* overlay_service);
+  // Private constructor used by factory method.
+  explicit JavaScriptDialogOverlayPresenter(Browser* browser);
 
   // JavaScriptDialogPresenter:
   void RunJavaScriptDialog(web::WebState* web_state,
@@ -41,8 +35,6 @@
                            const web::DialogClosedCallback& callback) override;
   void CancelDialogs(web::WebState* web_state) override;
 
-  // The WebState with which this presenter is associated.
-  web::WebState* web_state_;
   // The OverlayService to use for the dialogs.
   OverlayService* overlay_service_;
 
diff --git a/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.mm b/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.mm
index 4600f4d..e470f8bd 100644
--- a/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.mm
+++ b/ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.mm
@@ -4,36 +4,22 @@
 
 #import "ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_overlay_presenter.h"
 
+#import "ios/chrome/browser/ui/browser_list/browser.h"
 #import "ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_coordinator.h"
 #import "ios/clean/chrome/browser/ui/dialogs/java_script_dialogs/java_script_dialog_request.h"
 #import "ios/clean/chrome/browser/ui/overlays/overlay_service.h"
+#import "ios/clean/chrome/browser/ui/overlays/overlay_service_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-DEFINE_WEB_STATE_USER_DATA_KEY(JavaScriptDialogOverlayPresenter);
-
-// static
-void JavaScriptDialogOverlayPresenter::CreateForWebState(
-    web::WebState* web_state,
-    OverlayService* overlay_service) {
-  DCHECK(web_state);
-  if (!FromWebState(web_state)) {
-    std::unique_ptr<JavaScriptDialogOverlayPresenter> presenter =
-        base::WrapUnique(
-            new JavaScriptDialogOverlayPresenter(web_state, overlay_service));
-    web_state->SetUserData(UserDataKey(), std::move(presenter));
-  }
-}
+DEFINE_BROWSER_USER_DATA_KEY(JavaScriptDialogOverlayPresenter);
 
 JavaScriptDialogOverlayPresenter::JavaScriptDialogOverlayPresenter(
-    web::WebState* web_state,
-    OverlayService* overlay_service)
-    : web_state_(web_state), overlay_service_(overlay_service) {
-  DCHECK(web_state_);
-  DCHECK(overlay_service_);
-}
+    Browser* browser)
+    : overlay_service_(OverlayServiceFactory::GetInstance()->GetForBrowserState(
+          browser->browser_state())) {}
 
 JavaScriptDialogOverlayPresenter::~JavaScriptDialogOverlayPresenter() {}
 
@@ -44,9 +30,6 @@
     NSString* message_text,
     NSString* default_prompt_text,
     const web::DialogClosedCallback& callback) {
-  // This presenter should only attempt to present dialogs from its associated
-  // WebState.
-  DCHECK_EQ(web_state_, web_state);
   // Create a new coordinator and add it to the overlay queue.
   JavaScriptDialogRequest* request =
       [JavaScriptDialogRequest requestWithWebState:web_state
diff --git a/ios/clean/chrome/browser/ui/ntp/ntp_coordinator.mm b/ios/clean/chrome/browser/ui/ntp/ntp_coordinator.mm
index 779ffd6..a072183 100644
--- a/ios/clean/chrome/browser/ui/ntp/ntp_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/ntp/ntp_coordinator.mm
@@ -66,8 +66,8 @@
   if ([coordinator isKindOfClass:[NTPHomeCoordinator class]]) {
     self.viewController.homeViewController = coordinator.viewController;
 
-  } else if ([coordinator isKindOfClass:[BookmarksCoordinator class]]) {
-    if (IsIPadIdiom()) {
+  } else if (coordinator == self.bookmarksCoordinator) {
+    if (self.bookmarksCoordinator.mode == CONTAINED) {
       self.viewController.bookmarksViewController = coordinator.viewController;
     } else {
       coordinator.viewController.modalPresentationStyle =
@@ -77,8 +77,8 @@
                                       completion:nil];
     }
 
-  } else if ([coordinator isKindOfClass:[RecentTabsCoordinator class]]) {
-    if (IsIPadIdiom()) {
+  } else if (coordinator == self.recentTabsCoordinator) {
+    if (self.recentTabsCoordinator.mode == CONTAINED) {
       self.viewController.recentTabsViewController = coordinator.viewController;
     } else {
       coordinator.viewController.modalPresentationStyle =
@@ -117,7 +117,7 @@
 - (void)showNTPBookmarksPanel {
   if (!self.bookmarksCoordinator) {
     self.bookmarksCoordinator = [[BookmarksCoordinator alloc] init];
-    self.bookmarksCoordinator.contained = IsIPadIdiom();
+    self.bookmarksCoordinator.mode = IsIPadIdiom() ? CONTAINED : PRESENTED;
     [self addChildCoordinator:self.bookmarksCoordinator];
   }
   [self.bookmarksCoordinator start];
@@ -126,6 +126,7 @@
 - (void)showNTPRecentTabsPanel {
   if (!self.recentTabsCoordinator) {
     self.recentTabsCoordinator = [[RecentTabsCoordinator alloc] init];
+    self.recentTabsCoordinator.mode = IsIPadIdiom() ? CONTAINED : PRESENTED;
     [self addChildCoordinator:self.recentTabsCoordinator];
   }
   [self.recentTabsCoordinator start];
diff --git a/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm b/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm
index 9a55fddda..c9ce556 100644
--- a/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/ntp/ntp_home_coordinator.mm
@@ -128,8 +128,7 @@
       initWithBrowserState:self.browser->browser_state()
               webStateList:&self.browser->web_state_list()];
   self.googleLandingMediator.dispatcher =
-      static_cast<id<BrowserCommands, ChromeExecuteCommand, UrlLoader>>(
-          self.router);
+      static_cast<id<BrowserCommands, UrlLoader>>(self.router);
 
   favicon::LargeIconService* largeIconService =
       IOSChromeLargeIconServiceFactory::GetForBrowserState(
diff --git a/ios/clean/chrome/browser/ui/overlays/BUILD.gn b/ios/clean/chrome/browser/ui/overlays/BUILD.gn
index 972772f..9685401b 100644
--- a/ios/clean/chrome/browser/ui/overlays/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/overlays/BUILD.gn
@@ -78,9 +78,9 @@
     ":overlays_internal",
     "//base",
     "//base/test:test_support",
-    "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/ui/browser_list",
     "//ios/chrome/browser/ui/coordinators",
+    "//ios/chrome/browser/ui/coordinators:test_support",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/test/base",
     "//ios/clean/chrome/browser/ui/commands",
diff --git a/ios/clean/chrome/browser/ui/overlays/overlay_queue_manager_unittest.mm b/ios/clean/chrome/browser/ui/overlays/overlay_queue_manager_unittest.mm
index e043ac6..dc8dc86 100644
--- a/ios/clean/chrome/browser/ui/overlays/overlay_queue_manager_unittest.mm
+++ b/ios/clean/chrome/browser/ui/overlays/overlay_queue_manager_unittest.mm
@@ -4,15 +4,16 @@
 
 #import "ios/clean/chrome/browser/ui/overlays/overlay_queue_manager.h"
 
+#include <memory>
+
 #include "base/memory/ptr_util.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/ui/browser_list/browser.h"
+#import "ios/chrome/browser/ui/coordinators/browser_coordinator_test.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #import "ios/clean/chrome/browser/ui/overlays/overlay_queue.h"
 #import "ios/clean/chrome/browser/ui/overlays/test_helpers/test_overlay_coordinator.h"
 #import "ios/clean/chrome/browser/ui/overlays/test_helpers/test_overlay_queue_manager_observer.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #include "ios/web/public/test/fakes/test_web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
@@ -37,12 +38,10 @@
 }
 }
 
-class OverlayQueueManagerTest : public PlatformTest {
+class OverlayQueueManagerTest : public BrowserCoordinatorTest {
  public:
-  OverlayQueueManagerTest()
-      : PlatformTest(),
-        browser_(ios::ChromeBrowserState::FromBrowserState(&browser_state_)) {
-    OverlayQueueManager::CreateForBrowser(&browser_);
+  OverlayQueueManagerTest() {
+    OverlayQueueManager::CreateForBrowser(GetBrowser());
     manager()->AddObserver(&observer_);
   }
 
@@ -51,17 +50,18 @@
     manager()->Disconnect();
   }
 
-  Browser* browser() { return &browser_; }
-  WebStateList* web_state_list() { return &browser_.web_state_list(); }
+  WebStateList* web_state_list() { return &(GetBrowser()->web_state_list()); }
+
   OverlayQueueManager* manager() {
-    return OverlayQueueManager::FromBrowser(browser());
+    return OverlayQueueManager::FromBrowser(GetBrowser());
   }
+
   TestOverlayQueueManagerObserver* observer() { return &observer_; }
 
  private:
-  web::TestBrowserState browser_state_;
-  Browser browser_;
   TestOverlayQueueManagerObserver observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(OverlayQueueManagerTest);
 };
 
 // Tests that an OverlayQueueManager for a Browser with no WebStates contains
diff --git a/ios/clean/chrome/browser/ui/overlays/overlay_scheduler_unittest.mm b/ios/clean/chrome/browser/ui/overlays/overlay_scheduler_unittest.mm
index da91c478..5c50e81 100644
--- a/ios/clean/chrome/browser/ui/overlays/overlay_scheduler_unittest.mm
+++ b/ios/clean/chrome/browser/ui/overlays/overlay_scheduler_unittest.mm
@@ -5,7 +5,7 @@
 #import "ios/clean/chrome/browser/ui/overlays/overlay_scheduler.h"
 
 #include "base/memory/ptr_util.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/ui/coordinators/browser_coordinator_test.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h"
@@ -17,7 +17,6 @@
 #import "ios/clean/chrome/browser/ui/overlays/test_helpers/test_overlay_queue.h"
 #import "ios/clean/chrome/browser/ui/overlays/test_helpers/test_overlay_queue_observer.h"
 #import "ios/clean/chrome/browser/ui/overlays/web_state_overlay_queue.h"
-#include "ios/web/public/test/fakes/test_browser_state.h"
 #include "ios/web/public/test/fakes/test_web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
@@ -47,44 +46,44 @@
 };
 
 // Test fixture for OverlayScheduler.
-class OverlaySchedulerTest : public PlatformTest {
+class OverlaySchedulerTest : public BrowserCoordinatorTest {
  public:
-  OverlaySchedulerTest()
-      : PlatformTest(),
-        browser_(ios::ChromeBrowserState::FromBrowserState(&browser_state_)),
-        observer_(&browser_.web_state_list()) {
-    OverlayQueueManager::CreateForBrowser(&browser_);
-    OverlayScheduler::CreateForBrowser(&browser_);
+  OverlaySchedulerTest() {
+    observer_ =
+        std::make_unique<TestOverlaySchedulerObserver>(web_state_list());
+
+    OverlayQueueManager::CreateForBrowser(GetBrowser());
+    OverlayScheduler::CreateForBrowser(GetBrowser());
     scheduler()->SetQueueManager(manager());
-    scheduler()->AddObserver(&observer_);
+    scheduler()->AddObserver(observer());
   }
 
   ~OverlaySchedulerTest() override {
-    scheduler()->RemoveObserver(&observer_);
+    scheduler()->RemoveObserver(observer());
     scheduler()->Disconnect();
   }
 
-  Browser* browser() { return &browser_; }
-  WebStateList* web_state_list() { return &browser_.web_state_list(); }
-  TestOverlaySchedulerObserver* observer() { return &observer_; }
+  WebStateList* web_state_list() { return &(GetBrowser()->web_state_list()); }
+
+  TestOverlaySchedulerObserver* observer() { return observer_.get(); }
   OverlayQueueManager* manager() {
-    return OverlayQueueManager::FromBrowser(browser());
+    return OverlayQueueManager::FromBrowser(GetBrowser());
   }
   OverlayScheduler* scheduler() {
-    return OverlayScheduler::FromBrowser(browser());
+    return OverlayScheduler::FromBrowser(GetBrowser());
   }
 
  private:
-  web::TestBrowserState browser_state_;
-  Browser browser_;
-  TestOverlaySchedulerObserver observer_;
+  std::unique_ptr<TestOverlaySchedulerObserver> observer_;
   TestOverlayQueue queue_;
+
+  DISALLOW_COPY_AND_ASSIGN(OverlaySchedulerTest);
 };
 
 // Tests that adding an overlay to the BrowserOverlayQueue triggers successful
 // presentation.
 TEST_F(OverlaySchedulerTest, AddBrowserOverlay) {
-  BrowserOverlayQueue* queue = BrowserOverlayQueue::FromBrowser(browser());
+  BrowserOverlayQueue* queue = BrowserOverlayQueue::FromBrowser(GetBrowser());
   ASSERT_TRUE(queue);
   TestOverlayParentCoordinator* parent =
       [[TestOverlayParentCoordinator alloc] init];
diff --git a/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.h b/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.h
index d095fc5..f4cecea 100644
--- a/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.h
+++ b/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.h
@@ -11,6 +11,10 @@
 // A coordinator for the recent tabs UI, which can be presented modally on its
 // own or inside the NTP.
 @interface RecentTabsCoordinator : BrowserCoordinator
+
+// The presentation mode of this coordinator. Needs to be set before |-start|.
+@property(nonatomic, assign) BrowserCoordinatorMode mode;
+
 @end
 
 #endif  // IOS_CLEAN_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_COORDINATOR_H_
diff --git a/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
index 143d444..106aa94 100644
--- a/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -21,7 +21,6 @@
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
 #import "ios/chrome/browser/ui/sync/synced_sessions_bridge.h"
-#include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/clean/chrome/browser/ui/adaptor/application_commands_adaptor.h"
 #import "ios/clean/chrome/browser/ui/adaptor/url_loader_adaptor.h"
 
@@ -46,12 +45,18 @@
 @end
 
 @implementation RecentTabsCoordinator
+@synthesize mode = _mode;
 @synthesize viewController = _viewController;
 @synthesize tableViewController = _tableViewController;
 @synthesize loader = _loader;
 @synthesize applicationCommandAdaptor = _applicationCommandAdaptor;
 
 - (void)start {
+  if (self.started)
+    return;
+
+  DCHECK(self.mode != UNDEFINED);
+
   self.loader = [[URLLoaderAdaptor alloc] init];
   self.applicationCommandAdaptor = [[ApplicationCommandsAdaptor alloc] init];
   // HACK: Re-using old view controllers for now.
@@ -61,7 +66,7 @@
                 dispatcher:self.applicationCommandAdaptor];
   self.tableViewController.delegate = self;
 
-  if (!IsIPadIdiom()) {
+  if (self.mode == PRESENTED) {
     RecentTabsHandsetViewController* handsetViewController =
         [[RecentTabsHandsetViewController alloc]
             initWithViewController:self.tableViewController];
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm b/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm
index e5b71197..59c106b 100644
--- a/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm
@@ -117,12 +117,8 @@
 - (web::JavaScriptDialogPresenter*)javaScriptDialogPresenterForWebState:
     (web::WebState*)webState {
   DCHECK_EQ(self.webState, webState);
-  OverlayService* overlayService =
-      OverlayServiceFactory::GetInstance()->GetForBrowserState(
-          self.browser->browser_state());
-  JavaScriptDialogOverlayPresenter::CreateForWebState(self.webState,
-                                                      overlayService);
-  return JavaScriptDialogOverlayPresenter::FromWebState(self.webState);
+  JavaScriptDialogOverlayPresenter::CreateForBrowser(self.browser);
+  return JavaScriptDialogOverlayPresenter::FromBrowser(self.browser);
 }
 
 - (void)webState:(web::WebState*)webState
diff --git a/ios/testing/perf/startupLoggers.mm b/ios/testing/perf/startupLoggers.mm
index cd9d6611..b4c3eee7 100644
--- a/ios/testing/perf/startupLoggers.mm
+++ b/ios/testing/perf/startupLoggers.mm
@@ -21,13 +21,10 @@
 }
 
 void RegisterAppDidFinishLaunchingTime() {
-  DCHECK(g_start_time);
-  DCHECK(!g_finish_launching_time);
   g_finish_launching_time = new base::Time(base::Time::Now());
 }
 
 void RegisterAppDidBecomeActiveTime() {
-  DCHECK(g_start_time);
   g_become_active_time = new base::Time(base::Time::Now());
 }
 
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index a717934..d5499060 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -116,8 +116,8 @@
 void AudioInputDevice::Start() {
   DCHECK(callback_) << "Initialize hasn't been called";
   DVLOG(1) << "Start()";
-  task_runner()->PostTask(FROM_HERE,
-      base::Bind(&AudioInputDevice::StartUpOnIOThread, this));
+  task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&AudioInputDevice::StartUpOnIOThread, this));
 }
 
 void AudioInputDevice::Stop() {
@@ -129,8 +129,8 @@
     stopping_hack_ = true;
   }
 
-  task_runner()->PostTask(FROM_HERE,
-      base::Bind(&AudioInputDevice::ShutDownOnIOThread, this));
+  task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&AudioInputDevice::ShutDownOnIOThread, this));
 }
 
 void AudioInputDevice::SetVolume(double volume) {
@@ -139,15 +139,17 @@
     return;
   }
 
-  task_runner()->PostTask(FROM_HERE,
-      base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume));
+  task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&AudioInputDevice::SetVolumeOnIOThread, this, volume));
 }
 
 void AudioInputDevice::SetAutomaticGainControl(bool enabled) {
   DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")";
-  task_runner()->PostTask(FROM_HERE,
-      base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread,
-          this, enabled));
+  task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&AudioInputDevice::SetAutomaticGainControlOnIOThread, this,
+                     enabled));
 }
 
 void AudioInputDevice::OnStreamCreated(base::SharedMemoryHandle handle,
@@ -178,11 +180,11 @@
   if (initially_muted)
     callback_->OnCaptureMuted(true);
 
-  audio_callback_.reset(new AudioInputDevice::AudioThreadCallback(
+  audio_callback_ = std::make_unique<AudioInputDevice::AudioThreadCallback>(
       audio_parameters_, handle, kRequestedSharedMemoryCount, callback_,
-      base::BindRepeating(&AudioInputDevice::SetLastCallbackTimeToNow, this)));
-  audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(),
-                                            socket_handle, "AudioInputDevice"));
+      base::BindRepeating(&AudioInputDevice::SetLastCallbackTimeToNow, this));
+  audio_thread_ = std::make_unique<AudioDeviceThread>(
+      audio_callback_.get(), socket_handle, "AudioInputDevice");
 
   state_ = RECORDING;
   ipc_->RecordStream();
@@ -190,7 +192,7 @@
   // Start detecting missing callbacks.
   SetLastCallbackTimeToNowOnIOThread();
   DCHECK(!check_alive_timer_);
-  check_alive_timer_ = base::MakeUnique<base::RepeatingTimer>();
+  check_alive_timer_ = std::make_unique<base::RepeatingTimer>();
   check_alive_timer_->Start(
       FROM_HERE,
       base::TimeDelta::FromSeconds(kCheckMissingCallbacksIntervalSeconds), this,
@@ -341,7 +343,8 @@
 void AudioInputDevice::SetLastCallbackTimeToNow() {
   task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&AudioInputDevice::SetLastCallbackTimeToNowOnIOThread, this));
+      base::BindOnce(&AudioInputDevice::SetLastCallbackTimeToNowOnIOThread,
+                     this));
 }
 
 void AudioInputDevice::SetLastCallbackTimeToNowOnIOThread() {
diff --git a/media/audio/audio_input_device.h b/media/audio/audio_input_device.h
index 69125f5..cfffdd4 100644
--- a/media/audio/audio_input_device.h
+++ b/media/audio/audio_input_device.h
@@ -94,8 +94,20 @@
   void SetVolume(double volume) override;
   void SetAutomaticGainControl(bool enabled) override;
 
- protected:
+ private:
   friend class base::RefCountedThreadSafe<AudioInputDevice>;
+
+  // Our audio thread callback class.  See source file for details.
+  class AudioThreadCallback;
+
+  // Note: The ordering of members in this enum is critical to correct behavior!
+  enum State {
+    IPC_CLOSED,       // No more IPCs can take place.
+    IDLE,             // Not started.
+    CREATING_STREAM,  // Waiting for OnStreamCreated() to be called back.
+    RECORDING,        // Receiving audio data.
+  };
+
   ~AudioInputDevice() override;
 
   // Methods called on IO thread ----------------------------------------------
@@ -107,15 +119,6 @@
   void OnMuted(bool is_muted) override;
   void OnIPCClosed() override;
 
- private:
-  // Note: The ordering of members in this enum is critical to correct behavior!
-  enum State {
-    IPC_CLOSED,  // No more IPCs can take place.
-    IDLE,  // Not started.
-    CREATING_STREAM,  // Waiting for OnStreamCreated() to be called back.
-    RECORDING,  // Receiving audio data.
-  };
-
   // Methods called on IO thread ----------------------------------------------
   // The following methods are tasks posted on the IO thread that needs to
   // be executed on that thread. They interact with AudioInputMessageFilter and
@@ -163,9 +166,6 @@
   // Only modified on the IO thread.
   bool agc_is_enabled_;
 
-  // Our audio thread callback class.  See source file for details.
-  class AudioThreadCallback;
-
   // In order to avoid a race between OnStreamCreated and Stop(), we use this
   // guard to control stopping and starting the audio thread.
   base::Lock audio_thread_lock_;
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 3b398dd..9cfcaa9 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -256,7 +256,7 @@
 
 // Inform video blitter of video color space.
 const base::Feature kVideoBlitColorAccuracy{"video-blit-color-accuracy",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
+                                            base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables support for External Clear Key (ECK) key system for testing on
 // supported platforms. On platforms that do not support ECK, this feature has
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc
index d793c69..db5c9b6 100644
--- a/media/blink/multibuffer_data_source.cc
+++ b/media/blink/multibuffer_data_source.cc
@@ -379,13 +379,10 @@
     return;
   DCHECK(read_op_->size());
 
-  if (!reader_) {
+  if (!reader_)
     CreateResourceLoader(read_op_->position(), kPositionNotSpecified);
-  } else {
-    reader_->Seek(read_op_->position());
-  }
 
-  int64_t available = reader_->Available();
+  int64_t available = reader_->AvailableAt(read_op_->position());
   if (available < 0) {
     // A failure has occured.
     ReadOperation::Run(std::move(read_op_), kReadError);
@@ -394,8 +391,12 @@
   if (available) {
     bytes_read =
         static_cast<int>(std::min<int64_t>(available, read_op_->size()));
-    bytes_read = reader_->TryRead(read_op_->data(), bytes_read);
-    url_data_->AddBytesRead(bytes_read);
+    bytes_read =
+        reader_->TryReadAt(read_op_->position(), read_op_->data(), bytes_read);
+
+    int64_t new_pos = read_op_->position() + bytes_read;
+    if (reader_->AvailableAt(new_pos) <= reader_->Available())
+      reader_->Seek(new_pos);
     if (bytes_read == 0 && total_bytes_ == kPositionNotSpecified) {
       // We've reached the end of the file and we didn't know the total size
       // before. Update the total size so Read()s past the end of the file will
@@ -407,6 +408,7 @@
 
     ReadOperation::Run(std::move(read_op_), bytes_read);
   } else {
+    reader_->Seek(read_op_->position());
     reader_->Wait(1, base::Bind(&MultibufferDataSource::ReadTask,
                                 weak_factory_.GetWeakPtr()));
   }
diff --git a/media/blink/multibuffer_data_source_unittest.cc b/media/blink/multibuffer_data_source_unittest.cc
index 9b1aa9b..74a9785 100644
--- a/media/blink/multibuffer_data_source_unittest.cc
+++ b/media/blink/multibuffer_data_source_unittest.cc
@@ -1594,4 +1594,38 @@
   Stop();
 }
 
+TEST_F(MultibufferDataSourceTest, Http_Seek_Back) {
+  InitializeWith206Response();
+
+  // Read a bit from the beginning.
+  EXPECT_CALL(*this, ReadCallback(kDataSize));
+  ReadAt(0);
+
+  ReadAt(kDataSize);
+  EXPECT_CALL(*this, ReadCallback(kDataSize));
+  EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2));
+  ReceiveData(kDataSize);
+  ReadAt(kDataSize * 2);
+  EXPECT_CALL(*this, ReadCallback(kDataSize));
+  EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 3));
+  ReceiveData(kDataSize);
+
+  // Read some data from far ahead.
+  ReadAt(kFarReadPosition);
+  EXPECT_CALL(*this, ReadCallback(kDataSize));
+  EXPECT_CALL(host_, AddBufferedByteRange(kFarReadPosition,
+                                          kFarReadPosition + kDataSize));
+  Respond(response_generator_->Generate206(kFarReadPosition));
+  ReceiveData(kDataSize);
+
+  // This should not close the current connection, because we have
+  // more data buffered at this location than at kFarReadPosition.
+  EXPECT_CALL(*this, ReadCallback(kDataSize));
+  ReadAt(0);
+
+  EXPECT_EQ(kFarReadPosition + kDataSize, loader()->Tell());
+
+  Stop();
+}
+
 }  // namespace media
diff --git a/media/blink/multibuffer_reader.cc b/media/blink/multibuffer_reader.cc
index fa9e845..b5cb2b1 100644
--- a/media/blink/multibuffer_reader.cc
+++ b/media/blink/multibuffer_reader.cc
@@ -75,30 +75,29 @@
            block_ceil(pos_ + max_buffer_forward_));
 }
 
-int64_t MultiBufferReader::Available() const {
+int64_t MultiBufferReader::AvailableAt(int64_t pos) const {
   int64_t unavailable_byte_pos =
-      static_cast<int64_t>(multibuffer_->FindNextUnavailable(block(pos_)))
+      static_cast<int64_t>(multibuffer_->FindNextUnavailable(block(pos)))
       << multibuffer_->block_size_shift();
-  return std::max<int64_t>(0, unavailable_byte_pos - pos_);
+  return std::max<int64_t>(0, unavailable_byte_pos - pos);
 }
 
-int64_t MultiBufferReader::TryRead(uint8_t* data, int64_t len) {
+int64_t MultiBufferReader::TryReadAt(int64_t pos, uint8_t* data, int64_t len) {
   DCHECK_GT(len, 0);
   current_wait_size_ = 0;
   cb_.Reset();
-  DCHECK_LE(pos_ + len, end_);
+  DCHECK_LE(pos + len, end_);
   const MultiBuffer::DataMap& data_map = multibuffer_->map();
-  MultiBuffer::DataMap::const_iterator i = data_map.find(block(pos_));
-  int64_t p = pos_;
+  MultiBuffer::DataMap::const_iterator i = data_map.find(block(pos));
   int64_t bytes_read = 0;
   while (bytes_read < len) {
     if (i == data_map.end())
       break;
-    if (i->first != block(p))
+    if (i->first != block(pos))
       break;
     if (i->second->end_of_stream())
       break;
-    size_t offset = p & ((1LL << multibuffer_->block_size_shift()) - 1);
+    size_t offset = pos & ((1LL << multibuffer_->block_size_shift()) - 1);
     if (offset > static_cast<size_t>(i->second->data_size()))
       break;
     size_t tocopy =
@@ -106,10 +105,15 @@
     memcpy(data, i->second->data() + offset, tocopy);
     data += tocopy;
     bytes_read += tocopy;
-    p += tocopy;
+    pos += tocopy;
     ++i;
   }
-  Seek(p);
+  return bytes_read;
+}
+
+int64_t MultiBufferReader::TryRead(uint8_t* data, int64_t len) {
+  int64_t bytes_read = TryReadAt(pos_, data, len);
+  Seek(pos_ + bytes_read);
   return bytes_read;
 }
 
diff --git a/media/blink/multibuffer_reader.h b/media/blink/multibuffer_reader.h
index e0a76ef1..6adb2e3e 100644
--- a/media/blink/multibuffer_reader.h
+++ b/media/blink/multibuffer_reader.h
@@ -42,10 +42,14 @@
 
   ~MultiBufferReader() override;
 
-  // Returns number of bytes available for reading. When the rest of the file
-  // is available, the number returned will be greater than the number
-  // or readable bytes. If an error occurs, -1 is returned.
-  int64_t Available() const;
+  // Returns number of bytes available for reading. At position |pos|
+  // When the rest of the file is available, the number returned will
+  // be greater than the number or readable bytes. If an error occurs,
+  // -1 is returned.
+  int64_t AvailableAt(int64_t pos) const;
+
+  // Returns number of bytes available for reading at the current position.
+  int64_t Available() const { return AvailableAt(pos_); }
 
   // Seek to a different position.
   // If there is a pending Wait(), it will be cancelled.
@@ -54,7 +58,12 @@
   // Returns the current position.
   int64_t Tell() const { return pos_; }
 
-  // Tries to read |len| bytes and advance position.
+  // Tries to read |len| bytes from position |pos|.
+  // Returns number of bytes read.
+  // If there is a pending Wait(), it will be cancelled.
+  int64_t TryReadAt(int64_t pos, uint8_t* data, int64_t len);
+
+  // Tries to read |len| bytes and update current position.
   // Returns number of bytes read.
   // If there is a pending Wait(), it will be cancelled.
   int64_t TryRead(uint8_t* data, int64_t len);
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.cc b/media/cdm/ppapi/ppapi_cdm_adapter.cc
index f7601903..e8dac0d 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.cc
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.cc
@@ -1204,8 +1204,6 @@
 }
 
 void PpapiCdmAdapter::RequestStorageId() {
-  CDM_DLOG() << __func__;
-
   // If persistent storage is not allowed, no need to get the Storage ID.
   if (allow_persistent_state_) {
     linked_ptr<pp::Var> response(new pp::Var());
@@ -1339,16 +1337,20 @@
 void PpapiCdmAdapter::RequestStorageIdDone(
     int32_t result,
     const linked_ptr<pp::Var>& response) {
-  std::string storage_id;
+  uint8_t* storage_id_ptr;
+  uint32_t storage_id_size;
 
-  if (result == PP_OK)
-    storage_id = response->AsString();
+  if (result == PP_OK && response->is_array_buffer()) {
+    pp::VarArrayBuffer storage_id(*response);
+    storage_id_ptr = static_cast<uint8_t*>(storage_id.Map());
+    storage_id_size = storage_id.ByteLength();
+  } else {
+    CDM_DLOG() << __func__ << " failed, result = " << result;
+    storage_id_ptr = nullptr;
+    storage_id_size = 0;
+  }
 
-  CDM_DLOG() << __func__ << ": result = " << result
-             << ", storage_id = " << storage_id;
-
-  cdm_->OnStorageId(reinterpret_cast<const uint8_t*>(storage_id.data()),
-                    static_cast<uint32_t>(storage_id.length()));
+  cdm_->OnStorageId(storage_id_ptr, storage_id_size);
 }
 
 PpapiCdmAdapter::SessionError::SessionError(
diff --git a/media/filters/blocking_url_protocol.cc b/media/filters/blocking_url_protocol.cc
index 760e4c4e3..08be12e 100644
--- a/media/filters/blocking_url_protocol.cc
+++ b/media/filters/blocking_url_protocol.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "media/base/data_source.h"
 #include "media/ffmpeg/ffmpeg_common.h"
 
@@ -60,7 +61,12 @@
   }
 
   base::WaitableEvent* events[] = { &aborted_, &read_complete_ };
-  size_t index = base::WaitableEvent::WaitMany(events, arraysize(events));
+  size_t index;
+  {
+    base::ScopedBlockingCall scoped_blocking_call(
+        base::BlockingType::MAY_BLOCK);
+    index = base::WaitableEvent::WaitMany(events, arraysize(events));
+  }
 
   if (events[index] == &aborted_)
     return AVERROR(EIO);
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index 01225be0..6575fca 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -665,8 +665,9 @@
       profile = VP9PROFILE_PROFILE3;
       break;
     default:
-      MEDIA_LOG(ERROR, reader->media_log()) << "Unsupported VP9 profile: "
-                                            << profile_indication;
+      MEDIA_LOG(ERROR, reader->media_log())
+          << "Unsupported VP9 profile: 0x" << std::hex
+          << static_cast<uint32_t>(profile_indication);
       return false;
   }
   return true;
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index c0d00c61d..72fcb43 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -488,6 +488,11 @@
   if (moov_->extends.header.fragment_duration > 0) {
     params.duration = TimeDeltaFromRational(
         moov_->extends.header.fragment_duration, moov_->header.timescale);
+    if (params.duration == kNoTimestamp) {
+      MEDIA_LOG(ERROR, media_log_) << "Fragment duration exceeds representable "
+                                   << "limit";
+      return false;
+    }
     params.liveness = DemuxerStream::LIVENESS_RECORDED;
   } else if (moov_->header.duration > 0 &&
              ((moov_->header.version == 0 &&
@@ -503,6 +508,11 @@
     // duration".
     params.duration =
         TimeDeltaFromRational(moov_->header.duration, moov_->header.timescale);
+    if (params.duration == kNoTimestamp) {
+      MEDIA_LOG(ERROR, media_log_) << "Movie duration exceeds representable "
+                                   << "limit";
+      return false;
+    }
     params.liveness = DemuxerStream::LIVENESS_RECORDED;
   } else {
     // In ISO/IEC 14496-12:2005(E), 8.30.2: ".. If an MP4 file is created in
@@ -726,9 +736,30 @@
   if (decrypt_config)
     stream_buf->set_decrypt_config(std::move(decrypt_config));
 
-  stream_buf->set_duration(runs_->duration());
-  stream_buf->set_timestamp(runs_->cts());
-  stream_buf->SetDecodeTimestamp(runs_->dts());
+  if (runs_->duration() != kNoTimestamp) {
+    stream_buf->set_duration(runs_->duration());
+  } else {
+    MEDIA_LOG(ERROR, media_log_) << "Frame duration exceeds representable "
+                                 << "limit";
+    *err = true;
+    return false;
+  }
+
+  if (runs_->cts() != kNoTimestamp) {
+    stream_buf->set_timestamp(runs_->cts());
+  } else {
+    MEDIA_LOG(ERROR, media_log_) << "Frame CTS exceeds representable limit";
+    *err = true;
+    return false;
+  }
+
+  if (runs_->dts() != kNoDecodeTimestamp()) {
+    stream_buf->SetDecodeTimestamp(runs_->dts());
+  } else {
+    MEDIA_LOG(ERROR, media_log_) << "Frame DTS exceeds representable limit";
+    *err = true;
+    return false;
+  }
 
   DVLOG(3) << "Emit " << (audio ? "audio" : "video") << " frame: "
            << " track_id=" << runs_->track_id()
diff --git a/media/formats/mp4/track_run_iterator.cc b/media/formats/mp4/track_run_iterator.cc
index fba78c9f..a58db70 100644
--- a/media/formats/mp4/track_run_iterator.cc
+++ b/media/formats/mp4/track_run_iterator.cc
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "media/base/timestamp_constants.h"
 #include "media/formats/mp4/rcheck.h"
 #include "media/formats/mp4/sample_to_group_iterator.h"
 #include "media/media_features.h"
@@ -20,7 +21,7 @@
 struct SampleInfo {
   uint32_t size;
   uint32_t duration;
-  int cts_offset;
+  int64_t cts_offset;
   bool is_keyframe;
   uint32_t cenc_group_description_index;
 };
@@ -67,28 +68,41 @@
 TrackRunInfo::~TrackRunInfo() {}
 
 base::TimeDelta TimeDeltaFromRational(int64_t numer, int64_t denom) {
-  DCHECK_NE(denom, 0);
+  // TODO(sandersd): Change all callers to pass a |denom| as a uint32_t. This is
+  // the correct (and sufficient) type in all cases, but some intermediaries
+  // currently store -1 as a default value.
+  // TODO(sandersd): Change all callers to pass |numer| as a uint64_t. The few
+  // cases that could theoretically be negative would result in negative PTS
+  // anyway, and there are cases where an int64_t is not sufficient to store the
+  // entire representable range.
+  DCHECK_GT(denom, 0);
+  DCHECK_LE(denom, std::numeric_limits<uint32_t>::max());
 
-  // To avoid overflow, split the following calculation:
-  // (numer * base::Time::kMicrosecondsPerSecond) / denom
-  // into:
-  //  (numer / denom) * base::Time::kMicrosecondsPerSecond +
-  // ((numer % denom) * base::Time::kMicrosecondsPerSecond) / denom
-  int64_t a = numer / denom;
-  DCHECK_LE((a > 0 ? a : -a), std::numeric_limits<int64_t>::max() /
-                                  base::Time::kMicrosecondsPerSecond);
-  int64_t timea_in_us = a * base::Time::kMicrosecondsPerSecond;
+  // The maximum number of seconds that a TimeDelta can hold (about 300,000
+  // years worth). There is a (t ~= 0.775)-second fraction that is ignored.
+  const int64_t max_seconds =
+      std::numeric_limits<int64_t>::max() / base::Time::kMicrosecondsPerSecond;
 
-  int64_t b = numer % denom;
-  DCHECK_LE((b > 0 ? b : -b), std::numeric_limits<int64_t>::max() /
-                                  base::Time::kMicrosecondsPerSecond);
-  int64_t timeb_in_us = (b * base::Time::kMicrosecondsPerSecond) / denom;
+  // The integer part of the result, in seconds. There is a (0 <= f < 1)-second
+  // fraction that is not computed. (Also true for negative |numer|, since
+  // rounding of integer division is towards zero in C++.)
+  const int64_t result_seconds = numer / denom;
 
-  DCHECK((timeb_in_us < 0) ||
-         (timea_in_us <= std::numeric_limits<int64_t>::max() - timeb_in_us));
-  DCHECK((timeb_in_us > 0) ||
-         (timea_in_us >= std::numeric_limits<int64_t>::min() - timeb_in_us));
-  return base::TimeDelta::FromMicroseconds(timea_in_us + timeb_in_us);
+  // Reject |actual_seconds == max_seconds| under the assumption that f > t.
+  // This rejects valid times that are within t seconds of the limit.
+  if (result_seconds >= max_seconds || result_seconds <= -max_seconds)
+    return kNoTimestamp;
+
+  // Since (denom <= 2 ** 32), the multiplication fits in 52 bits.
+  // Note: When |numer| is negative, (numer % denom) is also negative. C++
+  // guarantees that ((numer / denom) * denom + (numer % denom) == numer).
+  // TODO(sandersd): Is round-toward-zero the best possible computation here?
+  const int64_t result_microseconds =
+      base::Time::kMicrosecondsPerSecond * (numer % denom) / denom;
+
+  const int64_t total_microseconds =
+      base::Time::kMicrosecondsPerSecond * result_seconds + result_microseconds;
+  return base::TimeDelta::FromMicroseconds(total_microseconds);
 }
 
 DecodeTimestamp DecodeTimestampFromRational(int64_t numer, int64_t denom) {
diff --git a/media/formats/mp4/track_run_iterator_unittest.cc b/media/formats/mp4/track_run_iterator_unittest.cc
index 4f4fed7..03f68b4 100644
--- a/media/formats/mp4/track_run_iterator_unittest.cc
+++ b/media/formats/mp4/track_run_iterator_unittest.cc
@@ -148,6 +148,33 @@
   return CONTAINS_STRING(arg, "Reserved value used in sample dependency info.");
 }
 
+TEST(TimeDeltaFromRationalTest, RoundsTowardZero) {
+  // In each case, 1.5us should round to 1us.
+  base::TimeDelta expected = base::TimeDelta::FromMicroseconds(1);
+  EXPECT_EQ(TimeDeltaFromRational(3, 2000000), expected);
+  EXPECT_EQ(TimeDeltaFromRational(-3, 2000000), -expected);
+}
+
+TEST(TimeDeltaFromRationalTest, HandlesLargeValues) {
+  int64_t max_seconds =
+      std::numeric_limits<int64_t>::max() / base::Time::kMicrosecondsPerSecond;
+  // The current implementation rejects |max_seconds|.
+  // Note: kNoTimestamp is printed as "9.22337e+12 s", which is visually
+  // indistinguishable from |expected|.
+  int64_t seconds = max_seconds - 1;
+  base::TimeDelta expected = base::TimeDelta::FromSeconds(seconds);
+  EXPECT_EQ(TimeDeltaFromRational(seconds, 1), expected);
+  EXPECT_EQ(TimeDeltaFromRational(-seconds, 1), -expected);
+}
+
+TEST(TimeDeltaFromRationalTest, HandlesOverflow) {
+  int64_t max_seconds =
+      std::numeric_limits<int64_t>::max() / base::Time::kMicrosecondsPerSecond;
+  int64_t seconds = max_seconds + 1;
+  EXPECT_EQ(TimeDeltaFromRational(seconds, 1), kNoTimestamp);
+  EXPECT_EQ(TimeDeltaFromRational(-seconds, 1), kNoTimestamp);
+}
+
 class TrackRunIteratorTest : public testing::Test {
  public:
   TrackRunIteratorTest() { CreateMovie(); }
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index b8e983f..ca2f3d9a 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -142,20 +142,51 @@
 
   # MSE pipeline fuzzer test variants. Note, while it would be nice to have one
   # generic MSE fuzzer, we use distinct fuzzers corresponding 1:1 to a set of
-  # mimetype+codec strings for now because maintaining the association of a
-  # (mutated) corpus item with the same MSE SourceBuffer configuration requires
-  # associating that item with the same mimetype+codec string. The benefits are
-  # simpler fuzzers and the ability to slice per-fuzzer coverage stats. The
-  # costs include more fuzzers and more potential duplicate bugs from different
-  # fuzzers for common issues exposed across mimetype+codec string variants.
-  # TODO(wolenetz): Add more MSE fuzzer variants for different bytestreams and
-  # codec combos. See https://crbug.com/750818.
-  "MP4_FLAC",
-  "MP4_AVC1",
+  # mimetype+codec strings for now because:
+  # a) the SourceBuffer implementation must be constructed to expect a
+  #    particular bytestream type and (set of) codec(s); it does not
+  #    auto-detect those from the appended media, and
+  # b) maintaining the association of a (mutated) corpus item with the same MSE
+  #    SourceBuffer configuration requires associating that item with the same
+  #    mimetype+codec string. The benefits are simpler fuzzers and the ability
+  #    to slice per-fuzzer coverage stats. The costs include more fuzzers, risk
+  #    of new bytestream types or codec fuzzing gaps, and more potential
+  #    duplicate bugs from different fuzzers for common issues exposed across
+  #    mimetype+codec string variants.
+  "WEBM_OPUS",
+  "WEBM_VORBIS",
+  "WEBM_VP8",
   "WEBM_VP9",
-  "MP3",
+  "WEBM_OPUS_VP9",
+
+  # See below for additional variants depending on build configuration.
 ]
 
+if (proprietary_codecs) {
+  pipeline_integration_fuzzer_variants += [
+    "ADTS",
+    "MP3",
+    "MP4_AACLC",
+    "MP4_AACSBR",
+
+    # Though neither StreamParserFactory, MP4StreamParser, nor
+    # SourceBufferState::Init differentiate kinds of AVC, we use "AVC1" here to
+    # retain corpus associated with this fuzzer target name.
+    "MP4_AVC1",
+    "MP4_FLAC",
+    "MP4_AACLC_AVC",
+  ]
+  if (enable_mse_mpeg2ts_stream_parser) {
+    pipeline_integration_fuzzer_variants += [
+      "MP2T_AACLC",
+      "MP2T_AACSBR",
+      "MP2T_AVC",
+      "MP2T_MP3",
+      "MP2T_AACLC_AVC",
+    ]
+  }
+}
+
 foreach(variant, pipeline_integration_fuzzer_variants) {
   if (variant == "SRC") {
     test_name = "media_pipeline_integration_fuzzer"
diff --git a/media/test/data/eme_player_js/player_utils.js b/media/test/data/eme_player_js/player_utils.js
index 7013920..bfaf9358 100644
--- a/media/test/data/eme_player_js/player_utils.js
+++ b/media/test/data/eme_player_js/player_utils.js
@@ -231,10 +231,11 @@
   }
 
   // The File IO test requires persistent state support.
-  if (player.testConfig.keySystem ==
-      'org.chromium.externalclearkey.fileiotest') {
+  if (player.testConfig.keySystem == FILE_IO_TEST_KEYSYSTEM) {
     config.persistentState = 'required';
-  } else if (player.testConfig.sessionToLoad) {
+  } else if (
+      player.testConfig.sessionToLoad ||
+      player.testConfig.keySystem == STORAGE_ID_TEST_KEYSYSTEM) {
     config.persistentState = 'required';
     config.sessionTypes = ['temporary', 'persistent-license'];
   }
diff --git a/media/test/data/load_many_videos.html b/media/test/data/load_many_videos.html
new file mode 100644
index 0000000..0eacf6f
--- /dev/null
+++ b/media/test/data/load_many_videos.html
@@ -0,0 +1,64 @@
+<!--
+Loads lots of videos to make sure that we don't deadlock somewhere
+while loading lots of videos. We try a variety of video formats and
+containers to try to cover different read patterns.
+-->
+<html>
+<body onload="RunTest();">
+<video controls preload=audo src="bear-320x180-hi10p.mp4"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?A"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?B"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?C"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?D"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?E"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?F"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?G"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?H"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?I"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?J"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?K"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?L"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?M"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?N"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?O"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?P"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?Q"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?R"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?S"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?T"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?U"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?V"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?W"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?X"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?Y"></video><br>
+<video controls preload=audo src="bear-320x180-hi10p.mp4?Z"></video><br>
+<video controls preload=audo src="bear-1280x720.mp4"></video><br>
+<video controls preload=audo src="bear-320x240.webm"></video><br>
+<video controls preload=audo src="bear.mp4"></video><br>
+<video controls preload=audo src="bear-vp8a.webm"></video><br>
+<video controls preload=audo src="bear-320x240-video-only.webm"></video><br>
+<video controls preload=audo src="bear-320x240-vp9_profile2.webm"></video><br>
+<video controls preload=audo src="bear-320x180-hi12p-vp9.webm"></video><br>
+<video controls preload=audo src="bbb-320x240-2video-2audio.mp4"></video><br>
+<video controls preload=audo src="bear-1280x720-av_with-aud-nalus_frag.mp4"></video><br>
+<video controls preload=audo src="bear-vp8-webvtt.webm"></video><br>
+</body>
+
+<script>
+  function CheckIfDone() {
+    console.log("Done?");
+    var players = document.getElementsByTagName("video");
+    for (var i = 0; i < players.length; i++) {
+      if (players[i].readyState < 4) return;
+    }
+    document.title = "ENDED";
+  }
+  function RunTest() {
+    var players = document.getElementsByTagName("video");
+    for (var i = 0; i < players.length; i++) {
+      players[i].addEventListener('canplaythrough', function(e) { CheckIfDone(); });
+    }
+    CheckIfDone();
+  }
+</script>
+</html>
diff --git a/media/test/pipeline_integration_fuzzertest.cc b/media/test/pipeline_integration_fuzzertest.cc
index b9fbe23b..c1ea3fde 100644
--- a/media/test/pipeline_integration_fuzzertest.cc
+++ b/media/test/pipeline_integration_fuzzertest.cc
@@ -23,12 +23,79 @@
 // Keep these aligned with BUILD.gn's pipeline_integration_fuzzer_variants
 enum FuzzerVariant {
   SRC,
-  MP4_FLAC,
-  MP4_AVC1,
+  WEBM_OPUS,
+  WEBM_VORBIS,
+  WEBM_VP8,
   WEBM_VP9,
+  WEBM_OPUS_VP9,
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+  ADTS,
   MP3,
+  MP4_AACLC,
+  MP4_AACSBR,
+  MP4_AVC1,
+  MP4_FLAC,
+  MP4_AACLC_AVC,
+#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
+  MP2T_AACLC,
+  MP2T_AACSBR,
+  MP2T_AVC,
+  MP2T_MP3,
+  MP2T_AACLC_AVC,
+#endif  // BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
+#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 };
 
+std::string MseFuzzerVariantEnumToMimeTypeString(FuzzerVariant variant) {
+  switch (variant) {
+    case WEBM_OPUS:
+      return "audio/webm; codecs=\"opus\"";
+    case WEBM_VORBIS:
+      return "audio/webm; codecs=\"vorbis\"";
+    case WEBM_VP8:
+      return "video/webm; codecs=\"vp8\"";
+    case WEBM_VP9:
+      return "video/webm; codecs=\"vp9\"";
+    case WEBM_OPUS_VP9:
+      return "video/webm; codecs=\"opus,vp9\"";
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+    case ADTS:
+      return "audio/aac";
+    case MP3:
+      return "audio/mpeg";
+    case MP4_AACLC:
+      return "audio/mp4; codecs=\"mp4a.40.2\"";
+    case MP4_AACSBR:
+      return "audio/mp4; codecs=\"mp4a.40.5\"";
+    case MP4_AVC1:
+      return "video/mp4; codecs=\"avc1.42E01E\"";
+    case MP4_FLAC:
+      return "audio/mp4; codecs=\"flac\"";
+    case MP4_AACLC_AVC:
+      return "video/mp4; codecs=\"mp4a.40.2,avc1.42E01E\"";
+#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
+    case MP2T_AACLC:
+      return "video/mp2t; codecs=\"mp4a.67\"";
+    case MP2T_AACSBR:
+      return "video/mp2t; codecs=\"mp4a.40.5\"";
+    case MP2T_AVC:
+      return "video/mp2t; codecs=\"avc1.42E01E\"";
+    case MP2T_MP3:
+      // Note, "mp4a.6B" appears to be an equivalent codec substring.
+      return "video/mp2t; codecs=\"mp4a.69\"";
+    case MP2T_AACLC_AVC:
+      return "video/mp2t; codecs=\"mp4a.40.2,avc1.42E01E\"";
+#endif  // BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
+#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
+
+    case SRC:
+      NOTREACHED() << "SRC is an invalid MSE fuzzer variant";
+      break;
+  }
+
+  return "";
+}
+
 }  // namespace
 
 namespace media {
@@ -147,32 +214,12 @@
 
   FuzzerVariant variant = PIPELINE_FUZZER_VARIANT;
 
-  switch (variant) {
-    case SRC: {
-      media::ProgressivePipelineIntegrationFuzzerTest test;
-      test.RunTest(data, size);
-      break;
-    }
-    case MP4_FLAC: {
-      media::MediaSourcePipelineIntegrationFuzzerTest test;
-      test.RunTest(data, size, "audio/mp4; codecs=\"flac\"");
-      break;
-    }
-    case MP4_AVC1: {
-      media::MediaSourcePipelineIntegrationFuzzerTest test;
-      test.RunTest(data, size, "video/mp4; codecs=\"avc1.42E01E\"");
-      break;
-    }
-    case WEBM_VP9: {
-      media::MediaSourcePipelineIntegrationFuzzerTest test;
-      test.RunTest(data, size, "video/webm; codecs=\"vp9\"");
-      break;
-    }
-    case MP3: {
-      media::MediaSourcePipelineIntegrationFuzzerTest test;
-      test.RunTest(data, size, "audio/mpeg");
-      break;
-    }
+  if (variant == SRC) {
+    media::ProgressivePipelineIntegrationFuzzerTest test;
+    test.RunTest(data, size);
+  } else {
+    media::MediaSourcePipelineIntegrationFuzzerTest test;
+    test.RunTest(data, size, MseFuzzerVariantEnumToMimeTypeString(variant));
   }
 
   return 0;
diff --git a/mojo/public/cpp/system/message.cc b/mojo/public/cpp/system/message.cc
deleted file mode 100644
index 09d8d46e..0000000
--- a/mojo/public/cpp/system/message.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/cpp/system/message.h"
-
-namespace mojo {
-
-ScopedMessageHandle::~ScopedMessageHandle() {
-
-}
-
-}  // namespace mojo
diff --git a/net/BUILD.gn b/net/BUILD.gn
index d12cbe4..0b23335 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1245,6 +1245,8 @@
       "quic/core/crypto/quic_encrypter.h",
       "quic/core/crypto/quic_random.cc",
       "quic/core/crypto/quic_random.h",
+      "quic/core/crypto/quic_tls_adapter.cc",
+      "quic/core/crypto/quic_tls_adapter.h",
       "quic/core/crypto/scoped_evp_aead_ctx.cc",
       "quic/core/crypto/scoped_evp_aead_ctx.h",
       "quic/core/frames/quic_ack_frame.cc",
@@ -2675,8 +2677,8 @@
       "test/spawned_test_server/remote_test_server_config.h",
       "test/spawned_test_server/remote_test_server_proxy.cc",
       "test/spawned_test_server/remote_test_server_proxy.h",
-      "test/spawned_test_server/spawner_communicator.cc",
-      "test/spawned_test_server/spawner_communicator.h",
+      "test/spawned_test_server/remote_test_server_spawner_request.cc",
+      "test/spawned_test_server/remote_test_server_spawner_request.h",
     ]
   }
 
@@ -5040,6 +5042,7 @@
     "quic/core/crypto/quic_crypto_client_config_test.cc",
     "quic/core/crypto/quic_crypto_server_config_test.cc",
     "quic/core/crypto/quic_random_test.cc",
+    "quic/core/crypto/quic_tls_adapter_test.cc",
     "quic/core/frames/quic_frames_test.cc",
     "quic/core/packet_number_indexed_queue_test.cc",
     "quic/core/quic_alarm_test.cc",
diff --git a/net/android/javatests/src/org/chromium/net/AndroidProxyConfigServiceTestUtil.java b/net/android/javatests/src/org/chromium/net/AndroidProxyConfigServiceTestUtil.java
index 99a6f753..81f1550 100644
--- a/net/android/javatests/src/org/chromium/net/AndroidProxyConfigServiceTestUtil.java
+++ b/net/android/javatests/src/org/chromium/net/AndroidProxyConfigServiceTestUtil.java
@@ -17,6 +17,8 @@
      */
     @CalledByNative
     private static void prepareLooper() {
-        Looper.prepare();
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
     }
 }
\ No newline at end of file
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 3b94ce0..635b43b 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -472,9 +472,6 @@
 
   {
     ASSERT_TRUE(CleanupCacheDir());
-    base::Thread cache_thread("CacheThread");
-    ASSERT_TRUE(cache_thread.StartWithOptions(
-        base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
 
     // Test the private factory method(s).
     std::unique_ptr<disk_cache::Backend> cache;
@@ -484,31 +481,15 @@
 
     // Now test the public API.
     int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE,
-                                            net::CACHE_BACKEND_DEFAULT,
-                                            cache_path_,
-                                            0,
-                                            false,
-                                            cache_thread.task_runner(),
-                                            NULL,
-                                            &cache,
-                                            cb.callback());
-    ASSERT_THAT(cb.GetResult(rv), IsOk());
-    ASSERT_TRUE(cache.get());
-    cache.reset();
-
-    // Variant without the explicit thread, too!
-    rv = disk_cache::CreateCacheBackend(net::DISK_CACHE,
                                         net::CACHE_BACKEND_DEFAULT, cache_path_,
                                         0, false, NULL, &cache, cb.callback());
     ASSERT_THAT(cb.GetResult(rv), IsOk());
     ASSERT_TRUE(cache.get());
     cache.reset();
 
-    rv = disk_cache::CreateCacheBackend(net::MEMORY_CACHE,
-                                        net::CACHE_BACKEND_DEFAULT,
-                                        base::FilePath(), 0,
-                                        false, NULL, NULL, &cache,
-                                        cb.callback());
+    rv = disk_cache::CreateCacheBackend(
+        net::MEMORY_CACHE, net::CACHE_BACKEND_DEFAULT, base::FilePath(), 0,
+        false, NULL, &cache, cb.callback());
     ASSERT_THAT(cb.GetResult(rv), IsOk());
     ASSERT_TRUE(cache.get());
     cache.reset();
@@ -547,11 +528,11 @@
   std::unique_ptr<disk_cache::Backend> cache, cache2;
 
   int rv = disk_cache::CreateCacheBackend(
-      net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, cache_path_, 0, false,
+      net::APP_CACHE, net::CACHE_BACKEND_DEFAULT, cache_path_, 0, false,
       nullptr, &cache, cb.callback());
 
   int rv2 = disk_cache::CreateCacheBackend(
-      net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, cache_path_, 0, false,
+      net::APP_CACHE, net::CACHE_BACKEND_DEFAULT, cache_path_, 0, false,
       nullptr, &cache2, cb2.callback());
 
   EXPECT_THAT(cb.GetResult(rv), IsOk());
@@ -584,12 +565,12 @@
   std::unique_ptr<disk_cache::Backend> cache, cache2;
 
   int rv = disk_cache::CreateCacheBackend(
-      net::DISK_CACHE, net::CACHE_BACKEND_SIMPLE, cache_path_, 0, false,
-      nullptr, &cache, cb.callback());
+      net::APP_CACHE, net::CACHE_BACKEND_SIMPLE, cache_path_, 0, false, nullptr,
+      &cache, cb.callback());
 
   int rv2 = disk_cache::CreateCacheBackend(
-      net::DISK_CACHE, net::CACHE_BACKEND_SIMPLE, cache_path_, 0, false,
-      nullptr, &cache2, cb2.callback());
+      net::APP_CACHE, net::CACHE_BACKEND_SIMPLE, cache_path_, 0, false, nullptr,
+      &cache2, cb2.callback());
 
   EXPECT_THAT(cb.GetResult(rv), IsOk());
   ASSERT_TRUE(cache.get());
@@ -631,8 +612,8 @@
   std::unique_ptr<disk_cache::Backend> cache;
 
   int rv = disk_cache::CreateCacheBackend(
-      net::DISK_CACHE, net::CACHE_BACKEND_SIMPLE, cache_path_, 0, false,
-      nullptr, &cache, run_loop.QuitClosure(), cb.callback());
+      net::APP_CACHE, net::CACHE_BACKEND_SIMPLE, cache_path_, 0, false, nullptr,
+      &cache, run_loop.QuitClosure(), cb.callback());
   EXPECT_THAT(cb.GetResult(rv), IsOk());
   ASSERT_TRUE(cache.get());
 
@@ -829,7 +810,7 @@
   std::unique_ptr<disk_cache::Backend> extra_cache;
   int rv = disk_cache::CreateCacheBackend(
       net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, store.GetPath(), 0, false,
-      base::ThreadTaskRunnerHandle::Get(), NULL, &extra_cache, cb.callback());
+      /* net_log = */ nullptr, &extra_cache, cb.callback());
   ASSERT_THAT(cb.GetResult(rv), IsOk());
   ASSERT_TRUE(extra_cache.get() != NULL);
 
@@ -846,6 +827,7 @@
   if (rv == net::ERR_IO_PENDING)
     EXPECT_FALSE(cb.have_result());
 
+  disk_cache::FlushCacheThreadForTesting();
   base::RunLoop().RunUntilIdle();
 
   // Wait for the actual operation to complete, or we'll keep a file handle that
diff --git a/net/disk_cache/disk_cache.cc b/net/disk_cache/disk_cache.cc
index 345a649e..da40ac6e 100644
--- a/net/disk_cache/disk_cache.cc
+++ b/net/disk_cache/disk_cache.cc
@@ -31,7 +31,6 @@
                net::CacheType type,
                net::BackendType backend_type,
                uint32_t flags,
-               const scoped_refptr<base::SingleThreadTaskRunner>& thread,
                net::NetLog* net_log,
                std::unique_ptr<disk_cache::Backend>* backend,
                base::OnceClosure post_cleanup_callback,
@@ -39,11 +38,11 @@
 
   int TryCreateCleanupTrackerAndRun();
 
- private:
   // Creates the backend, the cleanup context for it having been already
-  // established.
+  // established... or purposefully left as null.
   int Run();
 
+ private:
   ~CacheCreator();
 
   void DoCallback(int result);
@@ -59,7 +58,6 @@
 #if !defined(OS_ANDROID)
   uint32_t flags_;
 #endif
-  scoped_refptr<base::SingleThreadTaskRunner> thread_;
   std::unique_ptr<disk_cache::Backend>* backend_;
   base::OnceClosure post_cleanup_callback_;
   net::CompletionCallback callback_;
@@ -77,7 +75,6 @@
     net::CacheType type,
     net::BackendType backend_type,
     uint32_t flags,
-    const scoped_refptr<base::SingleThreadTaskRunner>& thread,
     net::NetLog* net_log,
     std::unique_ptr<disk_cache::Backend>* backend,
     base::OnceClosure post_cleanup_callback,
@@ -91,7 +88,6 @@
 #if !defined(OS_ANDROID)
       flags_(flags),
 #endif
-      thread_(thread),
       backend_(backend),
       post_cleanup_callback_(std::move(post_cleanup_callback)),
       callback_(callback),
@@ -110,8 +106,9 @@
       (backend_type_ == net::CACHE_BACKEND_DEFAULT &&
        kSimpleBackendIsDefault)) {
     disk_cache::SimpleBackendImpl* simple_cache =
-        new disk_cache::SimpleBackendImpl(path_, cleanup_tracker_.get(),
-                                          max_bytes_, type_, thread_, net_log_);
+        new disk_cache::SimpleBackendImpl(
+            path_, cleanup_tracker_.get(), max_bytes_, type_,
+            /* cache_thread = */ nullptr, net_log_);
     created_cache_.reset(simple_cache);
     return simple_cache->Init(
         base::Bind(&CacheCreator::OnIOComplete, base::Unretained(this)));
@@ -122,7 +119,7 @@
   return net::ERR_FAILED;
 #else
   disk_cache::BackendImpl* new_cache = new disk_cache::BackendImpl(
-      path_, cleanup_tracker_.get(), thread_, net_log_);
+      path_, cleanup_tracker_.get(), /*cache_thread = */ nullptr, net_log_);
   created_cache_.reset(new_cache);
   new_cache->SetMaxSize(max_bytes_);
   new_cache->SetType(type_);
@@ -205,7 +202,6 @@
     const base::FilePath& path,
     int max_bytes,
     bool force,
-    const scoped_refptr<base::SingleThreadTaskRunner>& thread,
     net::NetLog* net_log,
     std::unique_ptr<Backend>* backend,
     base::OnceClosure post_cleanup_callback,
@@ -228,28 +224,18 @@
     }
   }
 
+  bool had_post_cleanup_callback = !post_cleanup_callback.is_null();
   CacheCreator* creator = new CacheCreator(
-      path, force, max_bytes, type, backend_type, kNone, thread, net_log,
-      backend, std::move(post_cleanup_callback), callback);
+      path, force, max_bytes, type, backend_type, kNone, net_log, backend,
+      std::move(post_cleanup_callback), callback);
+  if (type == net::DISK_CACHE || type == net::MEDIA_CACHE) {
+    DCHECK(!had_post_cleanup_callback);
+    return creator->Run();
+  }
 
   return creator->TryCreateCleanupTrackerAndRun();
 }
 
-int CreateCacheBackend(
-    net::CacheType type,
-    net::BackendType backend_type,
-    const base::FilePath& path,
-    int max_bytes,
-    bool force,
-    const scoped_refptr<base::SingleThreadTaskRunner>& thread,
-    net::NetLog* net_log,
-    std::unique_ptr<Backend>* backend,
-    const net::CompletionCallback& callback) {
-  return CreateCacheBackendImpl(type, backend_type, path, max_bytes, force,
-                                thread, net_log, backend, base::OnceClosure(),
-                                callback);
-}
-
 int CreateCacheBackend(net::CacheType type,
                        net::BackendType backend_type,
                        const base::FilePath& path,
@@ -259,7 +245,7 @@
                        std::unique_ptr<Backend>* backend,
                        const net::CompletionCallback& callback) {
   return CreateCacheBackendImpl(type, backend_type, path, max_bytes, force,
-                                nullptr, net_log, backend, base::OnceClosure(),
+                                net_log, backend, base::OnceClosure(),
                                 callback);
 }
 
@@ -273,7 +259,7 @@
                        base::OnceClosure post_cleanup_callback,
                        const net::CompletionCallback& callback) {
   return CreateCacheBackendImpl(type, backend_type, path, max_bytes, force,
-                                nullptr, net_log, backend,
+                                net_log, backend,
                                 std::move(post_cleanup_callback), callback);
 }
 
diff --git a/net/disk_cache/disk_cache.h b/net/disk_cache/disk_cache.h
index 2429402..756a04a 100644
--- a/net/disk_cache/disk_cache.h
+++ b/net/disk_cache/disk_cache.h
@@ -24,7 +24,6 @@
 
 namespace base {
 class FilePath;
-class SingleThreadTaskRunner;
 
 namespace trace_event {
 class ProcessMemoryDump;
@@ -45,37 +44,20 @@
 // Returns an instance of a Backend of the given |type|. |path| points to a
 // folder where the cached data will be stored (if appropriate). This cache
 // instance must be the only object that will be reading or writing files to
-// that folder (if another one exists, this operation will not complete until
-// the previous duplicate gets destroyed and finishes all I/O).
+// that folder (if another one exists, and |type| is not net::DISK_CACHE or
+// net::MEDIA_CACHE, this operation will not complete until the previous
+// duplicate gets destroyed and finishes all I/O).
 //
 // The returned object should be deleted when not needed anymore.
 // If |force| is true, and there is a problem with the cache initialization, the
 // files will be deleted and a new set will be created. |max_bytes| is the
 // maximum size the cache can grow to. If zero is passed in as |max_bytes|, the
-// cache will determine the value to use. |thread| can be used to perform IO
-// operations if a dedicated thread is required; if you pass in null, the
-// backend will create its own. The returned pointer can be
+// cache will determine the value to use. The returned pointer can be
 // NULL if a fatal error is found. The actual return value of the function is a
 // net error code. If this function returns ERR_IO_PENDING, the |callback| will
 // be invoked when a backend is available or a fatal error condition is reached.
 // The pointer to receive the |backend| must remain valid until the operation
 // completes (the callback is notified).
-//
-// Note: this is in process of being deprecated for the variant below.
-NET_EXPORT int CreateCacheBackend(
-    net::CacheType type,
-    net::BackendType backend_type,
-    const base::FilePath& path,
-    int max_bytes,
-    bool force,
-    const scoped_refptr<base::SingleThreadTaskRunner>& thread,
-    net::NetLog* net_log,
-    std::unique_ptr<Backend>* backend,
-    const net::CompletionCallback& callback);
-
-// Like above, but the backend is responsible for its own thread setup.
-// This is being migrated towards (along with a not-yet existing variant for
-// those with synchronization requirements towards backend's I/O).
 NET_EXPORT int CreateCacheBackend(net::CacheType type,
                                   net::BackendType backend_type,
                                   const base::FilePath& path,
@@ -90,6 +72,9 @@
 // will get invoked even if the creation fails. The invocation will always be
 // via the event loop, and never direct.
 //
+// This is currently unsupported for |type| == net::DISK_CACHE or
+// net::MEDIA_CACHE.
+//
 // Note that this will not wait for |post_cleanup_callback| of a previous
 // instance for |path| to run.
 NET_EXPORT int CreateCacheBackend(net::CacheType type,
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 0f1f7ff..6acdc02 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -805,7 +805,7 @@
   if (!auth_challenge)
     return false;
   EXPECT_FALSE(auth_challenge->is_proxy);
-  EXPECT_EQ("http://172.22.68.17", auth_challenge->challenger.Serialize());
+  EXPECT_EQ("https://172.22.68.17", auth_challenge->challenger.Serialize());
   EXPECT_EQ(std::string(), auth_challenge->realm);
   EXPECT_EQ(kNtlmAuthScheme, auth_challenge->scheme);
   return true;
@@ -5950,7 +5950,7 @@
 TEST_F(HttpNetworkTransactionTest, NTLMAuth1) {
   HttpRequestInfo request;
   request.method = "GET";
-  request.url = GURL("http://172.22.68.17/kids/login.aspx");
+  request.url = GURL("https://172.22.68.17/kids/login.aspx");
 
   // Ensure load is not disrupted by flags which suppress behaviour specific
   // to other auth schemes.
@@ -6032,6 +6032,11 @@
   session_deps_.socket_factory->AddSocketDataProvider(&data1);
   session_deps_.socket_factory->AddSocketDataProvider(&data2);
 
+  SSLSocketDataProvider ssl1(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
+  SSLSocketDataProvider ssl2(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
+
   TestCompletionCallback callback1;
 
   HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
@@ -6081,7 +6086,7 @@
 TEST_F(HttpNetworkTransactionTest, NTLMAuth2) {
   HttpRequestInfo request;
   request.method = "GET";
-  request.url = GURL("http://172.22.68.17/kids/login.aspx");
+  request.url = GURL("https://172.22.68.17/kids/login.aspx");
 
   HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2,
                                                     MockGetHostName);
@@ -6210,6 +6215,13 @@
   session_deps_.socket_factory->AddSocketDataProvider(&data2);
   session_deps_.socket_factory->AddSocketDataProvider(&data3);
 
+  SSLSocketDataProvider ssl1(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
+  SSLSocketDataProvider ssl2(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
+  SSLSocketDataProvider ssl3(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3);
+
   TestCompletionCallback callback1;
 
   HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
@@ -6273,6 +6285,150 @@
   EXPECT_FALSE(response->auth_challenge);
   EXPECT_EQ(13, response->headers->GetContentLength());
 }
+
+// NTLM is not supported over HTTP/2, therefore the server requests a downgrade,
+// and the request is retried on an HTTP/1.1 connection.
+TEST_F(HttpNetworkTransactionTest, NTLMOverHttp2) {
+  HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1,
+                                                    MockGetHostName);
+
+  const char* kUrl = "https://172.22.68.17/kids/login.aspx";
+
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL(kUrl);
+
+  // First request without credentials.
+  SpdyHeaderBlock request_headers0(spdy_util_.ConstructGetHeaderBlock(kUrl));
+  SpdySerializedFrame request0(spdy_util_.ConstructSpdyHeaders(
+      1, std::move(request_headers0), LOWEST, true));
+
+  SpdyHeaderBlock response_headers0;
+  response_headers0[spdy_util_.GetStatusKey()] = "401";
+  response_headers0["www-authenticate"] = "NTLM";
+  SpdySerializedFrame resp(spdy_util_.ConstructSpdyResponseHeaders(
+      1, std::move(response_headers0), true));
+
+  // Stream 1 is closed.
+  spdy_util_.UpdateWithStreamDestruction(1);
+
+  // Retry with authorization header.
+  SpdyHeaderBlock request_headers1(spdy_util_.ConstructGetHeaderBlock(kUrl));
+  request_headers1["authorization"] =
+      "NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=";
+  SpdySerializedFrame request1(spdy_util_.ConstructSpdyHeaders(
+      3, std::move(request_headers1), LOWEST, true));
+
+  SpdySerializedFrame go_away(spdy_util_.ConstructSpdyGoAway(
+      0, ERROR_CODE_HTTP_1_1_REQUIRED, "NTLM not supported over HTTP/2."));
+
+  MockWrite writes0[] = {
+      CreateMockWrite(request0, 0), CreateMockWrite(request1, 2),
+  };
+  MockRead reads0[] = {CreateMockRead(resp, 1), CreateMockRead(go_away, 3)};
+
+  // Retry yet again using HTTP/1.1.
+  MockWrite writes1[] = {
+      // After restarting with a null identity, this is the
+      // request we should be issuing -- the final header line contains a Type
+      // 1 message.
+      MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+                "Host: 172.22.68.17\r\n"
+                "Connection: keep-alive\r\n"
+                "Authorization: NTLM "
+                "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"),
+
+      // After calling trans.RestartWithAuth(), we should send a Type 3 message
+      // (the credentials for the origin server).  The second request continues
+      // on the same connection.
+      MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
+                "Host: 172.22.68.17\r\n"
+                "Connection: keep-alive\r\n"
+                "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA"
+                "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA"
+                "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW"
+                "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX"
+                "ahlhx5I=\r\n\r\n"),
+  };
+
+  MockRead reads1[] = {
+      // The origin server responds with a Type 2 message.
+      MockRead("HTTP/1.1 401 Access Denied\r\n"),
+      MockRead("WWW-Authenticate: NTLM "
+               "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo"
+               "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE"
+               "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA"
+               "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy"
+               "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB"
+               "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw"
+               "BtAAAAAAA=\r\n"),
+      MockRead("Content-Length: 42\r\n"),
+      MockRead("Content-Type: text/html\r\n\r\n"),
+      MockRead("You are not authorized to view this page\r\n"),
+
+      // Lastly we get the desired content.
+      MockRead("HTTP/1.1 200 OK\r\n"),
+      MockRead("Content-Type: text/html; charset=utf-8\r\n"),
+      MockRead("Content-Length: 13\r\n\r\n"), MockRead("Please Login\r\n"),
+      MockRead(SYNCHRONOUS, OK),
+  };
+  SequencedSocketData data0(reads0, arraysize(reads0), writes0,
+                            arraysize(writes0));
+  StaticSocketDataProvider data1(reads1, arraysize(reads1), writes1,
+                                 arraysize(writes1));
+  session_deps_.socket_factory->AddSocketDataProvider(&data0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data1);
+
+  SSLSocketDataProvider ssl0(ASYNC, OK);
+  ssl0.next_proto = kProtoHTTP2;
+  SSLSocketDataProvider ssl1(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl0);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
+
+  std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
+
+  TestCompletionCallback callback1;
+  int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  rv = callback1.WaitForResult();
+  EXPECT_THAT(rv, IsOk());
+
+  EXPECT_FALSE(trans.IsReadyToRestartForAuth());
+
+  const HttpResponseInfo* response = trans.GetResponseInfo();
+  ASSERT_TRUE(response);
+  EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get()));
+
+  TestCompletionCallback callback2;
+
+  rv = trans.RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM),
+                             callback2.callback());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  rv = callback2.WaitForResult();
+  EXPECT_THAT(rv, IsOk());
+
+  EXPECT_TRUE(trans.IsReadyToRestartForAuth());
+
+  response = trans.GetResponseInfo();
+  ASSERT_TRUE(response);
+  EXPECT_FALSE(response->auth_challenge);
+
+  TestCompletionCallback callback3;
+
+  rv = trans.RestartWithAuth(AuthCredentials(), callback3.callback());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  rv = callback3.WaitForResult();
+  EXPECT_THAT(rv, IsOk());
+
+  response = trans.GetResponseInfo();
+  ASSERT_TRUE(response);
+  EXPECT_FALSE(response->auth_challenge);
+  EXPECT_EQ(13, response->headers->GetContentLength());
+}
 #endif  // NTLM_PORTABLE
 
 // Test reading a server response which has only headers, and no body.
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 4349812..7d34ac7 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -10400,7 +10400,6 @@
     { "name": "pagetoimage.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "painosso.org", "include_subdomains": true, "mode": "force-https" },
     { "name": "paisaone.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "pajowu.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "paperturn.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "paperwork.co.za", "include_subdomains": true, "mode": "force-https" },
     { "name": "paragreen.net", "include_subdomains": true, "mode": "force-https" },
@@ -11678,7 +11677,6 @@
     { "name": "geeklair.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "gamerslair.org", "include_subdomains": true, "mode": "force-https" },
     { "name": "gamepad.vg", "include_subdomains": true, "mode": "force-https" },
-    { "name": "gersting.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "gameisbest.jp", "include_subdomains": true, "mode": "force-https" },
     { "name": "geneau.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "gameparade.de", "include_subdomains": true, "mode": "force-https" },
@@ -11897,7 +11895,6 @@
     { "name": "loveyounastya.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "magicball.co", "include_subdomains": true, "mode": "force-https" },
     { "name": "lzkill.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "lwl-foej-bewerbung.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "luohua.im", "include_subdomains": true, "mode": "force-https" },
     { "name": "luoh.cc", "include_subdomains": true, "mode": "force-https" },
     { "name": "mailing-jbgg.com", "include_subdomains": true, "mode": "force-https" },
@@ -12262,7 +12259,6 @@
     { "name": "stargatepartners.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "stayokhotelscdc-mailing.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "stevenhumphrey.uk", "include_subdomains": true, "mode": "force-https" },
-    { "name": "stig.io", "include_subdomains": true, "mode": "force-https" },
     { "name": "stillblackhat.id", "include_subdomains": true, "mode": "force-https" },
     { "name": "stpatricksguild.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "stardanceacademy.net", "include_subdomains": true, "mode": "force-https" },
@@ -14135,7 +14131,6 @@
     { "name": "lolicon.eu", "include_subdomains": true, "mode": "force-https" },
     { "name": "lolkot.ru", "include_subdomains": true, "mode": "force-https" },
     { "name": "loopower.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "loveismore.ru", "include_subdomains": true, "mode": "force-https" },
     { "name": "lovelivewiki.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "lowhangingfruitgrabber.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "loxis.be", "include_subdomains": true, "mode": "force-https" },
@@ -17183,7 +17178,6 @@
     { "name": "elmar-kraamzorg.nl", "include_subdomains": true, "mode": "force-https" },
     { "name": "dyrkar.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "especificosba.com.ar", "include_subdomains": true, "mode": "force-https" },
-    { "name": "everpcpc.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "ehito.ovh", "include_subdomains": true, "mode": "force-https" },
     { "name": "enaah.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "enersec.co.uk", "include_subdomains": true, "mode": "force-https" },
@@ -17365,7 +17359,6 @@
     { "name": "herbweb.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "hexe.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "herbweb.org", "include_subdomains": true, "mode": "force-https" },
-    { "name": "hornblasters.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "hbdesign.work", "include_subdomains": true, "mode": "force-https" },
     { "name": "hunter.io", "include_subdomains": true, "mode": "force-https" },
     { "name": "hilnu.tk", "include_subdomains": true, "mode": "force-https" },
@@ -18626,7 +18619,6 @@
     { "name": "clipclip.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "chewey.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "chokladfantasi.net", "include_subdomains": true, "mode": "force-https" },
-    { "name": "chrisu3050.at", "include_subdomains": true, "mode": "force-https" },
     { "name": "celina-reads.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "chenky.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "clickgram.biz", "include_subdomains": true, "mode": "force-https" },
@@ -21924,7 +21916,6 @@
     { "name": "kodiaklabs.org", "include_subdomains": true, "mode": "force-https" },
     { "name": "kiddyboom.ua", "include_subdomains": true, "mode": "force-https" },
     { "name": "jutlander.dk", "include_subdomains": true, "mode": "force-https" },
-    { "name": "katzen.me", "include_subdomains": true, "mode": "force-https" },
     { "name": "jonkermedia.nl", "include_subdomains": true, "mode": "force-https" },
     { "name": "julian-witusch.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "knutur.is", "include_subdomains": true, "mode": "force-https" },
@@ -22173,7 +22164,6 @@
     { "name": "mjhsc.nl", "include_subdomains": true, "mode": "force-https" },
     { "name": "millanova.wedding", "include_subdomains": true, "mode": "force-https" },
     { "name": "mbardot.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "moeyi.xyz", "include_subdomains": true, "mode": "force-https" },
     { "name": "michael-steinhauer.eu", "include_subdomains": true, "mode": "force-https" },
     { "name": "michaelsulzer.eu", "include_subdomains": true, "mode": "force-https" },
     { "name": "mht-travel.com", "include_subdomains": true, "mode": "force-https" },
@@ -22280,7 +22270,6 @@
     { "name": "nalepte.cz", "include_subdomains": true, "mode": "force-https" },
     { "name": "newbieboss.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "neko-nyan.org", "include_subdomains": true, "mode": "force-https" },
-    { "name": "newbietech.cn", "include_subdomains": true, "mode": "force-https" },
     { "name": "nautsch.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "nadejeproninu.cz", "include_subdomains": true, "mode": "force-https" },
     { "name": "mariannenan.nl", "include_subdomains": true, "mode": "force-https" },
@@ -23186,7 +23175,6 @@
     { "name": "valoremtax.ch", "include_subdomains": true, "mode": "force-https" },
     { "name": "winbuzzer.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "viafinance.cz", "include_subdomains": true, "mode": "force-https" },
-    { "name": "warflame.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "windholz.us", "include_subdomains": true, "mode": "force-https" },
     { "name": "windwoodmedia.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "windwoodweb.com", "include_subdomains": true, "mode": "force-https" },
@@ -23825,7 +23813,6 @@
     { "name": "isthnew.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "it-cave.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "jacobi-server.de", "include_subdomains": true, "mode": "force-https" },
-    { "name": "jadefalcons.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "jahanaisamu.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "jamberrynails.co.uk", "include_subdomains": true, "mode": "force-https" },
     { "name": "jan-bucher.ch", "include_subdomains": true, "mode": "force-https" },
@@ -25564,7 +25551,6 @@
     { "name": "eintragsservice24.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "eisaev.ru", "include_subdomains": true, "mode": "force-https" },
     { "name": "ejgconsultancy.co.uk", "include_subdomains": true, "mode": "force-https" },
-    { "name": "ejone.co", "include_subdomains": true, "mode": "force-https" },
     { "name": "ekonbenefits.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "eldritchfiction.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "elektro-adam.de", "include_subdomains": true, "mode": "force-https" },
@@ -26318,7 +26304,6 @@
     { "name": "jgwb.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "jgwb.eu", "include_subdomains": true, "mode": "force-https" },
     { "name": "jhollandtranslations.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "jikegu.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "jinshavip.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "jiogo.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "jiyue.com", "include_subdomains": true, "mode": "force-https" },
@@ -26742,7 +26727,6 @@
     { "name": "meat.org.uk", "include_subdomains": true, "mode": "force-https" },
     { "name": "meathealth.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "mecanicadom.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "medicalwikis.cz", "include_subdomains": true, "mode": "force-https" },
     { "name": "mediweed.tk", "include_subdomains": true, "mode": "force-https" },
     { "name": "meeko.cc", "include_subdomains": true, "mode": "force-https" },
     { "name": "meinstartinsleben.com", "include_subdomains": true, "mode": "force-https" },
@@ -26908,7 +26892,6 @@
     { "name": "mygeotrip.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "mygreatjob.eu", "include_subdomains": true, "mode": "force-https" },
     { "name": "mygymer.ch", "include_subdomains": true, "mode": "force-https" },
-    { "name": "mylittlemoppet.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "mylocalsearch.co.uk", "include_subdomains": true, "mode": "force-https" },
     { "name": "mymed.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "mymed.eu", "include_subdomains": true, "mode": "force-https" },
@@ -27199,7 +27182,6 @@
     { "name": "perspektivwechsel-coaching.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "petangen.se", "include_subdomains": true, "mode": "force-https" },
     { "name": "petcarvers.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "petrkajzar.cz", "include_subdomains": true, "mode": "force-https" },
     { "name": "peuf.shop", "include_subdomains": true, "mode": "force-https" },
     { "name": "peyote.org", "include_subdomains": true, "mode": "force-https" },
     { "name": "pferdeeinstreu-kaufen.com", "include_subdomains": true, "mode": "force-https" },
@@ -28473,7 +28455,6 @@
     { "name": "zavetaji.lv", "include_subdomains": true, "mode": "force-https" },
     { "name": "zcgram.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "zdorovayasimya.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "zdravotnickainformatika.cz", "include_subdomains": true, "mode": "force-https" },
     { "name": "zelfmoord.ga", "include_subdomains": true, "mode": "force-https" },
     { "name": "zenghx.tk", "include_subdomains": true, "mode": "force-https" },
     { "name": "zero-x-baadf00d.com", "include_subdomains": true, "mode": "force-https" },
@@ -33792,7 +33773,6 @@
     { "name": "nba.download", "include_subdomains": true, "mode": "force-https" },
     { "name": "montanana.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "myfunworld.de", "include_subdomains": true, "mode": "force-https" },
-    { "name": "muthai.in.th", "include_subdomains": true, "mode": "force-https" },
     { "name": "nba.gs", "include_subdomains": true, "mode": "force-https" },
     { "name": "muzgra.in", "include_subdomains": true, "mode": "force-https" },
     { "name": "mehhh.xyz", "include_subdomains": true, "mode": "force-https" },
@@ -34657,7 +34637,6 @@
     { "name": "wikibulz.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "windowwellcovers.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "torontocorporatelimo.services", "include_subdomains": true, "mode": "force-https" },
-    { "name": "xfack.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "xlfblog.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "xlan.be", "include_subdomains": true, "mode": "force-https" },
     { "name": "xiangblog.com", "include_subdomains": true, "mode": "force-https" },
@@ -35009,6 +34988,354 @@
     { "name": "rdns.cc", "include_subdomains": true, "mode": "force-https" },
     { "name": "veslosada.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "www-8522.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "10og.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "2333.press", "include_subdomains": true, "mode": "force-https" },
+    { "name": "3fl.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "4baby.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "4xlabs.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "8522club.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "88laohu.cc", "include_subdomains": true, "mode": "force-https" },
+    { "name": "abona24.pl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "accbay.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "accommodation-berry.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "actionsack.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "agrarking.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "agrarshop4u.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aldien.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aliantsoft.pl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "allpointsblog.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "alternador.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "americandistribuidora.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "anchovy.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "anime1.top", "include_subdomains": true, "mode": "force-https" },
+    { "name": "antenasmundosat.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "apcemporium.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "apk.li", "include_subdomains": true, "mode": "force-https" },
+    { "name": "apn-dz.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aquarium-supplement.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "arcenergy.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "arcobalabs.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "arian.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "artsinthevalley.net.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "atlantahairsurgeon.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "atwonline.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "auntie-eileens.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "automatethis.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ayor.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ayor.tech", "include_subdomains": true, "mode": "force-https" },
+    { "name": "banksiaparkcottages.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "barsashop.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bati-alu.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bearcosports.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bellavistaoutdoor.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bemvindoaolar.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "big-fluglaerm-hamburg.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bonnieradvocaten.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "borisschapira.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "brucemartin.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bt123.xyz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "budgetlovers.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bypass.sh", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cestasedelicias.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chentianyi.cn", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chillebever.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chocolate13tilias.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "churrasqueirafacil.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cirurgicalucena.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "civilg20.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "clinicaferrusbratos.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "club-reduc.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "coderme.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "comflores.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "comodesinflamarlashemorroides.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "comorecuperaratumujerpdf.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "conformax.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "connectedcare.md", "include_subdomains": true, "mode": "force-https" },
+    { "name": "corporatecomputingsolutions.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cosmeticosdelivery.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "creativeapple.ltd", "include_subdomains": true, "mode": "force-https" },
+    { "name": "d.nf", "include_subdomains": true, "mode": "force-https" },
+    { "name": "d.nr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dbq.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "deliver.moe", "include_subdomains": true, "mode": "force-https" },
+    { "name": "denisewakeman.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "deprobe.pro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dev-talk.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "digitaljungle.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dimeponline.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "din-tools.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dingcc.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "do.gd", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dovecomputers.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dracox.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dyyn.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "e-cottage.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "educatoys.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "emporiodosperfumes.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "equinecoaching.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "equipeferramentas.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "equityflows.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "esite.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "esprit-cloture.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "faciledireto.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fameuxhosting.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fatdoge.cn", "include_subdomains": true, "mode": "force-https" },
+    { "name": "feld.design", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fernangp.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fhg90.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fitseven.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fl0000.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fl010.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fl0666.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "flunschi.goip.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "flyspace.ga", "include_subdomains": true, "mode": "force-https" },
+    { "name": "forbiddenhistory.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fr0zenbits.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "frugalfamilyhome.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gallicrooster.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "geaskb.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "geleia-real.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "giftmaniabrilhos.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "globalprojetores.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "great.nagoya", "include_subdomains": true, "mode": "force-https" },
+    { "name": "grouphomes.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gym-old.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "halitopuroprodutos.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hanys.xyz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "haogoodair.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hashinteractive.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "heartview.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "helpstarloja.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "homesandal.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hotcandlestick.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "howardwatts.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hulpbijmarketing.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "huskyduvercors.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iamprophet.pw", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ineed.com.mt", "include_subdomains": true, "mode": "force-https" },
+    { "name": "injust.eu.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "injust.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "insho.fashion", "include_subdomains": true, "mode": "force-https" },
+    { "name": "instafind.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iosnoops.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ishamf.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "istore.lt", "include_subdomains": true, "mode": "force-https" },
+    { "name": "itrack.in.th", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ivanilla.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jamaat.hk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jerseylvi2013.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jiaqiang.vip", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jingjo.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jmotion.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kakie-kolesa.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kangaroovalleykayaks.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kangaroovalleymuseum.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kangaroovalleyolives.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kangaroovalleyshow.org.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kangaroovalleywoodcrafts.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "karlsmithmn.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kazamasion.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kenrogers.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kingstclinic.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "korosiprogram.hu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kousaku.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kvcc.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kvpc.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "laboiteanem.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lakedavid.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "laymans911.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "leipziger-triathlon.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lennartheinrich.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lheinrich.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lheinrich.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "librazy.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lifesafety.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lingerielovers.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "littlenina.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "littlepigcreek.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lojaterrazul.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lojavalcapelli.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ls-reallife.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lukasfunk.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "macedopesca.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "macleodnc.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "magyarokegyhelyen.hu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "manududu.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "marilynmartin.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mathijskingma.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "maury-moteurs.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "medeinos.lt", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mediafocus.biz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "memiux.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mexicom.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "microcomploja.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mika.cat", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mimbeim.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "minimbah.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mittagonggardencentre.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "modaexecutiva.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "moderntld.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mona-antenna.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "movie4kto.stream", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mundoarabe.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mundokinderland.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mwainc.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myamend.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mygeneral.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mylatestnews.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mytruecare.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myupdatestar.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myupdatestudio.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myupdatesystems.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nairobibusinessreview.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "naoar.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "neowlan.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "netlentes.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "netmagicas.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "networkposting.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nexusbyte.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nkb.in.th", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nordnetz-hamburg.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "notadd.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "notadd.store", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nutrivisa.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nycoyote.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "officiants.wedding", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oleodecopayba.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "opcaobolsas.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oticasaopaulo.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oxro.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "panoxadrez.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "paradigi.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "patric-lenhart.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pepemodelismo.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "petofiprogram.hu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "piatabrasil.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pinnacles.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "piraten-bv-nord.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pixeame.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "placasonline.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pnukee.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pomardaserra.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pontodogame.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "portalkla.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "powerdent.net.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "prelogica.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "prestonandsons.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "productived.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "provitec.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pwm.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "qwe7002.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "radicalsub.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "randy.pw", "include_subdomains": true, "mode": "force-https" },
+    { "name": "raraflora.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rbran.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rdfz.tech", "include_subdomains": true, "mode": "force-https" },
+    { "name": "realitea.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "remedioparaherpes.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "revistapequenosolhares.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rial.space", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rimax.vn", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rivermist.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "robspeed.rocks", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rockuse.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rohanbassett.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rpine.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rtsr.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rubymartin.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "salishseawhalewatching.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "samsungxoa.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sberbank.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "schatmeester.be", "include_subdomains": true, "mode": "force-https" },
+    { "name": "selbys.net.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "semiocast.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "servicevie.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shgt.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shobhanayogsadan.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shotpixonline.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "simonsaxon.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sinuelovirtual.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sion.moe", "include_subdomains": true, "mode": "force-https" },
+    { "name": "slpower.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "smackhappy.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sohamroy.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "solicafe.at", "include_subdomains": true, "mode": "force-https" },
+    { "name": "soundedj.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "spaziobenedetti.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "spaziopervoi.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ssenberg.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stainedglass.net.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stairlin.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stannahtrapliften.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "steplogictalent.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stilettomoda.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stonemanbrasil.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "streamthemeeting.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "subwayz.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sussexwebdesigns.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sussexwebdesigns.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "swissid.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "talltreeskv.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tdrcartuchos.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "teknemodus.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tempdomain.ml", "include_subdomains": true, "mode": "force-https" },
+    { "name": "test02.dk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "texture.net.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thiscode.works", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thrivesummit.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tobias.gr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tokoindo.top", "include_subdomains": true, "mode": "force-https" },
+    { "name": "topnotchendings.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tougetu.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trainline.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trainline.com.pt", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trainline.dk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trainline.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trainline.no", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trainline.pl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trainline.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "transfersummit.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tropicalserver.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tsedryk.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tyroremotes.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tyroremotes.es", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tyroremotes.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tyroremotes.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tyroremotes.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tyroremotes.no", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ucac.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "umsapi.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uniformebateriasheliar.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uniformehope.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "urlachershop.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "valleycode.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vcti.cloud", "include_subdomains": true, "mode": "force-https" },
+    { "name": "viladochurrasco.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "visitkangaroovalley.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vitra-vcare.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vividlumen.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vwsoft.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webbx.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webless.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "welcome-werkstatt.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "welcome-werkstatt.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wellcomp.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wiiaam.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wireless-emergency-stop.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wisak.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wombatalla.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wowaffixes.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xehost.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xmiui.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xn--jywq5uqwqxhd2onsij.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xn--n8jtcugp92n4wc738f.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xn--xz1a.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xn--yj8h0m.ws", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xpjcunkuan.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "yeu.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zecrypto.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zhaoxixiangban.cc", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zoorigin.com", "include_subdomains": true, "mode": "force-https" },
     // END OF BULK ENTRIES
 
     // Manual additions and changes in Chrome 51 or later that do not belong in a
@@ -35070,7 +35397,7 @@
     { "name": "patrick.dark.name", "include_subdomains": true, "mode": "force-https" },
     { "name": "techmasters.andover.edu", "include_subdomains": true, "mode": "force-https" },
     { "name": "simpletax.ca", "include_subdomains": true, "mode": "force-https" },
-    { "name": "scotthelme.co.uk", "include_subdomains": true, "mode": "force-https", "expect_staple": true, "expect_staple_report_uri": "https://scotthelme.report-uri.io/r/default/staple/reportOnly", "include_subdomains_for_expect_staple": true },
+    { "name": "scotthelme.co.uk", "include_subdomains": true, "mode": "force-https", "expect_staple": true, "expect_staple_report_uri": "https://scotthelme.report-uri.io/r/default/staple/reportOnly", "include_subdomains_for_expect_staple": true, "expect_ct": true, "expect_ct_report_uri": "https://scotthelme.report-uri.io/r/default/ct/reportOnly", "include_subdomains_for_expect_ct": true },
     { "name": "hstspreload.appspot.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "matteomarescotti.it", "include_subdomains": true, "mode": "force-https", "expect_staple": true, "expect_staple_report_uri": "https://matteomarescotti.report-uri.io/r/default/staple/reportOnly", "include_subdomains_for_expect_staple": true },
     { "name": "www.cnet.com", "include_subdomains": true, "mode": "force-https" },
@@ -35149,6 +35476,7 @@
       "expect_staple_report_uri": "https://photistic.report-uri.io/r/default/staple/reportOnly"
     },
     { "name": "ccu.plus", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mitm-software.badssl.com", "include_subdomains": true, "mode": "force-https" },
     // END OF MANUAL ENTRIES
 
     // TODO(lgarron): hstspreload.org can't scan IPv6-only sites due to Google
diff --git a/net/quic/chromium/quic_chromium_client_session_test.cc b/net/quic/chromium/quic_chromium_client_session_test.cc
index ec8f1eb..a68719d 100644
--- a/net/quic/chromium/quic_chromium_client_session_test.cc
+++ b/net/quic/chromium/quic_chromium_client_session_test.cc
@@ -1186,6 +1186,11 @@
   struct iovec iov[1];
   iov[0].iov_base = data;
   iov[0].iov_len = 4;
+  if (session_->save_data_before_consumption()) {
+    QuicStreamPeer::SendBuffer(stream).SaveStreamData(
+        QuicIOVector(iov, arraysize(iov), 4), 0, 4);
+    QuicStreamPeer::SetStreamBytesWritten(4, stream);
+  }
   session_->WritevData(stream, stream->id(),
                        QuicIOVector(iov, arraysize(iov), 4), 0, NO_FIN,
                        nullptr);
diff --git a/net/quic/chromium/quic_chromium_client_stream.cc b/net/quic/chromium/quic_chromium_client_stream.cc
index 81f726c..0607365 100644
--- a/net/quic/chromium/quic_chromium_client_stream.cc
+++ b/net/quic/chromium/quic_chromium_client_stream.cc
@@ -548,10 +548,16 @@
   // Must not be called when data is buffered.
   DCHECK(!HasBufferedData());
   // Writes the data, or buffers it.
-  for (size_t i = 0; i < buffers.size(); ++i) {
-    bool is_fin = fin && (i == buffers.size() - 1);
-    QuicStringPiece string_data(buffers[i]->data(), lengths[i]);
-    WriteOrBufferData(string_data, is_fin, nullptr);
+  if (session_->can_use_slices()) {
+    WriteMemSlices(QuicMemSliceSpan(QuicMemSliceSpanImpl(
+                       buffers.data(), lengths.data(), buffers.size())),
+                   fin);
+  } else {
+    for (size_t i = 0; i < buffers.size(); ++i) {
+      bool is_fin = fin && (i == buffers.size() - 1);
+      QuicStringPiece string_data(buffers[i]->data(), lengths[i]);
+      WriteOrBufferData(string_data, is_fin, nullptr);
+    }
   }
   return !HasBufferedData();  // Was all data written?
 }
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc
index 716037eb..634348b 100644
--- a/net/quic/chromium/quic_network_transaction_unittest.cc
+++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -4860,7 +4860,8 @@
       GetRequestHeaders("POST", "https", "/"), &offset));
 
   std::unique_ptr<QuicEncryptedPacket> packet;
-  if (version_ == QUIC_VERSION_36) {
+  if (version_ == QUIC_VERSION_36 &&
+      !FLAGS_quic_reloadable_flag_quic_use_stream_notifier2) {
     packet = ConstructClientForceHolDataPacket(
         3, GetNthClientInitiatedStreamId(0), true, true, &offset, "1");
   } else {
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
index c0275089..964e6f7 100644
--- a/net/quic/chromium/quic_stream_factory.cc
+++ b/net/quic/chromium/quic_stream_factory.cc
@@ -347,8 +347,6 @@
 
   void OnIOComplete(int rv);
 
-  void Cancel();
-
   const QuicSessionKey& key() const { return key_; }
 
   const NetLogWithSource& net_log() const { return net_log_; }
@@ -484,14 +482,6 @@
     base::ResetAndReturn(&callback_).Run(rv);
 }
 
-void QuicStreamFactory::Job::Cancel() {
-  callback_.Reset();
-  if (session_)
-    session_->connection()->CloseConnection(
-        QUIC_CONNECTION_CANCELLED, "New job canceled.",
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
 void QuicStreamFactory::Job::PopulateNetErrorDetails(
     NetErrorDetails* details) const {
   if (!session_)
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc
index ab024e087..a5e37a27 100644
--- a/net/quic/chromium/quic_stream_factory_test.cc
+++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -4809,7 +4809,8 @@
   EXPECT_EQ(OK, callback_.WaitForResult());
 
   QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
-  if (session->connection()->version() == QUIC_VERSION_36) {
+  if (session->connection()->version() == QUIC_VERSION_36 &&
+      !FLAGS_quic_reloadable_flag_quic_use_stream_notifier2) {
     EXPECT_TRUE(session->force_hol_blocking());
   } else {
     EXPECT_FALSE(session->force_hol_blocking());
diff --git a/net/quic/core/crypto/quic_tls_adapter.cc b/net/quic/core/crypto/quic_tls_adapter.cc
new file mode 100644
index 0000000..aa7eb218
--- /dev/null
+++ b/net/quic/core/crypto/quic_tls_adapter.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/quic_tls_adapter.h"
+
+#include "net/quic/platform/api/quic_logging.h"
+#include "net/quic/platform/api/quic_text_utils.h"
+
+using std::string;
+
+namespace net {
+
+const BIO_METHOD QuicTlsAdapter::kBIOMethod = {
+    0,        // type
+    nullptr,  // name
+    QuicTlsAdapter::BIOWriteWrapper,
+    QuicTlsAdapter::BIOReadWrapper,
+    nullptr,  // puts
+    nullptr,  // gets
+    QuicTlsAdapter::BIOCtrlWrapper,
+    nullptr,  // create
+    nullptr,  // destroy
+    nullptr,  // callback_ctrl
+};
+
+// static
+QuicTlsAdapter* QuicTlsAdapter::GetAdapter(BIO* bio) {
+  DCHECK_EQ(&kBIOMethod, bio->method);
+  QuicTlsAdapter* adapter = reinterpret_cast<QuicTlsAdapter*>(bio->ptr);
+  if (adapter)
+    DCHECK_EQ(bio, adapter->bio());
+  return adapter;
+}
+
+// static
+int QuicTlsAdapter::BIOReadWrapper(BIO* bio, char* out, int len) {
+  QuicTlsAdapter* adapter = GetAdapter(bio);
+  if (!adapter)
+    return -1;
+  return adapter->Read(out, len);
+}
+
+// static
+int QuicTlsAdapter::BIOWriteWrapper(BIO* bio, const char* in, int len) {
+  QuicTlsAdapter* adapter = GetAdapter(bio);
+  if (!adapter)
+    return -1;
+  return adapter->Write(in, len);
+}
+
+// static
+// NOLINTNEXTLINE
+long QuicTlsAdapter::BIOCtrlWrapper(BIO* bio, int cmd, long larg, void* parg) {
+  QuicTlsAdapter* adapter = GetAdapter(bio);
+  if (!adapter)
+    return 0;
+  switch (cmd) {
+    // The only control request sent by the TLS stack is from BIO_flush. Any
+    // other values of |cmd| would indicate some sort of programming error.
+    case BIO_CTRL_FLUSH:
+      adapter->Flush();
+      return 1;
+  }
+  QUIC_NOTREACHED();
+  return 0;
+}
+
+QuicTlsAdapter::QuicTlsAdapter(Visitor* visitor)
+    : visitor_(visitor), bio_(BIO_new(&kBIOMethod)) {
+  bio_->ptr = this;
+  bio_->init = 1;
+}
+
+QuicTlsAdapter::~QuicTlsAdapter() {}
+
+QuicErrorCode QuicTlsAdapter::error() const {
+  // QuicTlsAdapter passes messages received from ProcessInput straight through
+  // to the TLS stack (via the BIO) and does not parse the messages at all.
+  // ProcessInput never fails, so there is never an error to provide.
+  return QUIC_NO_ERROR;
+}
+
+const string& QuicTlsAdapter::error_detail() const {
+  return error_detail_;
+}
+
+bool QuicTlsAdapter::ProcessInput(QuicStringPiece input,
+                                  Perspective perspective) {
+  read_buffer_.append(input.data(), input.length());
+  visitor_->OnDataAvailableForBIO();
+  return true;
+}
+
+size_t QuicTlsAdapter::InputBytesRemaining() const {
+  return read_buffer_.length();
+}
+
+int QuicTlsAdapter::Read(char* out, int len) {
+  if (len < 0) {
+    return -1;
+  }
+  if (len >= static_cast<int>(read_buffer_.length())) {
+    len = read_buffer_.length();
+  }
+  memcpy(out, read_buffer_.data(), len);
+  read_buffer_.erase(0, len);
+  QUIC_LOG(INFO) << "BIO_read: reading " << len << " bytes:\n"
+                 << QuicTextUtils::HexEncode(out, len);
+  return len;
+}
+
+int QuicTlsAdapter::Write(const char* in, int len) {
+  if (len < 0) {
+    return -1;
+  }
+  QUIC_LOG(INFO) << "BIO_write: writing " << len << " bytes:\n"
+                 << QuicTextUtils::HexEncode(in, len);
+  write_buffer_.append(in, len);
+  return len;
+}
+
+void QuicTlsAdapter::Flush() {
+  QUIC_LOG(INFO) << "BIO_flush: flushing " << write_buffer_.size() << " bytes";
+  visitor_->OnDataReceivedFromBIO(write_buffer_);
+  write_buffer_.clear();
+}
+
+}  // namespace net
diff --git a/net/quic/core/crypto/quic_tls_adapter.h b/net/quic/core/crypto/quic_tls_adapter.h
new file mode 100644
index 0000000..99a78e3f
--- /dev/null
+++ b/net/quic/core/crypto/quic_tls_adapter.h
@@ -0,0 +1,161 @@
+// Copyright (c) 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 NET_QUIC_CORE_CRYPTO_QUIC_TLS_ADAPTER_H_
+#define NET_QUIC_CORE_CRYPTO_QUIC_TLS_ADAPTER_H_
+
+#include "net/quic/core/crypto/crypto_message_parser.h"
+#include "net/quic/core/quic_error_codes.h"
+#include "net/quic/core/quic_types.h"
+#include "net/quic/platform/api/quic_export.h"
+#include "net/quic/platform/api/quic_string_piece.h"
+#include "third_party/boringssl/src/include/openssl/bio.h"
+
+namespace net {
+
+// QuicTlsAdapter provides an implementation of CryptoMessageParser that takes
+// incoming messages and provides them to be read in a BIO (used by the TLS
+// stack to read incoming messages). Messages written to the BIO by the TLS
+// stack are provided to the QuicTlsAdapter's consumer through the
+// OnDataReceived method of the consumer's implementation of
+// QuicTlsAdapter::Visitor.
+//
+// QuicTlsAdapter also provides an implementation of the BIO interface,
+// openssl's abstraction used by the TLS stack for I/O. The BIO interface
+// provides BIO_read, BIO_write, and BIO_flush methods, with an API very similar
+// to Berkeley sockets. This is a non-blocking interface - if data is not
+// available for the BIO consumer to read with BIO_read, it returns 0 bytes of
+// data, and the BIO consumer must handle waiting for more data and only calling
+// BIO_read once data is available to read. With a QuicTlsAdapter, the signal
+// that data is available to read is provided by
+// QuicTlsAdapter::Visitor::OnDataAvailableForBIO.
+//
+// In effect, the QuicTlsAdapter moves messages between the QuicCryptoStream and
+// the TLS stack. On one end, the QuicTlsAdapter implements CryptoMessageParser
+// to take incoming messages and make them available to be read through the BIO,
+// and on the other end, it takes messages written to the BIO and once the BIO
+// flushes them, sends them out to the QuicStream via the
+// QuicTlsAdapter::Visitor.
+//
+// Data flows from a QuicCryptoStream to the TLS stack like so:
+//  1. QuicCryptoStream::OnDataAvailable is called (by QuicStream) when data is
+//     available on the stream.
+//  2. OnDataAvailable calls CryptoMessageParser::ProcessInput; in the case of a
+//     TLS crypto stream, this is QuicTlsAdapter::ProcessInput.
+//  3. ProcessInput saves the data to QuicTlsAdapter's read buffer, and signals
+//     that data is available to read by calling
+//     QuicTlsAdapter::Visitor::OnDataAvailableForBIO.
+//  4. TlsHandshaker (which implements QuicTlsAdapter::Visitor) receives the
+//     OnDataAvailableForBIO, and has the TLS stack continue its handshake.
+//  5. The TLS stack calls BIO_read to read handshake messages, and this call is
+//     made on a BIO backed by QuicTlsAdapter.
+//  6. BIO_read calls QuicTlsAdapter::BIOReadWrapper, which calls
+//     QuicTlsAdapter::Read (on the appropriate instance) which provides the
+//     data from the read buffer written to by QuicTlsAdapter::ProcessInput.
+//
+// Data flows from the TLS stack to the QUIC crypto stream like so:
+//  1. The TLS stack makes multiple calls to BIO_write as it generates handshake
+//     messages. Via QuicTlsAdapter::BIOWriteWrapper and QuicTlsAdapter::Write,
+//     this data gets appended to the QuicTlsAdapter's write buffer.
+//  2. Once the TLS stack has written a flight of handshake messages, it calls
+//     BIO_flush. This, via QuicTlsAdapter::BIOCtrlWrapper and
+//     QuicTlsAdapter::Flush, signals to QuicTlsAdapter's Visitor that data has
+//     been received.
+//  3. QuicTlsAdapter::Flush calls
+//     QuicTlsAdapter::Visitor::OnDataReceivedFromBIO with the contents of the
+//     write buffer.
+//  4. TlsHandshaker receives the data from OnDataReceivedFromBIO, and writes it
+//     to the QUIC crypto stream.
+class QUIC_EXPORT QuicTlsAdapter : public CryptoMessageParser {
+ public:
+  // QuicTlsAdapter::Visitor is notified whenever data is received (in either
+  // direction). When data is read from the QUIC crypto stream,
+  // Visitor::OnDataAvailableForBIO is called so that the Visitor can continue
+  // reading from the BIO. (E.g. in the case of a TlsHandshaker as the Visitor,
+  // it would continue the TLS handshake, which uses a BIO for I/O.) When data
+  // is written to a QuicTlsAdapter's BIO interface and then flushed,
+  // Visitor::OnDataReceivedFromBIO is called to provide the Visitor with the
+  // data to write to the QUIC crypto stream.
+  class QUIC_EXPORT Visitor {
+   public:
+    virtual ~Visitor() {}
+
+    // OnDataAvailableForBIO is called when QuicTlsAdapter has received data
+    // (via ProcessInput) that is now available to be read by the BIO.
+    virtual void OnDataAvailableForBIO() = 0;
+
+    // OnDataReceivedFromBIO is called when data is written to the BIO. For
+    // example, when the TLS stack writes messages to the BIO and then flushes
+    // them, the resulting data will be made available to the Visitor via this
+    // method, so that the Visitor can write the messages to the QuicStream. The
+    // stringpiece |data| is only valid during the execution of this function;
+    // implementations must consume all of |data|.
+    virtual void OnDataReceivedFromBIO(const QuicStringPiece& data) = 0;
+  };
+
+  // Constructs a QuicTlsAdapter that will notify |visitor| when data is
+  // available in either direction. The provided Visitor must outlive the
+  // QuicTlsAdapter.
+  explicit QuicTlsAdapter(Visitor* visitor);
+
+  ~QuicTlsAdapter() override;
+
+  QuicErrorCode error() const override;
+  const std::string& error_detail() const override;
+  bool ProcessInput(QuicStringPiece input, Perspective perspective) override;
+  size_t InputBytesRemaining() const override;
+
+  BIO* bio() { return bio_.get(); }
+
+ private:
+  // The following methods, Read, Write, and Flush, are used to implement the
+  // BIO.
+
+  // Read copies up to |len| bytes from |read_buffer_| into |out|. It returns
+  // the number of bytes copied, zero on EOF, or a negative number on error.
+  int Read(char* out, int len);
+
+  // Write appends |len| bytes from |in| to |write_buffer_|. It returns |len|,
+  // or a negative number on error.
+  int Write(const char* in, int len);
+
+  // Flush calls Visitor::OnDataReceivedFromBIO with the data in
+  // |write_buffer_| and then empties the buffer.
+  void Flush();
+
+  // Used by the static BIO*Wrapper methods to get the QuicTlsAdapter instance
+  // to call Read/Write/Flush on.
+  static QuicTlsAdapter* GetAdapter(BIO* bio);
+
+  // Functions used to build a BIO_METHOD vtable. BIOReadWrapper calls Read,
+  // BIOWriteWrapper calls Write, and BIOCtrlWrapper calls Flush if |cmd| is
+  // |BIO_CTRL_FLUSH|.
+
+  static int BIOReadWrapper(BIO* bio, char* out, int len);
+  static int BIOWriteWrapper(BIO* bio, const char* in, int len);
+  // BIOCtrlWrapper has the type it does so it can be used as the |ctrl| field
+  // in a BIO_METHOD struct, hence the use of long as an argument  and return
+  // type.
+  // NOLINTNEXTLINE
+  static long BIOCtrlWrapper(BIO* bio, int cmd, long larg, void* parg);
+
+  static const BIO_METHOD kBIOMethod;
+
+  // Visitor to call when QuicTlsAdapter receives data (in either direction).
+  Visitor* visitor_;
+  bssl::UniquePtr<BIO> bio_;
+
+  // Buffer of data received from ProcessInput waiting to be read by the BIO.
+  std::string read_buffer_;
+
+  // Buffer of data received from the BIO waiting to be handed off to
+  // Visitor::OnDataReceivedFromBIO.
+  std::string write_buffer_;
+
+  std::string error_detail_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CORE_CRYPTO_QUIC_TLS_ADAPTER_H_
diff --git a/net/quic/core/crypto/quic_tls_adapter_test.cc b/net/quic/core/crypto/quic_tls_adapter_test.cc
new file mode 100644
index 0000000..9a7c7cc
--- /dev/null
+++ b/net/quic/core/crypto/quic_tls_adapter_test.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/core/crypto/quic_tls_adapter.h"
+
+#include <vector>
+
+#include "net/quic/platform/api/quic_test.h"
+#include "third_party/boringssl/src/include/openssl/bio.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+class TestVisitor : public QuicTlsAdapter::Visitor {
+ public:
+  void OnDataAvailableForBIO() override { data_available_count_++; }
+
+  void OnDataReceivedFromBIO(const QuicStringPiece& data) override {
+    received_messages_.push_back(string(data.data(), data.length()));
+  }
+
+  int data_available_count() const { return data_available_count_; }
+
+  const std::vector<string>& received_messages() const {
+    return received_messages_;
+  }
+
+ private:
+  int data_available_count_ = 0;
+  std::vector<string> received_messages_;
+};
+
+class QuicTlsAdapterTest : public QuicTestWithParam<Perspective> {
+ public:
+  QuicTlsAdapterTest() : adapter_(&visitor_) { bio_ = adapter_.bio(); }
+
+ protected:
+  TestVisitor visitor_;
+  QuicTlsAdapter adapter_;
+  BIO* bio_;
+};
+
+INSTANTIATE_TEST_CASE_P(Tests,
+                        QuicTlsAdapterTest,
+                        ::testing::Values(Perspective::IS_CLIENT,
+                                          Perspective::IS_SERVER));
+
+TEST_P(QuicTlsAdapterTest, ProcessInput) {
+  string input = "abc";
+  EXPECT_TRUE(adapter_.ProcessInput(input, GetParam()));
+  EXPECT_EQ(1, visitor_.data_available_count());
+
+  char buf[4];
+  ASSERT_EQ(static_cast<int>(input.length()),
+            BIO_read(bio_, buf, arraysize(buf)));
+  EXPECT_EQ(input, string(buf, input.length()));
+}
+
+TEST_P(QuicTlsAdapterTest, BIORead) {
+  string input1 = "abcd";
+  string input2 = "efgh";
+
+  EXPECT_TRUE(adapter_.ProcessInput(input1, GetParam()));
+  EXPECT_EQ(QUIC_NO_ERROR, adapter_.error());
+  EXPECT_EQ(1, visitor_.data_available_count());
+
+  // Test that a call to BIO_read for less than what is in |adapter_|'s buffer
+  // still leaves more input remaining to read.
+  char buf1[3];
+  ASSERT_EQ(static_cast<int>(arraysize(buf1)),
+            BIO_read(bio_, buf1, arraysize(buf1)));
+  EXPECT_EQ("abc", string(buf1, arraysize(buf1)));
+  EXPECT_EQ(1u, adapter_.InputBytesRemaining());
+
+  // Test that the bytes read by BIO_read can span input read in by
+  // ProcessInput.
+  EXPECT_TRUE(adapter_.ProcessInput(input2, GetParam()));
+  EXPECT_EQ(QUIC_NO_ERROR, adapter_.error());
+  EXPECT_EQ(2, visitor_.data_available_count());
+  char buf2[5];
+  ASSERT_EQ(static_cast<int>(arraysize(buf2)),
+            BIO_read(bio_, buf2, arraysize(buf2)));
+  EXPECT_EQ("defgh", string(buf2, arraysize(buf2)));
+  EXPECT_EQ(0u, adapter_.InputBytesRemaining());
+}
+
+TEST_P(QuicTlsAdapterTest, BIOWrite) {
+  string input = "abcde";
+  // Test that just calling BIO_write does not post any messages to the Visitor.
+  EXPECT_EQ(static_cast<int>(input.length()),
+            BIO_write(bio_, input.data(), input.length()));
+  ASSERT_EQ(0u, visitor_.received_messages().size());
+
+  // Test that calling BIO_flush does post the message to the Visitor.
+  EXPECT_EQ(1, BIO_flush(bio_));
+  ASSERT_EQ(1u, visitor_.received_messages().size());
+  EXPECT_EQ(input, visitor_.received_messages()[0]);
+
+  // Test that multiple calls to BIO_write, followed by one call to BIO_flush
+  // results in only one call to Visitor::OnDataReceivedFromBIO.
+  EXPECT_EQ(static_cast<int>(input.length()),
+            BIO_write(bio_, input.data(), input.length()));
+  EXPECT_EQ(static_cast<int>(input.length()),
+            BIO_write(bio_, input.data(), input.length()));
+  EXPECT_EQ(1, BIO_flush(bio_));
+  ASSERT_EQ(2u, visitor_.received_messages().size());
+  EXPECT_EQ("abcdeabcde", visitor_.received_messages()[1]);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/core/quic_alarm_test.cc b/net/quic/core/quic_alarm_test.cc
index e665f313..fc58ded 100644
--- a/net/quic/core/quic_alarm_test.cc
+++ b/net/quic/core/quic_alarm_test.cc
@@ -6,7 +6,6 @@
 
 #include "net/quic/platform/api/quic_test.h"
 
-using testing::Return;
 using testing::Invoke;
 
 namespace net {
diff --git a/net/quic/core/quic_blocked_writer_interface.h b/net/quic/core/quic_blocked_writer_interface.h
index 2da2eb4..0dba5d3 100644
--- a/net/quic/core/quic_blocked_writer_interface.h
+++ b/net/quic/core/quic_blocked_writer_interface.h
@@ -19,7 +19,7 @@
 
   // Called by the PacketWriter when the underlying socket becomes writable
   // so that the BlockedWriter can go ahead and try writing.
-  virtual void OnCanWrite() = 0;
+  virtual void OnBlockedWriterCanWrite() = 0;
 };
 
 }  // namespace net
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index 32bb773..504d1a5c0 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -1269,6 +1269,10 @@
   current_packet_data_ = nullptr;
 }
 
+void QuicConnection::OnBlockedWriterCanWrite() {
+  OnCanWrite();
+}
+
 void QuicConnection::OnCanWrite() {
   DCHECK(!writer_->IsWriteBlocked());
 
@@ -1323,6 +1327,8 @@
             last_packet_destination_address_.host().Normalized()) {
       if (FLAGS_quic_reloadable_flag_quic_allow_one_address_change &&
           AllowSelfAddressChange()) {
+        QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_allow_one_address_change, 2,
+                          2);
         OnSelfAddressChange();
       } else {
         CloseConnection(
@@ -1514,7 +1520,7 @@
   // Termination packets are eventually owned by TimeWaitListManager.
   // Others are deleted at the end of this call.
   if (is_termination_packet) {
-    if (termination_packets_.get() == nullptr) {
+    if (termination_packets_ == nullptr) {
       termination_packets_.reset(
           new std::vector<std::unique_ptr<QuicEncryptedPacket>>);
     }
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h
index fc180415..6b624c05 100644
--- a/net/quic/core/quic_connection.h
+++ b/net/quic/core/quic_connection.h
@@ -396,7 +396,10 @@
   // QuicBlockedWriterInterface
   // Called when the underlying connection becomes writable to allow queued
   // writes to happen.
-  void OnCanWrite() override;
+  void OnBlockedWriterCanWrite() override;
+
+  // Called when the caller thinks it's worth a try to write.
+  virtual void OnCanWrite();
 
   // Called when an error occurs while attempting to write a packet to the
   // network.
diff --git a/net/quic/core/quic_crypto_client_handshaker.cc b/net/quic/core/quic_crypto_client_handshaker.cc
index 2fe6c6f6..0b5d96e 100644
--- a/net/quic/core/quic_crypto_client_handshaker.cc
+++ b/net/quic/core/quic_crypto_client_handshaker.cc
@@ -372,7 +372,7 @@
     return;
   }
   CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT);
-  channel_id_sent_ = (channel_id_key_.get() != nullptr);
+  channel_id_sent_ = (channel_id_key_ != nullptr);
   if (cached->proof_verify_details()) {
     proof_handler_->OnProofVerifyDetailsAvailable(
         *cached->proof_verify_details());
@@ -503,7 +503,7 @@
                         base::TimeTicks::Now() - proof_verify_start_time_);
   }
   if (!verify_ok_) {
-    if (verify_details_.get()) {
+    if (verify_details_) {
       proof_handler_->OnProofVerifyDetailsAvailable(*verify_details_);
     }
     if (num_client_hellos_ == 0) {
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index 2588eca3..32bf3c1 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -110,7 +110,7 @@
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_pcc, false)
 
 // If true, enable QUIC v40.
-QUIC_FLAG(bool, FLAGS_quic_enable_version_40, false)
+QUIC_FLAG(bool, FLAGS_quic_enable_version_40, true)
 
 // In QUIC, QuicSession gets notified when stream frames are acked, discarded or
 // retransmitted.
@@ -161,7 +161,7 @@
 // If true, application data is saved before consumption in QUIC.
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_save_data_before_consumption2,
-          false)
+          true)
 
 // If buffered data in QUIC stream is less than this threshold, buffers all
 // provided data or asks upper layer for more data.
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc
index 90e7280..c4e50b8 100644
--- a/net/quic/core/quic_framer.cc
+++ b/net/quic/core/quic_framer.cc
@@ -1632,7 +1632,7 @@
 }
 
 void QuicFramer::SetDecrypter(EncryptionLevel level, QuicDecrypter* decrypter) {
-  DCHECK(alternative_decrypter_.get() == nullptr);
+  DCHECK(alternative_decrypter_ == nullptr);
   DCHECK_GE(level, decrypter_level_);
   decrypter_.reset(decrypter);
   decrypter_level_ = level;
@@ -1685,7 +1685,7 @@
                                   const QuicPacket& packet,
                                   char* buffer,
                                   size_t buffer_len) {
-  DCHECK(encrypter_[level].get() != nullptr);
+  DCHECK(encrypter_[level] != nullptr);
 
   QuicStringPiece associated_data = packet.AssociatedData(quic_version_);
   // Copy in the header, because the encrypter only populates the encrypted
@@ -1711,7 +1711,7 @@
   size_t min_plaintext_size = ciphertext_size;
 
   for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; i++) {
-    if (encrypter_[i].get() != nullptr) {
+    if (encrypter_[i] != nullptr) {
       size_t size = encrypter_[i]->GetMaxPlaintextSize(ciphertext_size);
       if (size < min_plaintext_size) {
         min_plaintext_size = size;
@@ -1729,7 +1729,7 @@
                                 size_t buffer_length,
                                 size_t* decrypted_length) {
   QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload();
-  DCHECK(decrypter_.get() != nullptr);
+  DCHECK(decrypter_ != nullptr);
   QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket(
       quic_version_, packet, header.public_header.connection_id_length,
       header.public_header.version_flag, header.public_header.nonce != nullptr,
@@ -1740,7 +1740,7 @@
       decrypted_buffer, decrypted_length, buffer_length);
   if (success) {
     visitor_->OnDecryptedPacket(decrypter_level_);
-  } else if (alternative_decrypter_.get() != nullptr) {
+  } else if (alternative_decrypter_ != nullptr) {
     if (header.public_header.nonce != nullptr) {
       DCHECK_EQ(perspective_, Perspective::IS_CLIENT);
       alternative_decrypter_->SetDiversificationNonce(
diff --git a/net/quic/core/quic_headers_stream_test.cc b/net/quic/core/quic_headers_stream_test.cc
index e0b28f36..dce57ad 100644
--- a/net/quic/core/quic_headers_stream_test.cc
+++ b/net/quic/core/quic_headers_stream_test.cc
@@ -33,7 +33,6 @@
 using std::string;
 using testing::_;
 using testing::AtLeast;
-using testing::HasSubstr;
 using testing::InSequence;
 using testing::Invoke;
 using testing::Return;
diff --git a/net/quic/core/quic_sent_packet_manager_test.cc b/net/quic/core/quic_sent_packet_manager_test.cc
index bce2bbd..5ca5590 100644
--- a/net/quic/core/quic_sent_packet_manager_test.cc
+++ b/net/quic/core/quic_sent_packet_manager_test.cc
@@ -22,7 +22,6 @@
 using testing::Pair;
 using testing::Pointwise;
 using testing::Return;
-using testing::SetArgPointee;
 using testing::StrictMock;
 using testing::_;
 
diff --git a/net/quic/core/quic_server_session_base.cc b/net/quic/core/quic_server_session_base.cc
index 2a352ca8..fef219e 100644
--- a/net/quic/core/quic_server_session_base.cc
+++ b/net/quic/core/quic_server_session_base.cc
@@ -90,7 +90,7 @@
   QuicSession::OnConnectionClosed(error, error_details, source);
   // In the unlikely event we get a connection close while doing an asynchronous
   // crypto event, make sure we cancel the callback.
-  if (crypto_stream_.get() != nullptr) {
+  if (crypto_stream_ != nullptr) {
     crypto_stream_->CancelOutstandingCallbacks();
   }
 }
diff --git a/net/quic/core/quic_simple_buffer_allocator_test.cc b/net/quic/core/quic_simple_buffer_allocator_test.cc
index 3549997..1e9244b 100644
--- a/net/quic/core/quic_simple_buffer_allocator_test.cc
+++ b/net/quic/core/quic_simple_buffer_allocator_test.cc
@@ -7,8 +7,6 @@
 #include "net/quic/core/quic_packets.h"
 #include "net/quic/platform/api/quic_test.h"
 
-using ::testing::Eq;
-
 namespace net {
 namespace {
 
diff --git a/net/quic/core/quic_stream_test.cc b/net/quic/core/quic_stream_test.cc
index 40d1d3c..d4d6645 100644
--- a/net/quic/core/quic_stream_test.cc
+++ b/net/quic/core/quic_stream_test.cc
@@ -1016,7 +1016,7 @@
     return;
   }
   char data[1024];
-  std::vector<std::pair<char*, size_t>> buffers;
+  std::vector<std::pair<char*, int>> buffers;
   buffers.push_back(std::make_pair(data, arraysize(data)));
   buffers.push_back(std::make_pair(data, arraysize(data)));
   QuicTestMemSliceVector vector1(buffers);
diff --git a/net/quic/platform/api/quic_mem_slice_span_test.cc b/net/quic/platform/api/quic_mem_slice_span_test.cc
index 23464d00..827dc78 100644
--- a/net/quic/platform/api/quic_mem_slice_span_test.cc
+++ b/net/quic/platform/api/quic_mem_slice_span_test.cc
@@ -22,7 +22,7 @@
   }
 
   char data_[1024];
-  std::vector<std::pair<char*, size_t>> buffers_;
+  std::vector<std::pair<char*, int>> buffers_;
 };
 
 TEST_F(QuicMemSliceSpanImplTest, SaveDataInSendBuffer) {
diff --git a/net/quic/platform/api/quic_test_mem_slice_vector.h b/net/quic/platform/api/quic_test_mem_slice_vector.h
index a5bc275c..8602187 100644
--- a/net/quic/platform/api/quic_test_mem_slice_vector.h
+++ b/net/quic/platform/api/quic_test_mem_slice_vector.h
@@ -20,7 +20,7 @@
 // returned QuicMemSliceSpan.
 class QuicTestMemSliceVector {
  public:
-  explicit QuicTestMemSliceVector(std::vector<std::pair<char*, size_t>> buffers)
+  explicit QuicTestMemSliceVector(std::vector<std::pair<char*, int>> buffers)
       : impl_(std::move(buffers)) {}
 
   QuicMemSliceSpan span() { return QuicMemSliceSpan(impl_.span()); }
diff --git a/net/quic/platform/impl/quic_mem_slice_span_impl.cc b/net/quic/platform/impl/quic_mem_slice_span_impl.cc
index 48c4816..2f488f5 100644
--- a/net/quic/platform/impl/quic_mem_slice_span_impl.cc
+++ b/net/quic/platform/impl/quic_mem_slice_span_impl.cc
@@ -10,12 +10,10 @@
 namespace net {
 
 QuicMemSliceSpanImpl::QuicMemSliceSpanImpl(
-    const std::vector<scoped_refptr<IOBuffer>>* buffers,
-    const std::vector<size_t>* lengths)
-    : buffers_(buffers), lengths_(lengths) {
-  QUIC_BUG_IF(buffers->size() != lengths->size())
-      << " buffers size and lengths size are not equal";
-}
+    const scoped_refptr<IOBuffer>* buffers,
+    const int* lengths,
+    size_t num_buffers)
+    : buffers_(buffers), lengths_(lengths), num_buffers_(num_buffers) {}
 
 QuicMemSliceSpanImpl::QuicMemSliceSpanImpl(const QuicMemSliceSpanImpl& other) =
     default;
@@ -31,10 +29,10 @@
 QuicByteCount QuicMemSliceSpanImpl::SaveMemSlicesInSendBuffer(
     QuicStreamSendBuffer* send_buffer) {
   size_t saved_length = 0;
-  for (size_t i = 0; i < buffers_->size(); ++i) {
-    saved_length += (*lengths_)[i];
+  for (size_t i = 0; i < num_buffers_; ++i) {
+    saved_length += lengths_[i];
     send_buffer->SaveMemSlice(
-        QuicMemSlice(QuicMemSliceImpl((*buffers_)[i], (*lengths_)[i])));
+        QuicMemSlice(QuicMemSliceImpl(buffers_[i], lengths_[i])));
   }
   return saved_length;
 }
diff --git a/net/quic/platform/impl/quic_mem_slice_span_impl.h b/net/quic/platform/impl/quic_mem_slice_span_impl.h
index 309d60f..3e8d495 100644
--- a/net/quic/platform/impl/quic_mem_slice_span_impl.h
+++ b/net/quic/platform/impl/quic_mem_slice_span_impl.h
@@ -16,8 +16,9 @@
 // QuicMemSliceSpanImpl wraps a MemSlice span.
 class QUIC_EXPORT_PRIVATE QuicMemSliceSpanImpl {
  public:
-  QuicMemSliceSpanImpl(const std::vector<scoped_refptr<IOBuffer>>* buffers,
-                       const std::vector<size_t>* lengths);
+  QuicMemSliceSpanImpl(const scoped_refptr<IOBuffer>* buffers,
+                       const int* lengths,
+                       size_t num_buffers);
 
   QuicMemSliceSpanImpl(const QuicMemSliceSpanImpl& other);
   QuicMemSliceSpanImpl& operator=(const QuicMemSliceSpanImpl& other);
@@ -30,11 +31,13 @@
   // saved mem slices.
   QuicByteCount SaveMemSlicesInSendBuffer(QuicStreamSendBuffer* send_buffer);
 
-  bool empty() const { return buffers_->empty(); }
+  bool empty() const { return num_buffers_ == 0; }
 
  private:
-  const std::vector<scoped_refptr<IOBuffer>>* buffers_;
-  const std::vector<size_t>* lengths_;
+  const scoped_refptr<IOBuffer>* buffers_;
+  const int* lengths_;
+  // Not const so that the move operator can work properly.
+  size_t num_buffers_;
 };
 
 }  // namespace net
diff --git a/net/quic/platform/impl/quic_test_mem_slice_vector_impl.cc b/net/quic/platform/impl/quic_test_mem_slice_vector_impl.cc
index 03e650b..33a9aeeb 100644
--- a/net/quic/platform/impl/quic_test_mem_slice_vector_impl.cc
+++ b/net/quic/platform/impl/quic_test_mem_slice_vector_impl.cc
@@ -14,7 +14,7 @@
 QuicTestMemSliceVectorImpl::~QuicTestMemSliceVectorImpl() {}
 
 QuicTestMemSliceVectorImpl::QuicTestMemSliceVectorImpl(
-    std::vector<std::pair<char*, size_t>> buffers) {
+    std::vector<std::pair<char*, int>> buffers) {
   for (auto& buffer : buffers) {
     buffers_.push_back(new TestIOBuffer(buffer.first));
     lengths_.push_back(buffer.second);
@@ -22,7 +22,8 @@
 }
 
 QuicMemSliceSpanImpl QuicTestMemSliceVectorImpl::span() {
-  return QuicMemSliceSpanImpl(&buffers_, &lengths_);
+  return QuicMemSliceSpanImpl(buffers_.data(), lengths_.data(),
+                              buffers_.size());
 }
 
 }  // namespace test
diff --git a/net/quic/platform/impl/quic_test_mem_slice_vector_impl.h b/net/quic/platform/impl/quic_test_mem_slice_vector_impl.h
index 6fa01282..42edc9a 100644
--- a/net/quic/platform/impl/quic_test_mem_slice_vector_impl.h
+++ b/net/quic/platform/impl/quic_test_mem_slice_vector_impl.h
@@ -22,14 +22,14 @@
 class QuicTestMemSliceVectorImpl {
  public:
   explicit QuicTestMemSliceVectorImpl(
-      std::vector<std::pair<char*, size_t>> buffers);
+      std::vector<std::pair<char*, int>> buffers);
   ~QuicTestMemSliceVectorImpl();
 
   QuicMemSliceSpanImpl span();
 
  private:
   std::vector<scoped_refptr<IOBuffer>> buffers_;
-  std::vector<size_t> lengths_;
+  std::vector<int> lengths_;
 };
 
 }  // namespace test
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index 2d21004..87ec620 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -3184,7 +3184,7 @@
 }
 
 void SpdySession::QueueSendStalledStream(const SpdyStream& stream) {
-  DCHECK(stream.send_stalled_by_flow_control());
+  DCHECK(stream.send_stalled_by_flow_control() || IsSendStalled());
   RequestPriority priority = stream.priority();
   CHECK_GE(priority, MINIMUM_PRIORITY);
   CHECK_LE(priority, MAXIMUM_PRIORITY);
@@ -3197,6 +3197,8 @@
   // have to worry about streams being closed, as well as ourselves
   // being closed.
 
+  std::deque<SpdyStream*> streams_to_requeue;
+
   while (!IsSendStalled()) {
     size_t old_size = 0;
 #if DCHECK_IS_ON()
@@ -3210,13 +3212,20 @@
     // The stream may actually still be send-stalled after this (due
     // to its own send window) but that's okay -- it'll then be
     // resumed once its send window increases.
-    if (it != active_streams_.end())
-      it->second->PossiblyResumeIfSendStalled();
+    if (it != active_streams_.end()) {
+      if (it->second->PossiblyResumeIfSendStalled() == SpdyStream::Requeue)
+        streams_to_requeue.push_back(it->second);
+    }
 
     // The size should decrease unless we got send-stalled again.
     if (!IsSendStalled())
       DCHECK_LT(GetTotalSize(stream_send_unstall_queue_), old_size);
   }
+  while (!streams_to_requeue.empty()) {
+    SpdyStream* stream = streams_to_requeue.front();
+    streams_to_requeue.pop_front();
+    QueueSendStalledStream(*stream);
+  }
 }
 
 SpdyStreamId SpdySession::PopStreamToPossiblyResume() {
diff --git a/net/spdy/chromium/spdy_session_unittest.cc b/net/spdy/chromium/spdy_session_unittest.cc
index fe25445..e94de4c 100644
--- a/net/spdy/chromium/spdy_session_unittest.cc
+++ b/net/spdy/chromium/spdy_session_unittest.cc
@@ -4563,6 +4563,120 @@
   EXPECT_TRUE(data.AllReadDataConsumed());
 }
 
+// An upload stream is stalled when the session gets unstalled, then the session
+// is stalled again when the stream gets unstalled.  The stream should not fail.
+// Regression test for https://crbug.com/761919.
+TEST_F(SpdySessionTest, ResumeSessionWithStalledStream) {
+  SpdySerializedFrame req1(spdy_util_.ConstructSpdyPost(
+      kDefaultUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
+  SpdySerializedFrame req2(spdy_util_.ConstructSpdyPost(
+      kDefaultUrl, 3, kBodyDataSize, LOWEST, nullptr, 0));
+  SpdySerializedFrame body1(
+      spdy_util_.ConstructSpdyDataFrame(3, kBodyData, kBodyDataSize, true));
+  SpdySerializedFrame body2(
+      spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, true));
+  MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
+                        CreateMockWrite(body1, 2), CreateMockWrite(body2, 3)};
+
+  SpdySerializedFrame resp1(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+  SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
+  MockRead reads[] = {CreateMockRead(resp1, 4), CreateMockRead(resp2, 5),
+                      MockRead(ASYNC, 0, 6)};
+
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+  AddSSLSocketData();
+
+  CreateNetworkSession();
+  CreateSpdySession();
+
+  base::WeakPtr<SpdyStream> stream1 =
+      CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+                                test_url_, LOWEST, NetLogWithSource());
+  ASSERT_TRUE(stream1);
+
+  test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
+  stream1->SetDelegate(&delegate1);
+
+  base::WeakPtr<SpdyStream> stream2 =
+      CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_,
+                                test_url_, LOWEST, NetLogWithSource());
+  ASSERT_TRUE(stream2);
+
+  test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
+  stream2->SetDelegate(&delegate2);
+
+  EXPECT_FALSE(stream1->send_stalled_by_flow_control());
+  EXPECT_FALSE(stream2->send_stalled_by_flow_control());
+
+  StallSessionSend();
+
+  SpdyHeaderBlock headers1(
+      spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
+  EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequestHeaders(std::move(headers1),
+                                                        MORE_DATA_TO_SEND));
+  EXPECT_EQ(kDefaultUrl, stream1->GetUrlFromHeaders().spec());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1u, stream1->stream_id());
+  EXPECT_TRUE(stream1->send_stalled_by_flow_control());
+
+  SpdyHeaderBlock headers2(
+      spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kBodyDataSize));
+  EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequestHeaders(std::move(headers2),
+                                                        MORE_DATA_TO_SEND));
+  EXPECT_EQ(kDefaultUrl, stream2->GetUrlFromHeaders().spec());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(3u, stream2->stream_id());
+  EXPECT_TRUE(stream2->send_stalled_by_flow_control());
+
+  StallStreamSend(stream1.get());
+
+  // At this point, both |session| and |stream1| are stalled
+  // by their respective flow control mechanisms.  Now unstall the session.
+  // This calls session->ResumeSendStalledStreams(), which calls
+  // stream1->PossiblyResumeIfSendStalled().  However, |stream1| is stalled, so
+  // no data are sent on that stream.  At this point, |stream1| should not be
+  // removed from session_->stream_send_unstall_queue_.
+  // Then stream2->PossiblyResumeIfSendStalled() is called,
+  // data are sent on |stream2|, and |session_| stalls again.
+  UnstallSessionSend(kBodyDataSize);
+
+  EXPECT_TRUE(stream1->send_stalled_by_flow_control());
+  EXPECT_FALSE(stream2->send_stalled_by_flow_control());
+
+  // Make sure that the session is stalled.  Otherwise
+  // stream1->PossiblyResumeIfSendStalled() would resume the stream as soon as
+  // the stream is unstalled, hiding the bug.
+  EXPECT_TRUE(session_->IsSendStalled());
+  UnstallStreamSend(stream1.get(), kBodyDataSize);
+
+  // Finally, unstall session.
+  UnstallSessionSend(kBodyDataSize);
+
+  EXPECT_FALSE(stream1->send_stalled_by_flow_control());
+  EXPECT_FALSE(stream2->send_stalled_by_flow_control());
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_THAT(delegate1.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
+  EXPECT_THAT(delegate2.WaitForClose(), IsError(ERR_CONNECTION_CLOSED));
+
+  EXPECT_TRUE(delegate1.send_headers_completed());
+  EXPECT_EQ("200", delegate1.GetResponseHeaderValue(":status"));
+  EXPECT_EQ(SpdyString(), delegate1.TakeReceivedData());
+
+  EXPECT_TRUE(delegate2.send_headers_completed());
+  EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
+  EXPECT_EQ(SpdyString(), delegate2.TakeReceivedData());
+
+  EXPECT_FALSE(session_);
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
+}
+
 // Delegate that closes a given stream after sending its body.
 class StreamClosingDelegate : public test::StreamDelegateWithBody {
  public:
diff --git a/net/spdy/chromium/spdy_stream.cc b/net/spdy/chromium/spdy_stream.cc
index 40e696c..dd63fd4 100644
--- a/net/spdy/chromium/spdy_stream.cc
+++ b/net/spdy/chromium/spdy_stream.cc
@@ -734,17 +734,17 @@
   return session_->GetNegotiatedProtocol();
 }
 
-void SpdyStream::PossiblyResumeIfSendStalled() {
-  if (IsLocallyClosed()) {
-    return;
+SpdyStream::ShouldRequeueStream SpdyStream::PossiblyResumeIfSendStalled() {
+  if (IsLocallyClosed() || !send_stalled_by_flow_control_)
+    return DoNotRequeue;
+  if (session_->IsSendStalled() || send_window_size_ <= 0) {
+    return Requeue;
   }
-  if (send_stalled_by_flow_control_ && !session_->IsSendStalled() &&
-      send_window_size_ > 0) {
-    net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_FLOW_CONTROL_UNSTALLED,
-                      NetLog::IntCallback("stream_id", stream_id_));
-    send_stalled_by_flow_control_ = false;
-    QueueNextDataFrame();
-  }
+  net_log_.AddEvent(NetLogEventType::HTTP2_STREAM_FLOW_CONTROL_UNSTALLED,
+                    NetLog::IntCallback("stream_id", stream_id_));
+  send_stalled_by_flow_control_ = false;
+  QueueNextDataFrame();
+  return DoNotRequeue;
 }
 
 bool SpdyStream::IsClosed() const {
diff --git a/net/spdy/chromium/spdy_stream.h b/net/spdy/chromium/spdy_stream.h
index 26a8a0f..9dcd13b 100644
--- a/net/spdy/chromium/spdy_stream.h
+++ b/net/spdy/chromium/spdy_stream.h
@@ -336,7 +336,8 @@
   // set |send_stalled_by_flow_control_| to false and unstall the data
   // sending. Called by the session or by the stream itself. Must be
   // called only when the stream is still open.
-  void PossiblyResumeIfSendStalled();
+  enum ShouldRequeueStream { Requeue, DoNotRequeue };
+  ShouldRequeueStream PossiblyResumeIfSendStalled();
 
   // Returns whether or not this stream is closed. Note that the only
   // time a stream is closed and not deleted is in its delegate's
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index bf1a41db..cc58d00f 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -260,6 +260,10 @@
 
 BaseTestServer::~BaseTestServer() {}
 
+bool BaseTestServer::Start() {
+  return StartInBackground() && BlockUntilStarted();
+}
+
 const HostPortPair& BaseTestServer::host_port_pair() const {
   DCHECK(started_);
   return host_port_pair_;
@@ -463,6 +467,7 @@
 
 bool BaseTestServer::SetupWhenServerStarted() {
   DCHECK(host_port_pair_.port());
+  DCHECK(!started_);
 
   if (UsingSSL(type_) && !LoadTestRootCert())
       return false;
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
index fd44381ab..ae50bce1 100644
--- a/net/test/spawned_test_server/base_test_server.h
+++ b/net/test/spawned_test_server/base_test_server.h
@@ -304,6 +304,29 @@
   // Initialize a TestServer with a specific set of SSLOptions for HTTPS or WSS.
   BaseTestServer(Type type, const SSLOptions& ssl_options);
 
+  // Starts the server blocking until the server is ready.
+  bool Start() WARN_UNUSED_RESULT;
+
+  // Start the test server without blocking. Use this if you need multiple test
+  // servers (such as WebSockets and HTTP, or HTTP and HTTPS). You must call
+  // BlockUntilStarted on all servers your test requires before executing the
+  // test. For example:
+  //
+  //   // Start the servers in parallel.
+  //   ASSERT_TRUE(http_server.StartInBackground());
+  //   ASSERT_TRUE(websocket_server.StartInBackground());
+  //   // Wait for both servers to be ready.
+  //   ASSERT_TRUE(http_server.BlockUntilStarted());
+  //   ASSERT_TRUE(websocket_server.BlockUntilStarted());
+  //   RunMyTest();
+  //
+  // Returns true on success.
+  virtual bool StartInBackground() WARN_UNUSED_RESULT = 0;
+
+  // Block until the test server is ready. Returns true on success. See
+  // StartInBackground() documentation for more information.
+  virtual bool BlockUntilStarted() WARN_UNUSED_RESULT = 0;
+
   // Returns the host port pair used by current Python based test server only
   // if the server is started.
   const HostPortPair& host_port_pair() const;
@@ -354,6 +377,8 @@
   virtual ~BaseTestServer();
   Type type() const { return type_; }
 
+  bool started() const { return started_; }
+
   // Gets port currently assigned to host_port_pair_ without checking
   // whether it's available (server started) or not.
   uint16_t GetPort();
diff --git a/net/test/spawned_test_server/local_test_server.cc b/net/test/spawned_test_server/local_test_server.cc
index e1822dd8..da7009f8 100644
--- a/net/test/spawned_test_server/local_test_server.cc
+++ b/net/test/spawned_test_server/local_test_server.cc
@@ -88,11 +88,9 @@
   return true;
 }
 
-bool LocalTestServer::Start() {
-  return StartInBackground() && BlockUntilStarted();
-}
-
 bool LocalTestServer::StartInBackground() {
+  DCHECK(!started());
+
   base::ThreadRestrictions::ScopedAllowIO allow_io_from_test_code;
 
   // Get path to Python server script.
diff --git a/net/test/spawned_test_server/local_test_server.h b/net/test/spawned_test_server/local_test_server.h
index 6d8a3f8..28f54967 100644
--- a/net/test/spawned_test_server/local_test_server.h
+++ b/net/test/spawned_test_server/local_test_server.h
@@ -39,28 +39,9 @@
 
   ~LocalTestServer() override;
 
-  // Start the test server and block until it's ready. Returns true on success.
-  bool Start() WARN_UNUSED_RESULT;
-
-  // Start the test server without blocking. Use this if you need multiple test
-  // servers (such as WebSockets and HTTP, or HTTP and HTTPS). You must call
-  // BlockUntilStarted on all servers your test requires before executing the
-  // test. For example:
-  //
-  //   // Start the servers in parallel.
-  //   ASSERT_TRUE(http_server.StartInBackground());
-  //   ASSERT_TRUE(websocket_server.StartInBackground());
-  //   // Wait for both servers to be ready.
-  //   ASSERT_TRUE(http_server.BlockUntilStarted());
-  //   ASSERT_TRUE(websocket_server.BlockUntilStarted());
-  //   RunMyTest();
-  //
-  // Returns true on success.
-  bool StartInBackground() WARN_UNUSED_RESULT;
-
-  // Block until ths test server is ready. Returns true on success. See
-  // StartInBackground() documentation for more information.
-  bool BlockUntilStarted() WARN_UNUSED_RESULT;
+  // BaseTestServer overrides.
+  bool StartInBackground() override WARN_UNUSED_RESULT;
+  bool BlockUntilStarted() override WARN_UNUSED_RESULT;
 
   // Stop the server started by Start().
   bool Stop();
diff --git a/net/test/spawned_test_server/remote_test_server.cc b/net/test/spawned_test_server/remote_test_server.cc
index 5bf7ed2a..92b55a6 100644
--- a/net/test/spawned_test_server/remote_test_server.cc
+++ b/net/test/spawned_test_server/remote_test_server.cc
@@ -17,19 +17,20 @@
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
+#include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/test/spawned_test_server/remote_test_server_config.h"
 #include "net/test/spawned_test_server/remote_test_server_proxy.h"
-#include "net/test/spawned_test_server/spawner_communicator.h"
+#include "net/test/spawned_test_server/remote_test_server_spawner_request.h"
 #include "url/gurl.h"
 
 namespace net {
 
 namespace {
 
-// Please keep it sync with dictionary SERVER_TYPES in testserver.py
+// Please keep in sync with dictionary SERVER_TYPES in testserver.py
 std::string GetServerTypeString(BaseTestServer::Type type) {
   switch (type) {
     case BaseTestServer::TYPE_FTP:
@@ -72,13 +73,9 @@
   Stop();
 }
 
-bool RemoteTestServer::Start() {
-  if (spawner_communicator_.get())
-    return true;
-
-  RemoteTestServerConfig config = RemoteTestServerConfig::Load();
-
-  spawner_communicator_ = std::make_unique<SpawnerCommunicator>(config);
+bool RemoteTestServer::StartInBackground() {
+  DCHECK(!started());
+  DCHECK(!start_request_);
 
   base::DictionaryValue arguments_dict;
   if (!GenerateArguments(&arguments_dict))
@@ -96,56 +93,62 @@
   if (arguments_string.empty())
     return false;
 
-  // Start the Python test server on the remote machine.
+  start_request_ = std::make_unique<RemoteTestServerSpawnerRequest>(
+      io_thread_.task_runner(), config_.GetSpawnerUrl("start"),
+      arguments_string);
+
+  return true;
+}
+
+bool RemoteTestServer::BlockUntilStarted() {
+  DCHECK(start_request_);
+
   std::string server_data;
-  if (!spawner_communicator_->StartServer(arguments_string, &server_data))
+  bool request_result = start_request_->WaitForCompletion(&server_data);
+  start_request_.reset();
+  if (!request_result)
     return false;
 
   // Parse server_data.
-  int server_port;
   if (server_data.empty() ||
-      !SetAndParseServerData(server_data, &server_port)) {
+      !SetAndParseServerData(server_data, &remote_port_)) {
     LOG(ERROR) << "Could not parse server_data: " << server_data;
     return false;
   }
 
   // If the server is not on localhost then start a proxy on localhost to
   // forward connections to the server.
-  if (config.address() != IPAddress::IPv4Localhost()) {
+  if (config_.address() != IPAddress::IPv4Localhost()) {
     test_server_proxy_ = std::make_unique<RemoteTestServerProxy>(
-        IPEndPoint(config.address(), server_port), io_thread_.task_runner());
+        IPEndPoint(config_.address(), remote_port_), io_thread_.task_runner());
     SetPort(test_server_proxy_->local_port());
   } else {
-    SetPort(server_port);
+    SetPort(remote_port_);
   }
 
   return SetupWhenServerStarted();
 }
 
-bool RemoteTestServer::StartInBackground() {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-bool RemoteTestServer::BlockUntilStarted() {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 bool RemoteTestServer::Stop() {
-  if (!spawner_communicator_)
-    return true;
+  DCHECK(!start_request_);
 
-  uint16_t port = GetPort();
+  if (remote_port_) {
+    std::unique_ptr<RemoteTestServerSpawnerRequest> kill_request =
+        std::make_unique<RemoteTestServerSpawnerRequest>(
+            io_thread_.task_runner(),
+            config_.GetSpawnerUrl(
+                base::StringPrintf("kill?port=%d", remote_port_)),
+            std::string());
+
+    if (!kill_request->WaitForCompletion(nullptr))
+      LOG(ERROR) << "Failed stopping RemoteTestServer";
+
+    remote_port_ = 0;
+  }
+
   CleanUpWhenStoppingServer();
-  bool stopped = spawner_communicator_->StopServer(port);
 
-  if (!stopped)
-    LOG(ERROR) << "Failed stopping RemoteTestServer";
-
-  // Explicitly reset |spawner_communicator_| to avoid reusing the stopped one.
-  spawner_communicator_.reset();
-  return stopped;
+  return true;
 }
 
 // On Android, the document root in the device is not the same as the document
@@ -162,6 +165,8 @@
   if (document_root.IsAbsolute())
     return false;
 
+  config_ = RemoteTestServerConfig::Load();
+
   bool thread_started = io_thread_.StartWithOptions(
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
   CHECK(thread_started);
diff --git a/net/test/spawned_test_server/remote_test_server.h b/net/test/spawned_test_server/remote_test_server.h
index 04dcdb4c..af75d2f 100644
--- a/net/test/spawned_test_server/remote_test_server.h
+++ b/net/test/spawned_test_server/remote_test_server.h
@@ -10,14 +10,47 @@
 #include "base/macros.h"
 #include "base/threading/thread.h"
 #include "net/test/spawned_test_server/base_test_server.h"
+#include "net/test/spawned_test_server/remote_test_server_config.h"
 
 namespace net {
 
-class SpawnerCommunicator;
+class RemoteTestServerSpawnerRequest;
 class RemoteTestServerProxy;
 
 // The RemoteTestServer runs an external Python-based test server in another
-// machine that is different from the machine in which RemoteTestServer runs.
+// machine that is different from the machine that executes the tests. It is
+// necessary because it's not always possible to run the test server on the same
+// machine (it doesn't run on Android and Fuchsia because it's written in
+// Python).
+//
+// The actual test server is executed on the host machine, while the unit tests
+// themselves continue running on the device. To control the test server on the
+// host machine, a second HTTP server is started, the spawner server, which
+// controls the life cycle of remote test servers. Calls to start/kill the
+// SpawnedTestServer are then redirected to the spawner server via
+// this spawner communicator. The spawner is implemented in
+// build/util/lib/common/chrome_test_server_spawner.py .
+//
+// Currently the following two commands are supported by spawner.
+//
+// (1) Start Python test server, format is:
+// Path: "/start".
+// Method: "POST".
+// Data to server: all arguments needed to launch the Python test server, in
+//   JSON format.
+// Data from server: a JSON dict includes the following two field if success,
+//   "port": the port the Python test server actually listen on that.
+//   "message": must be "started".
+//
+// (2) Kill Python test server, format is:
+// Path: "/kill".
+// Method: "GET".
+// Data to server: port=<server_port>.
+// Data from server: String "killed" returned if success.
+//
+// The internal I/O thread is required by net stack to perform net I/O.
+// The Start/StopServer methods block the caller thread until result is
+// fetched from spawner server or timed-out.
 class RemoteTestServer : public BaseTestServer {
  public:
   // Initialize a TestServer. |document_root| must be a relative path under the
@@ -32,14 +65,9 @@
 
   ~RemoteTestServer() override;
 
-  // Starts the Python test server on the host, instead of on the device, and
-  // blocks until the server is ready.
-  bool Start() WARN_UNUSED_RESULT;
-
-  // These are currently unused and unimplemented for RemoteTestServer. See
-  // the same methods in LocalTestServer for more information.
-  bool StartInBackground() WARN_UNUSED_RESULT;
-  bool BlockUntilStarted() WARN_UNUSED_RESULT;
+  // BaseTestServer overrides.
+  bool StartInBackground() override WARN_UNUSED_RESULT;
+  bool BlockUntilStarted() override WARN_UNUSED_RESULT;
 
   // Stops the Python test server that is running on the host machine.
   bool Stop();
@@ -53,13 +81,16 @@
  private:
   bool Init(const base::FilePath& document_root);
 
-  // Thread used to run all IO activity in |test_server_proxy_|.
-  // TODO(sergeyu): Use it for |spawner_communicator_| as well.
+  RemoteTestServerConfig config_;
+
+  // Thread used to run all IO activity in RemoteTestServerSpawnerRequest and
+  // |test_server_proxy_|.
   base::Thread io_thread_;
 
-  // Helper to start and stop instances of the Python test server that runs on
-  // the host machine.
-  std::unique_ptr<SpawnerCommunicator> spawner_communicator_;
+  std::unique_ptr<RemoteTestServerSpawnerRequest> start_request_;
+
+  // Server port. Non-zero when the server is running.
+  int remote_port_ = 0;
 
   std::unique_ptr<RemoteTestServerProxy> test_server_proxy_;
 
diff --git a/net/test/spawned_test_server/remote_test_server_spawner_request.cc b/net/test/spawned_test_server/remote_test_server_spawner_request.cc
new file mode 100644
index 0000000..2202bd30
--- /dev/null
+++ b/net/test/spawned_test_server/remote_test_server_spawner_request.cc
@@ -0,0 +1,227 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/test/spawned_test_server/remote_test_server_spawner_request.h"
+
+#include <utility>
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "build/build_config.h"
+#include "net/base/elements_upload_data_stream.h"
+#include "net/base/io_buffer.h"
+#include "net/base/port_util.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_util.h"
+#include "url/gurl.h"
+
+namespace net {
+
+static const int kBufferSize = 2048;
+
+class RemoteTestServerSpawnerRequest::Core : public URLRequest::Delegate {
+ public:
+  Core();
+  ~Core() override;
+
+  void SendRequest(const GURL& url, const std::string& post_data);
+
+  // Blocks until request is finished. If |response| isn't nullptr then server
+  // response is copied to *response. Returns true if the request was completed
+  // successfully.
+  bool WaitForCompletion(std::string* response) WARN_UNUSED_RESULT;
+
+ private:
+  // URLRequest::Delegate methods.
+  void OnResponseStarted(URLRequest* request, int net_error) override;
+  void OnReadCompleted(URLRequest* request, int num_bytes) override;
+
+  void ReadResponse();
+  void OnCommandCompleted(int net_error);
+  void OnTimeout();
+
+  // Request results.
+  int result_code_ = 0;
+  std::string data_received_;
+
+  // WaitableEvent to notify when the request is finished.
+  base::WaitableEvent event_;
+
+  std::unique_ptr<URLRequestContext> context_;
+  std::unique_ptr<URLRequest> request_;
+
+  scoped_refptr<IOBuffer> read_buffer_;
+
+  std::unique_ptr<base::OneShotTimer> timeout_timer_;
+
+  THREAD_CHECKER(thread_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(Core);
+};
+
+RemoteTestServerSpawnerRequest::Core::Core()
+    : event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+             base::WaitableEvent::InitialState::NOT_SIGNALED),
+      read_buffer_(new IOBuffer(kBufferSize)) {
+  DETACH_FROM_THREAD(thread_checker_);
+}
+
+void RemoteTestServerSpawnerRequest::Core::SendRequest(
+    const GURL& url,
+    const std::string& post_data) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  // Prepare the URLRequest for sending the command.
+  DCHECK(!request_.get());
+  context_.reset(new TestURLRequestContext);
+  request_ = context_->CreateRequest(url, DEFAULT_PRIORITY, this);
+
+  if (post_data.empty()) {
+    request_->set_method("GET");
+  } else {
+    request_->set_method("POST");
+    std::unique_ptr<UploadElementReader> reader(
+        UploadOwnedBytesElementReader::CreateWithString(post_data));
+    request_->set_upload(
+        ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
+    request_->SetExtraRequestHeaderByName(HttpRequestHeaders::kContentType,
+                                          "application/json",
+                                          /*override=*/true);
+  }
+
+  timeout_timer_ = std::make_unique<base::OneShotTimer>();
+  timeout_timer_->Start(FROM_HERE, TestTimeouts::action_max_timeout(),
+                        base::Bind(&Core::OnTimeout, base::Unretained(this)));
+
+  request_->Start();
+}
+
+RemoteTestServerSpawnerRequest::Core::~Core() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
+
+bool RemoteTestServerSpawnerRequest::Core::WaitForCompletion(
+    std::string* response) {
+  // Called by RemoteTestServerSpawnerRequest::WaitForCompletion() on the main
+  // thread.
+
+  event_.Wait();
+  if (response)
+    *response = data_received_;
+  return result_code_ == OK;
+}
+
+void RemoteTestServerSpawnerRequest::Core::OnTimeout() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  int result = request_->CancelWithError(ERR_TIMED_OUT);
+  OnCommandCompleted(result);
+}
+
+void RemoteTestServerSpawnerRequest::Core::OnCommandCompleted(int net_error) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_NE(ERR_IO_PENDING, net_error);
+  DCHECK(!event_.IsSignaled());
+
+  // If request has failed, return the error code.
+  if (net_error != OK) {
+    LOG(ERROR) << "request failed, error: " << ErrorToString(net_error);
+    result_code_ = net_error;
+  } else if (request_->GetResponseCode() != 200) {
+    LOG(ERROR) << "Spawner server returned bad status: "
+               << request_->response_headers()->GetStatusLine() << ", "
+               << data_received_;
+    result_code_ = ERR_FAILED;
+  }
+
+  if (result_code_ != OK)
+    data_received_.clear();
+
+  request_.reset();
+  context_.reset();
+  timeout_timer_.reset();
+
+  event_.Signal();
+}
+
+void RemoteTestServerSpawnerRequest::Core::ReadResponse() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  while (true) {
+    int result = request_->Read(read_buffer_.get(), kBufferSize);
+    if (result == ERR_IO_PENDING)
+      return;
+
+    if (result <= 0) {
+      OnCommandCompleted(result);
+      return;
+    }
+
+    data_received_.append(read_buffer_->data(), result);
+  }
+}
+
+void RemoteTestServerSpawnerRequest::Core::OnResponseStarted(
+    URLRequest* request,
+    int net_error) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_NE(ERR_IO_PENDING, net_error);
+  DCHECK_EQ(request, request_.get());
+
+  if (net_error != OK) {
+    OnCommandCompleted(net_error);
+    return;
+  }
+
+  ReadResponse();
+}
+
+void RemoteTestServerSpawnerRequest::Core::OnReadCompleted(URLRequest* request,
+                                                           int read_result) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_NE(ERR_IO_PENDING, read_result);
+  DCHECK_EQ(request, request_.get());
+
+  if (read_result <= 0) {
+    OnCommandCompleted(read_result);
+    return;
+  }
+
+  data_received_.append(read_buffer_->data(), read_result);
+
+  ReadResponse();
+}
+
+RemoteTestServerSpawnerRequest::RemoteTestServerSpawnerRequest(
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    const GURL& url,
+    const std::string& post_data)
+    : io_task_runner_(io_task_runner),
+      core_(new Core()),
+      allowed_port_(new ScopedPortException(url.EffectiveIntPort())) {
+  io_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&Core::SendRequest,
+                                base::Unretained(core_.get()), url, post_data));
+}
+
+RemoteTestServerSpawnerRequest::~RemoteTestServerSpawnerRequest() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  io_task_runner_->DeleteSoon(FROM_HERE, core_.release());
+}
+
+bool RemoteTestServerSpawnerRequest::WaitForCompletion(std::string* response) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  return core_->WaitForCompletion(response);
+}
+
+}  // namespace net
diff --git a/net/test/spawned_test_server/remote_test_server_spawner_request.h b/net/test/spawned_test_server/remote_test_server_spawner_request.h
new file mode 100644
index 0000000..7abc4f5
--- /dev/null
+++ b/net/test/spawned_test_server/remote_test_server_spawner_request.h
@@ -0,0 +1,64 @@
+// 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 NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_SPAWNER_REQUEST_H_
+#define NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_SPAWNER_REQUEST_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+
+class GURL;
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace net {
+
+class ScopedPortException;
+
+// RemoteTestServerSpawnerRequest is used by RemoteTestServer to send a request
+// to the test server spawner.
+class RemoteTestServerSpawnerRequest {
+ public:
+  // Queries the specified URL. If |post_data| is empty then a GET request is
+  // sent. Otherwise |post_data| must be a json blob which is sent as a POST
+  // request body.
+  RemoteTestServerSpawnerRequest(
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+      const GURL& url,
+      const std::string& post_data);
+  ~RemoteTestServerSpawnerRequest();
+
+  // Blocks until request is finished. If |response| isn't nullptr then server
+  // response is copied to *response. Returns true if the request was completed
+  // successfully.
+  bool WaitForCompletion(std::string* response) WARN_UNUSED_RESULT;
+
+ private:
+  class Core;
+
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+  // Core runs on |io_task_runner_|. It's responsible for sending the request
+  // and reading the response.
+  std::unique_ptr<Core> core_;
+
+  // Helper to add spawner port to the list of the globally explicitly allowed
+  // ports. It needs to be here instead of in Core because ScopedPortException
+  // is not thread-safe.
+  std::unique_ptr<ScopedPortException> allowed_port_;
+
+  THREAD_CHECKER(thread_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteTestServerSpawnerRequest);
+};
+
+}  // namespace net
+
+#endif  // NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_SPAWNER_REQUEST_H_
diff --git a/net/test/spawned_test_server/spawner_communicator.cc b/net/test/spawned_test_server/spawner_communicator.cc
deleted file mode 100644
index 8968045..0000000
--- a/net/test/spawned_test_server/spawner_communicator.cc
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/test/spawned_test_server/spawner_communicator.h"
-
-#include <inttypes.h>
-
-#include <limits>
-#include <utility>
-
-#include "base/json/json_reader.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/stringprintf.h"
-#include "base/supports_user_data.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "net/base/elements_upload_data_stream.h"
-#include "net/base/port_util.h"
-#include "net/base/request_priority.h"
-#include "net/base/upload_bytes_element_reader.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/url_request_test_util.h"
-#include "url/gurl.h"
-
-namespace net {
-
-namespace {
-
-int kBufferSize = 2048;
-
-// A class to hold all data needed to send a command to spawner server.
-class SpawnerRequestData : public base::SupportsUserData::Data {
- public:
-  SpawnerRequestData(int* result_code, std::string* data_received)
-      : buf_(new IOBuffer(kBufferSize)),
-        result_code_(result_code),
-        data_received_(data_received) {
-    DCHECK(result_code);
-    *result_code_ = OK;
-    DCHECK(data_received);
-    data_received_->clear();
-  }
-
-  ~SpawnerRequestData() override {}
-
-  IOBuffer* buf() const { return buf_.get(); }
-
-  bool IsResultOK() const { return *result_code_ == OK; }
-
-  const std::string& data_received() const { return *data_received_; }
-  void ClearReceivedData() { data_received_->clear(); }
-
-  void SetResultCode(int result_code) { *result_code_ = result_code; }
-
-  void IncreaseResponseStartedCount() { response_started_count_++; }
-
-  int response_started_count() const { return response_started_count_; }
-
-  // Write data read from URLRequest::Read() to |data_received_|. Returns true
-  // if |num_bytes| is great than 0. |num_bytes| is 0 for EOF, < 0 on errors.
-  bool ConsumeBytesRead(int num_bytes) {
-    // Error while reading, or EOF.
-    if (num_bytes <= 0)
-      return false;
-
-    data_received_->append(buf_->data(), num_bytes);
-    return true;
-  }
-
- private:
-  // Buffer that URLRequest writes into.
-  scoped_refptr<IOBuffer> buf_;
-
-  // Holds the error condition that was hit on the current request, or OK.
-  int* result_code_;
-
-  // Data received from server;
-  std::string* data_received_;
-
-  // Used to track how many times the OnResponseStarted get called after
-  // sending a command to spawner server.
-  int response_started_count_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(SpawnerRequestData);
-};
-
-}  // namespace
-
-SpawnerCommunicator::SpawnerCommunicator(const RemoteTestServerConfig& config)
-    : config_(config),
-      io_thread_("spawner_communicator"),
-      event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-             base::WaitableEvent::InitialState::NOT_SIGNALED) {}
-
-SpawnerCommunicator::~SpawnerCommunicator() {
-  DCHECK(!io_thread_.IsRunning());
-}
-
-void SpawnerCommunicator::WaitForResponse() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  event_.Wait();
-  event_.Reset();
-}
-
-void SpawnerCommunicator::StartIOThread() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (io_thread_.IsRunning())
-    return;
-
-  bool thread_started = io_thread_.StartWithOptions(
-      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
-  DCHECK(thread_started);
-}
-
-void SpawnerCommunicator::Shutdown() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(io_thread_.IsRunning());
-  // The request and its context should be created and destroyed only on the
-  // IO thread.
-  DCHECK(!cur_request_.get());
-  DCHECK(!context_.get());
-  io_thread_.Stop();
-  allowed_port_.reset();
-}
-
-int SpawnerCommunicator::SendCommandAndWaitForResult(
-    const std::string& command,
-    const std::string& post_data,
-    std::string* data_received) {
-  DCHECK(data_received);
-
-  // Start the communicator thread to talk to test server spawner.
-  StartIOThread();
-  DCHECK(io_thread_.message_loop());
-
-  // Since the method will be blocked until SpawnerCommunicator gets result
-  // from the spawner server or timed-out. It's safe to use base::Unretained
-  // when using base::Bind.
-  int result_code;
-  io_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread,
-                 base::Unretained(this), command, post_data, &result_code,
-                 data_received));
-  WaitForResponse();
-
-  return result_code;
-}
-
-void SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread(
-    const std::string& command,
-    const std::string& post_data,
-    int* result_code,
-    std::string* data_received) {
-  DCHECK(io_thread_.task_runner()->BelongsToCurrentThread());
-
-  // Prepare the URLRequest for sending the command.
-  DCHECK(!cur_request_.get());
-  context_.reset(new TestURLRequestContext);
-  GURL url = config_.GetSpawnerUrl(command);
-  allowed_port_ = std::make_unique<ScopedPortException>(url.EffectiveIntPort());
-  cur_request_ = context_->CreateRequest(url, DEFAULT_PRIORITY, this);
-
-  DCHECK(cur_request_);
-  cur_request_->SetUserData(
-      this, std::make_unique<SpawnerRequestData>(result_code, data_received));
-
-  if (post_data.empty()) {
-    cur_request_->set_method("GET");
-  } else {
-    cur_request_->set_method("POST");
-    std::unique_ptr<UploadElementReader> reader(
-        UploadOwnedBytesElementReader::CreateWithString(post_data));
-    cur_request_->set_upload(
-        ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
-    HttpRequestHeaders headers;
-    headers.SetHeader(HttpRequestHeaders::kContentType,
-                      "application/json");
-    cur_request_->SetExtraRequestHeaders(headers);
-  }
-
-  timeout_timer_ = std::make_unique<base::OneShotTimer>();
-  timeout_timer_->Start(
-      FROM_HERE, TestTimeouts::action_max_timeout(),
-      base::Bind(&SpawnerCommunicator::OnTimeout, base::Unretained(this)));
-
-  // Start the request.
-  cur_request_->Start();
-}
-
-void SpawnerCommunicator::OnTimeout() {
-  DCHECK(io_thread_.task_runner()->BelongsToCurrentThread());
-
-  SpawnerRequestData* data =
-      static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
-  DCHECK(data);
-
-  // Set the result code and cancel the timed-out task.
-  int result = cur_request_->CancelWithError(ERR_TIMED_OUT);
-  OnSpawnerCommandCompleted(cur_request_.get(), result);
-}
-
-void SpawnerCommunicator::OnSpawnerCommandCompleted(URLRequest* request,
-                                                    int net_error) {
-  DCHECK(io_thread_.task_runner()->BelongsToCurrentThread());
-  DCHECK_NE(ERR_IO_PENDING, net_error);
-
-  if (!cur_request_.get())
-    return;
-  DCHECK_EQ(request, cur_request_.get());
-  SpawnerRequestData* data =
-      static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
-  DCHECK(data);
-
-  // If request has failed, return the error code.
-  if (net_error != OK) {
-    LOG(ERROR) << "request failed, error: " << ErrorToString(net_error);
-    data->SetResultCode(net_error);
-  } else if (request->GetResponseCode() != 200) {
-    LOG(ERROR) << "Spawner server returned bad status: "
-               << request->response_headers()->GetStatusLine() << ", "
-               << data->data_received();
-    data->SetResultCode(ERR_FAILED);
-  } else {
-    DCHECK_EQ(1, data->response_started_count());
-  }
-
-  if (!data->IsResultOK()) {
-    // Clear the buffer of received data if any net error happened.
-    data->ClearReceivedData();
-  }
-
-  // Clear current request to indicate the completion of sending a command
-  // to spawner server and getting the result.
-  cur_request_.reset();
-  context_.reset();
-  timeout_timer_.reset();
-
-  // Wakeup the caller in user thread.
-  event_.Signal();
-}
-
-void SpawnerCommunicator::ReadResult(URLRequest* request) {
-  DCHECK(io_thread_.task_runner()->BelongsToCurrentThread());
-  DCHECK_EQ(request, cur_request_.get());
-  SpawnerRequestData* data =
-      static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
-  DCHECK(data);
-
-  IOBuffer* buf = data->buf();
-  // Read as many bytes as are available synchronously.
-  while (true) {
-    int rv = request->Read(buf, kBufferSize);
-    if (rv == ERR_IO_PENDING)
-      return;
-
-    if (rv < 0) {
-      OnSpawnerCommandCompleted(request, rv);
-      return;
-    }
-
-    if (!data->ConsumeBytesRead(rv)) {
-      OnSpawnerCommandCompleted(request, rv);
-      return;
-    }
-  }
-}
-
-void SpawnerCommunicator::OnResponseStarted(URLRequest* request,
-                                            int net_error) {
-  DCHECK(io_thread_.task_runner()->BelongsToCurrentThread());
-  DCHECK_EQ(request, cur_request_.get());
-  DCHECK_NE(ERR_IO_PENDING, net_error);
-
-  SpawnerRequestData* data =
-      static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
-  DCHECK(data);
-
-  data->IncreaseResponseStartedCount();
-
-  if (net_error != OK) {
-    OnSpawnerCommandCompleted(request, net_error);
-    return;
-  }
-
-  ReadResult(request);
-}
-
-void SpawnerCommunicator::OnReadCompleted(URLRequest* request, int num_bytes) {
-  DCHECK(io_thread_.task_runner()->BelongsToCurrentThread());
-  DCHECK_NE(ERR_IO_PENDING, num_bytes);
-
-  if (!cur_request_.get())
-    return;
-  DCHECK_EQ(request, cur_request_.get());
-  SpawnerRequestData* data =
-      static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this));
-  DCHECK(data);
-
-  if (data->ConsumeBytesRead(num_bytes)) {
-    // Keep reading.
-    ReadResult(request);
-  } else {
-    // |bytes_read| < 0
-    int net_error = num_bytes;
-    OnSpawnerCommandCompleted(request, net_error);
-  }
-}
-
-bool SpawnerCommunicator::StartServer(const std::string& arguments,
-                                      std::string* server_data) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // Send the start command to spawner server to start the Python test server
-  // on remote machine.
-  int result = SendCommandAndWaitForResult("start", arguments, server_data);
-  return result == OK;
-}
-
-bool SpawnerCommunicator::StopServer(uint16_t port) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // It's OK to stop the SpawnerCommunicator without starting it. Some tests
-  // have test server on their test fixture but do not actually use it.
-  if (!io_thread_.IsRunning())
-    return true;
-
-  // When the test is done, ask the test server spawner to kill the test server
-  // on the remote machine.
-  std::string server_return_data;
-  std::string command = base::StringPrintf("kill?port=%" PRIu16, port);
-  int result =
-      SendCommandAndWaitForResult(command, std::string(), &server_return_data);
-  Shutdown();
-  if (result != OK || server_return_data != "killed")
-    return false;
-  return true;
-}
-
-}  // namespace net
diff --git a/net/test/spawned_test_server/spawner_communicator.h b/net/test/spawned_test_server/spawner_communicator.h
deleted file mode 100644
index 958cc79..0000000
--- a/net/test/spawned_test_server/spawner_communicator.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
-#define NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_checker.h"
-#include "net/test/spawned_test_server/remote_test_server_config.h"
-#include "net/url_request/url_request.h"
-
-namespace base {
-class OneShotTimer;
-}  // namespace base
-
-namespace net {
-
-class ScopedPortException;
-
-// SpawnerCommunicator communicates with a spawner server that runs on a
-// remote system.
-//
-// The test server used by unit tests is written in Python. However, Android
-// does not support running Python code, so the test server cannot run on the
-// same device running unit tests.
-//
-// The actual test server is executed on the host machine, while the unit tests
-// themselves continue running on the device. To control the test server on the
-// host machine, a second HTTP server is started, the spawner server, which
-// controls the life cycle of remote test servers. Calls to start/kill the
-// SpawnedTestServer are then redirected to the spawner server via
-// this spawner communicator.
-//
-// Currently only three commands are supported by spawner.
-//
-// (1) Start Python test server, format is:
-// Path: "/start".
-// Method: "POST".
-// Data to server: all arguments needed to launch the Python test server, in
-//   JSON format.
-// Data from server: a JSON dict includes the following two field if success,
-//   "port": the port the Python test server actually listen on that.
-//   "message": must be "started".
-//
-// (2) Kill Python test server, format is:
-// Path: "/kill".
-// Method: "GET".
-// Data to server: port=<server_port>.
-// Data from server: String "killed" returned if success.
-//
-// (3) Ping Python test server to see whether it is alive, format is:
-// Path: "/ping".
-// Method: "GET".
-// Data to server: None.
-// Data from server: String "ready" returned if success.
-//
-// The internal I/O thread is required by net stack to perform net I/O.
-// The Start/StopServer methods block the caller thread until result is
-// fetched from spawner server or timed-out.
-class SpawnerCommunicator : public URLRequest::Delegate {
- public:
-  explicit SpawnerCommunicator(const RemoteTestServerConfig& config);
-  ~SpawnerCommunicator() override;
-
-  // Starts an instance of the Python test server on the host/ machine.If
-  // successfully started, returns true, setting |*server_data| to the server
-  // data returned by the spawner.
-  bool StartServer(const std::string& arguments,
-                   std::string* server_data) WARN_UNUSED_RESULT;
-  bool StopServer(uint16_t port) WARN_UNUSED_RESULT;
-
- private:
-  // Starts the IO thread. Called on the user thread.
-  void StartIOThread();
-
-  // Shuts down the remote test server spawner. Called on the user thread.
-  void Shutdown();
-
-  // Waits for the server response on IO thread. Called on the user thread.
-  void WaitForResponse();
-
-  // Sends a command to the test server over HTTP, returning response data in
-  // |*data_received|, which must not be nullptr. If |post_data| is empty, HTTP
-  // GET will be used to send |command|. If |post_data| is non-empty, performs
-  // an HTTP POST. This method is called on the user thread.
-  int SendCommandAndWaitForResult(const std::string& command,
-                                  const std::string& post_data,
-                                  std::string* data_received);
-
-  // Performs the command sending on the IO thread. Called on the IO thread.
-  void SendCommandAndWaitForResultOnIOThread(const std::string& command,
-                                             const std::string& post_data,
-                                             int* result_code,
-                                             std::string* data_received);
-
-  // URLRequest::Delegate methods. Called on the IO thread.
-  void OnResponseStarted(URLRequest* request, int net_error) override;
-  void OnReadCompleted(URLRequest* request, int num_bytes) override;
-
-  // Reads Result from the response. Called on the IO thread.
-  void ReadResult(URLRequest* request);
-
-  // Called on the IO thread upon completion of the spawner command.
-  void OnSpawnerCommandCompleted(URLRequest* request, int net_error);
-
-  // Timeout timer task. Runs on IO thread.
-  void OnTimeout();
-
-  const RemoteTestServerConfig config_;
-
-  // A thread to communicate with test_spawner server.
-  base::Thread io_thread_;
-
-  // WaitableEvent to notify whether the communication is done.
-  base::WaitableEvent event_;
-
-  // Helper to add spawner port to the list of the globally explicitly allowed
-  // ports.
-  std::unique_ptr<ScopedPortException> allowed_port_;
-
-  // Request context used by |cur_request_|.
-  std::unique_ptr<URLRequestContext> context_;
-
-  // The current (in progress) request, or NULL.
-  std::unique_ptr<URLRequest> cur_request_;
-
-  std::unique_ptr<base::OneShotTimer> timeout_timer_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(SpawnerCommunicator);
-};
-
-}  // namespace net
-
-#endif  // NET_TEST_SPAWNED_TEST_SERVER_SPAWNER_COMMUNICATOR_H_
diff --git a/net/tools/cachetool/cachetool.cc b/net/tools/cachetool/cachetool.cc
index 4c3b7c1..0b84790d 100644
--- a/net/tools/cachetool/cachetool.cc
+++ b/net/tools/cachetool/cachetool.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
+#include "base/task_scheduler/task_scheduler.h"
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
 #include "net/disk_cache/disk_cache.h"
@@ -647,6 +648,8 @@
     return 1;
   }
 
+  base::TaskScheduler::CreateAndStartWithDefaultParams("cachetool");
+
   base::FilePath cache_path(args[0]);
   std::string cache_backend_type(args[1]);
 
@@ -663,9 +666,9 @@
 
   std::unique_ptr<Backend> cache_backend;
   net::TestCompletionCallback cb;
-  int rv = disk_cache::CreateCacheBackend(
-      net::DISK_CACHE, backend_type, cache_path, INT_MAX, false,
-      message_loop.task_runner(), nullptr, &cache_backend, cb.callback());
+  int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE, backend_type,
+                                          cache_path, INT_MAX, false, nullptr,
+                                          &cache_backend, cb.callback());
   if (cb.GetResult(rv) != net::OK) {
     std::cerr << "Invalid cache." << std::endl;
     return 1;
@@ -678,6 +681,7 @@
 
   base::RunLoop().RunUntilIdle();
   cache_backend = nullptr;
+  disk_cache::FlushCacheThreadForTesting();
   base::RunLoop().RunUntilIdle();
   return !successful_commands;
 }
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 185566be..4d3ee9b 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -341,28 +341,28 @@
   }
 
   void set_client_initial_stream_flow_control_receive_window(uint32_t window) {
-    CHECK(client_.get() == nullptr);
+    CHECK(client_ == nullptr);
     QUIC_DLOG(INFO) << "Setting client initial stream flow control window: "
                     << window;
     client_config_.SetInitialStreamFlowControlWindowToSend(window);
   }
 
   void set_client_initial_session_flow_control_receive_window(uint32_t window) {
-    CHECK(client_.get() == nullptr);
+    CHECK(client_ == nullptr);
     QUIC_DLOG(INFO) << "Setting client initial session flow control window: "
                     << window;
     client_config_.SetInitialSessionFlowControlWindowToSend(window);
   }
 
   void set_server_initial_stream_flow_control_receive_window(uint32_t window) {
-    CHECK(server_thread_.get() == nullptr);
+    CHECK(server_thread_ == nullptr);
     QUIC_DLOG(INFO) << "Setting server initial stream flow control window: "
                     << window;
     server_config_.SetInitialStreamFlowControlWindowToSend(window);
   }
 
   void set_server_initial_session_flow_control_receive_window(uint32_t window) {
-    CHECK(server_thread_.get() == nullptr);
+    CHECK(server_thread_ == nullptr);
     QUIC_DLOG(INFO) << "Setting server initial session flow control window: "
                     << window;
     server_config_.SetInitialSessionFlowControlWindowToSend(window);
@@ -479,7 +479,7 @@
   void StopServer() {
     if (!server_started_)
       return;
-    if (server_thread_.get()) {
+    if (server_thread_) {
       server_thread_->Quit();
       server_thread_->Join();
     }
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 73a09ba..7c3435e4 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -512,6 +512,10 @@
   accept_new_connections_ = false;
 }
 
+bool QuicDispatcher::ShouldAddToBlockedList() {
+  return writer_->IsWriteBlocked();
+}
+
 void QuicDispatcher::DeleteSessions() {
   closed_session_list_.clear();
 }
@@ -526,7 +530,7 @@
     QuicBlockedWriterInterface* blocked_writer =
         write_blocked_list_.begin()->first;
     write_blocked_list_.erase(write_blocked_list_.begin());
-    blocked_writer->OnCanWrite();
+    blocked_writer->OnBlockedWriterCanWrite();
   }
 }
 
@@ -577,9 +581,9 @@
 
 void QuicDispatcher::OnWriteBlocked(
     QuicBlockedWriterInterface* blocked_writer) {
-  if (!writer_->IsWriteBlocked()) {
-    QUIC_BUG << "QuicDispatcher::OnWriteBlocked called when the writer is "
-                "not blocked.";
+  if (!ShouldAddToBlockedList()) {
+    QUIC_BUG
+        << "Tried to add writer into blocked list when it shouldn't be added";
     // Return without adding the connection to the blocked list, to avoid
     // infinite loops in OnCanWrite.
     return;
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 59779cd..52905bc 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -38,7 +38,6 @@
 
 class QuicDispatcher : public QuicTimeWaitListManager::Visitor,
                        public ProcessPacketInterface,
-                       public QuicBlockedWriterInterface,
                        public QuicFramerVisitorInterface,
                        public QuicBufferedPacketStore::VisitorInterface {
  public:
@@ -64,7 +63,7 @@
                      const QuicReceivedPacket& packet) override;
 
   // Called when the socket becomes writable to allow queued writes to happen.
-  void OnCanWrite() override;
+  virtual void OnCanWrite();
 
   // Returns true if there's anything in the blocked writer list.
   virtual bool HasPendingWrites() const;
@@ -287,6 +286,9 @@
 
   void StopAcceptingNewConnections();
 
+  // Return true if the blocked writer should be added to blocked list.
+  virtual bool ShouldAddToBlockedList();
+
  private:
   friend class test::QuicDispatcherPeer;
   friend class StatelessRejectorProcessDoneCallback;
diff --git a/net/tools/quic/quic_simple_server_packet_writer.cc b/net/tools/quic/quic_simple_server_packet_writer.cc
index 6386cd7..575ceca 100644
--- a/net/tools/quic/quic_simple_server_packet_writer.cc
+++ b/net/tools/quic/quic_simple_server_packet_writer.cc
@@ -11,14 +11,15 @@
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/socket/udp_server_socket.h"
+#include "net/tools/quic/quic_dispatcher.h"
 
 namespace net {
 
 QuicSimpleServerPacketWriter::QuicSimpleServerPacketWriter(
     UDPServerSocket* socket,
-    QuicBlockedWriterInterface* blocked_writer)
+    QuicDispatcher* dispatcher)
     : socket_(socket),
-      blocked_writer_(blocked_writer),
+      dispatcher_(dispatcher),
       write_blocked_(false),
       weak_factory_(this) {}
 
@@ -48,7 +49,7 @@
   if (!callback_.is_null()) {
     base::ResetAndReturn(&callback_).Run(result);
   }
-  blocked_writer_->OnCanWrite();
+  dispatcher_->OnCanWrite();
 }
 
 bool QuicSimpleServerPacketWriter::IsWriteBlockedDataBuffered() const {
diff --git a/net/tools/quic/quic_simple_server_packet_writer.h b/net/tools/quic/quic_simple_server_packet_writer.h
index a08c0da..b3bf6db 100644
--- a/net/tools/quic/quic_simple_server_packet_writer.h
+++ b/net/tools/quic/quic_simple_server_packet_writer.h
@@ -16,7 +16,7 @@
 
 namespace net {
 
-class QuicBlockedWriterInterface;
+class QuicDispatcher;
 class UDPServerSocket;
 struct WriteResult;
 
@@ -28,7 +28,7 @@
   typedef base::Callback<void(WriteResult)> WriteCallback;
 
   QuicSimpleServerPacketWriter(UDPServerSocket* socket,
-                               QuicBlockedWriterInterface* blocked_writer);
+                               QuicDispatcher* dispatcher);
   ~QuicSimpleServerPacketWriter() override;
 
   // Wraps WritePacket, and ensures that |callback| is run on successful write.
@@ -58,7 +58,7 @@
   UDPServerSocket* socket_;
 
   // To be notified after every successful asynchronous write.
-  QuicBlockedWriterInterface* blocked_writer_;
+  QuicDispatcher* dispatcher_;
 
   // To call once the write completes.
   WriteCallback callback_;
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 04ce85b..beedf3a 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -134,7 +134,7 @@
   return (it->second).version;
 }
 
-void QuicTimeWaitListManager::OnCanWrite() {
+void QuicTimeWaitListManager::OnBlockedWriterCanWrite() {
   while (!pending_packets_queue_.empty()) {
     QueuedPacket* queued_packet = pending_packets_queue_.front().get();
     if (!WriteToWire(queued_packet)) {
diff --git a/net/tools/quic/quic_time_wait_list_manager.h b/net/tools/quic/quic_time_wait_list_manager.h
index f2eb505..495d55c 100644
--- a/net/tools/quic/quic_time_wait_list_manager.h
+++ b/net/tools/quic/quic_time_wait_list_manager.h
@@ -90,7 +90,7 @@
   // Called by the dispatcher when the underlying socket becomes writable again,
   // since we might need to send pending public reset packets which we didn't
   // send because the underlying socket was write blocked.
-  void OnCanWrite() override;
+  void OnBlockedWriterCanWrite() override;
 
   // Used to delete connection_id entries that have outlived their time wait
   // period.
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index c9e7a8e..34e70874 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -378,7 +378,7 @@
               WritePacket(_, _, server_address_.host(), client_address_, _))
       .With(Args<0, 1>(PublicResetPacketEq(other_connection_id)))
       .WillOnce(Return(WriteResult(WRITE_STATUS_OK, other_packet->length())));
-  time_wait_list_manager_.OnCanWrite();
+  time_wait_list_manager_.OnBlockedWriterCanWrite();
 }
 
 TEST_F(QuicTimeWaitListManagerTest, GetQuicVersionFromMap) {
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 2fa3f9e..fa81d1f 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -397,14 +397,6 @@
                                     bool fin) {
   // Always force creation of a stream for SendMessage.
   latest_created_stream_ = nullptr;
-  // If we're not connected, try to find an sni hostname.
-  if (!connected()) {
-    QuicUrl url(SpdyUtils::GetUrlFromHeaderBlock(headers));
-    if (override_sni_set_) {
-      client_->set_server_id(
-          QuicServerId(override_sni_, url.port(), PRIVACY_MODE_DISABLED));
-    }
-  }
 
   ssize_t ret = GetOrCreateStreamAndSendRequest(&headers, body, fin, nullptr);
   WaitForWriteToFlush();
@@ -536,6 +528,13 @@
   if (!connect_attempted_) {
     client_->Initialize();
   }
+
+  // If we've been asked to override SNI, set it now
+  if (override_sni_set_) {
+    client_->set_server_id(
+        QuicServerId(override_sni_, address().port(), PRIVACY_MODE_DISABLED));
+  }
+
   client_->Connect();
   connect_attempted_ = true;
 }
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index edfeadf29..f420ac9 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -2343,14 +2343,16 @@
   if (text_length <= 0)
     return;
 
+  // Adding +1 to text_length to account for the string terminator that is
+  // included.
   base::string16 page_text;
   PDFiumAPIStringBufferAdapter<base::string16> api_string_adapter(
-      &page_text, text_length, false);
+      &page_text, text_length + 1, false);
   unsigned short* data =
       reinterpret_cast<unsigned short*>(api_string_adapter.GetData());
-  int written =
-      FPDFText_GetText(pages_[current_page]->GetTextPage(),
-                       character_to_start_searching_from, text_length, data);
+  int written = FPDFText_GetText(pages_[current_page]->GetTextPage(),
+                                 character_to_start_searching_from,
+                                 text_length + 1, data);
   api_string_adapter.Close(written);
 
   std::vector<PDFEngine::Client::SearchStringResult> results;
diff --git a/pdf/pdfium/pdfium_range.cc b/pdf/pdfium/pdfium_range.cc
index 7e30e19..b720404c 100644
--- a/pdf/pdfium/pdfium_range.cc
+++ b/pdf/pdfium/pdfium_range.cc
@@ -67,11 +67,13 @@
   }
 
   if (count > 0) {
-    PDFiumAPIStringBufferAdapter<base::string16> api_string_adapter(&rv, count,
-                                                                    false);
+    // Adding +1 to count to account for the string terminator that is included.
+    PDFiumAPIStringBufferAdapter<base::string16> api_string_adapter(
+        &rv, count + 1, false);
     unsigned short* data =
         reinterpret_cast<unsigned short*>(api_string_adapter.GetData());
-    int written = FPDFText_GetText(page_->GetTextPage(), index, count, data);
+    int written =
+        FPDFText_GetText(page_->GetTextPage(), index, count + 1, data);
     api_string_adapter.Close(written);
   }
 
diff --git a/ppapi/api/private/ppb_platform_verification_private.idl b/ppapi/api/private/ppb_platform_verification_private.idl
index afd41bd..b39d4eb 100644
--- a/ppapi/api/private/ppb_platform_verification_private.idl
+++ b/ppapi/api/private/ppb_platform_verification_private.idl
@@ -87,7 +87,7 @@
    * Requests the device's storage ID.
    *
    * @param[out] storage_id A <code>PP_Var</code> of type
-   * <code>PP_VARTYPE_STRING</code> that contains the storage ID.
+   * <code>PP_VARTYPE_ARRAY_BUFFER</code> that contains the storage ID.
    *
    * @param[in] callback A <code>PP_CompletionCallback</code> to be called after
    * the storage ID has been obtained. This callback will only run if
diff --git a/ppapi/c/private/ppb_platform_verification_private.h b/ppapi/c/private/ppb_platform_verification_private.h
index 83f6860..bd3690b 100644
--- a/ppapi/c/private/ppb_platform_verification_private.h
+++ b/ppapi/c/private/ppb_platform_verification_private.h
@@ -4,7 +4,7 @@
  */
 
 /* From private/ppb_platform_verification_private.idl,
- *   modified Tue Jun 13 15:47:24 2017.
+ *   modified Fri Aug 11 11:47:35 2017.
  */
 
 #ifndef PPAPI_C_PRIVATE_PPB_PLATFORM_VERIFICATION_PRIVATE_H_
@@ -102,7 +102,7 @@
    * Requests the device's storage ID.
    *
    * @param[out] storage_id A <code>PP_Var</code> of type
-   * <code>PP_VARTYPE_STRING</code> that contains the storage ID.
+   * <code>PP_VARTYPE_ARRAY_BUFFER</code> that contains the storage ID.
    *
    * @param[in] callback A <code>PP_CompletionCallback</code> to be called after
    * the storage ID has been obtained. This callback will only run if
diff --git a/ppapi/proxy/platform_verification_private_resource.cc b/ppapi/proxy/platform_verification_private_resource.cc
index d9fbf998..7a54ffdc 100644
--- a/ppapi/proxy/platform_verification_private_resource.cc
+++ b/ppapi/proxy/platform_verification_private_resource.cc
@@ -88,12 +88,14 @@
   if (params.result() == PP_OK) {
     *(output_params.signed_data) =
         (PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferVar(
-            static_cast<uint32_t>(raw_signed_data.size()),
-            &raw_signed_data.front()))->GetPPVar();
+             static_cast<uint32_t>(raw_signed_data.size()),
+             raw_signed_data.data()))
+            ->GetPPVar();
     *(output_params.signed_data_signature) =
         (PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferVar(
-            static_cast<uint32_t>(raw_signed_data_signature.size()),
-            &raw_signed_data_signature.front()))->GetPPVar();
+             static_cast<uint32_t>(raw_signed_data_signature.size()),
+             raw_signed_data_signature.data()))
+            ->GetPPVar();
     *(output_params.platform_key_certificate) =
         (new StringVar(raw_platform_key_certificate))->GetPPVar();
   }
@@ -121,14 +123,17 @@
 void PlatformVerificationPrivateResource::OnGetStorageIdReply(
     GetStorageIdParams output_params,
     const ResourceMessageReplyParams& params,
-    const std::string& storage_id) {
+    const std::vector<uint8_t>& storage_id) {
   if (!TrackedCallback::IsPending(output_params.callback) ||
       TrackedCallback::IsScheduledToRun(output_params.callback)) {
     return;
   }
 
   if (params.result() == PP_OK) {
-    *(output_params.storage_id) = (new StringVar(storage_id))->GetPPVar();
+    *(output_params.storage_id) =
+        (PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferVar(
+             static_cast<uint32_t>(storage_id.size()), storage_id.data()))
+            ->GetPPVar();
   }
   output_params.callback->Run(params.result());
 }
diff --git a/ppapi/proxy/platform_verification_private_resource.h b/ppapi/proxy/platform_verification_private_resource.h
index 031e9ef..87198b63 100644
--- a/ppapi/proxy/platform_verification_private_resource.h
+++ b/ppapi/proxy/platform_verification_private_resource.h
@@ -58,7 +58,7 @@
                        const scoped_refptr<TrackedCallback>& callback) override;
   void OnGetStorageIdReply(GetStorageIdParams output_params,
                            const ResourceMessageReplyParams& params,
-                           const std::string& storage_id);
+                           const std::vector<uint8_t>& storage_id);
 
   DISALLOW_COPY_AND_ASSIGN(PlatformVerificationPrivateResource);
 };
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 4307409..67e61b70e 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -1869,7 +1869,7 @@
                      std::string /* platform_key_certificate */)
 IPC_MESSAGE_CONTROL0(PpapiHostMsg_PlatformVerification_GetStorageId)
 IPC_MESSAGE_CONTROL1(PpapiHostMsg_PlatformVerification_GetStorageIdReply,
-                     std::string /* storage_id */)
+                     std::vector<uint8_t> /* storage_id */)
 
 // Printing.
 IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_Create)
diff --git a/remoting/android/java/src/org/chromium/chromoting/HostInfo.java b/remoting/android/java/src/org/chromium/chromoting/HostInfo.java
index a8ac2cc..795347f8 100644
--- a/remoting/android/java/src/org/chromium/chromoting/HostInfo.java
+++ b/remoting/android/java/src/org/chromium/chromoting/HostInfo.java
@@ -95,6 +95,12 @@
                 return R.string.offline_reason_success_exit;
             case "username_mismatch":
                 return R.string.offline_reason_username_mismatch;
+            case "x_server_retries_exceeded":
+                return R.string.offline_reason_x_server_retries_exceeded;
+            case "session_retries_exceeded":
+                return R.string.offline_reason_session_retries_exceeded;
+            case "host_retries_exceeded":
+                return R.string.offline_reason_host_retries_exceeded;
             default:
                 return R.string.offline_reason_unknown;
         }
diff --git a/remoting/host/linux/linux_me2me_host.py b/remoting/host/linux/linux_me2me_host.py
index 6e7e26a..0ebd91d82 100755
--- a/remoting/host/linux/linux_me2me_host.py
+++ b/remoting/host/linux/linux_me2me_host.py
@@ -119,6 +119,16 @@
 # Number of seconds to save session output to the log.
 SESSION_OUTPUT_TIME_LIMIT_SECONDS = 30
 
+# Host offline reason if the X server retry count is exceeded.
+HOST_OFFLINE_REASON_X_SERVER_RETRIES_EXCEEDED = "X_SERVER_RETRIES_EXCEEDED"
+
+# Host offline reason if the X session retry count is exceeded.
+HOST_OFFLINE_REASON_SESSION_RETRIES_EXCEEDED = "SESSION_RETRIES_EXCEEDED"
+
+# Host offline reason if the host retry count is exceeded. (Note: It may or may
+# not be possible to send this, depending on why the host is failing.)
+HOST_OFFLINE_REASON_HOST_RETRIES_EXCEEDED = "HOST_RETRIES_EXCEEDED"
+
 # This is the file descriptor used to pass messages to the user_session binary
 # during startup. It must be kept in sync with kMessageFd in
 # remoting_user_session.cc.
@@ -510,19 +520,22 @@
       del env_copy["TMPDIR"]
       return env_copy
 
+  def check_x_responding(self):
+    """Checks if the X server is responding to connections."""
+    with open(os.devnull, "r+") as devnull:
+      exit_code = subprocess.call("xdpyinfo", env=self.child_env,
+                                  stdout=devnull)
+    return exit_code == 0
+
   def _wait_for_x(self):
     # Wait for X to be active.
-    with open(os.devnull, "r+") as devnull:
-      for _test in range(20):
-        exit_code = subprocess.call("xdpyinfo", env=self.child_env,
-                                    stdout=devnull)
-        if exit_code == 0:
-          break
-        time.sleep(0.5)
-      if exit_code != 0:
-        raise Exception("Could not connect to X server.")
-      else:
+    for _test in range(20):
+      if self.check_x_responding():
         logging.info("X server is active.")
+        return
+      time.sleep(0.5)
+
+    raise Exception("Could not connect to X server.")
 
   def _launch_xvfb(self, display, x_auth_file, extra_x_args):
     max_width = max([width for width, height in self.sizes])
@@ -751,6 +764,41 @@
     finally:
       self.host_proc.stdin.close()
 
+  def shutdown_all_procs(self):
+    """Send SIGTERM to all procs and wait for them to exit. Will fallback to
+    SIGKILL if a process doesn't exit within 10 seconds.
+    """
+    for proc, name in [(self.x_proc, "X server"),
+                       (self.session_proc, "session"),
+                       (self.host_proc, "host")]:
+      if proc is not None:
+        logging.info("Terminating " + name)
+        try:
+          psutil_proc = psutil.Process(proc.pid)
+          psutil_proc.terminate()
+
+          # Use a short timeout, to avoid delaying service shutdown if the
+          # process refuses to die for some reason.
+          psutil_proc.wait(timeout=10)
+        except psutil.TimeoutExpired:
+          logging.error("Timed out - sending SIGKILL")
+          psutil_proc.kill()
+        except psutil.Error:
+          logging.error("Error terminating process")
+    self.x_proc = None
+    self.session_proc = None
+    self.host_proc = None
+
+  def report_offline_reason(self, host_config, reason):
+    """Attempt to report the specified offline reason to the registry. This
+    is best effort, and requires a valid host config.
+    """
+    logging.info("Attempting to report offline reason: " + reason)
+    args = [HOST_BINARY_PATH, "--host-config=-",
+            "--report-offline-reason=" + reason]
+    proc = subprocess.Popen(args, env=self.child_env, stdin=subprocess.PIPE)
+    proc.communicate(json.dumps(host_config.data).encode('UTF-8'))
+
 
 def parse_config_arg(args):
   """Parses only the --config option from a given command-line.
@@ -1105,23 +1153,7 @@
 
   global g_desktop
   if g_desktop is not None:
-    for proc, name in [(g_desktop.x_proc, "X server"),
-                       (g_desktop.session_proc, "session"),
-                       (g_desktop.host_proc, "host")]:
-      if proc is not None:
-        logging.info("Terminating " + name)
-        try:
-          psutil_proc = psutil.Process(proc.pid)
-          psutil_proc.terminate()
-
-          # Use a short timeout, to avoid delaying service shutdown if the
-          # process refuses to die for some reason.
-          psutil_proc.wait(timeout=10)
-        except psutil.TimeoutExpired:
-          logging.error("Timed out - sending SIGKILL")
-          psutil_proc.kill()
-        except psutil.Error:
-          logging.error("Error terminating process")
+    g_desktop.shutdown_all_procs()
     if g_desktop.xorg_conf is not None:
       os.remove(g_desktop.xorg_conf)
 
@@ -1186,14 +1218,16 @@
     self.earliest_successful_termination = time.time() + minimum_lifetime
     self.running = True
 
-  def record_stopped(self):
+  def record_stopped(self, expected):
     """Record that the process was stopped, and adjust the failure count
-    depending on whether the process ran long enough."""
+    depending on whether the process ran long enough. If the process was
+    intentionally stopped (expected is True), the failure count will not be
+    incremented."""
     self.running = False
-    if time.time() < self.earliest_successful_termination:
-      self.failures += 1
-    else:
+    if time.time() >= self.earliest_successful_termination:
       self.failures = 0
+    elif not expected:
+      self.failures += 1
     logging.info("Failure count for '%s' is now %d", self.label, self.failures)
 
 
@@ -1566,61 +1600,75 @@
   # launched at (roughly) the same time as the X server, and the termination of
   # one of these triggers the termination of the other.
   x_server_inhibitor = RelaunchInhibitor("X server")
+  session_inhibitor = RelaunchInhibitor("session")
   host_inhibitor = RelaunchInhibitor("host")
-  all_inhibitors = [x_server_inhibitor, host_inhibitor]
+  all_inhibitors = [
+      (x_server_inhibitor, HOST_OFFLINE_REASON_X_SERVER_RETRIES_EXCEEDED),
+      (session_inhibitor, HOST_OFFLINE_REASON_SESSION_RETRIES_EXCEEDED),
+      (host_inhibitor, HOST_OFFLINE_REASON_HOST_RETRIES_EXCEEDED)
+  ]
 
-  # Don't allow relaunching the script on the first loop iteration.
-  allow_relaunch_self = False
+  # Whether we are tearing down because the X server and/or session exited.
+  # This keeps us from counting processes exiting because we've terminated them
+  # as errors.
+  tear_down = False
 
   while True:
-    # Set the backoff interval and exit if a process failed too many times.
-    backoff_time = SHORT_BACKOFF_TIME
-    for inhibitor in all_inhibitors:
-      if inhibitor.failures >= MAX_LAUNCH_FAILURES:
-        logging.error("Too many launch failures of '%s', exiting."
-                      % inhibitor.label)
-        return 1
-      elif inhibitor.failures >= SHORT_BACKOFF_THRESHOLD:
-        backoff_time = LONG_BACKOFF_TIME
-
-    relaunch_times = []
-
     # If the session process or X server stops running (e.g. because the user
-    # logged out), kill the other. This will trigger the next conditional block
-    # as soon as os.waitpid() reaps its exit-code.
-    if desktop.session_proc is None and desktop.x_proc is not None:
-      logging.info("Terminating X server")
-      desktop.x_proc.terminate()
-    elif desktop.x_proc is None and desktop.session_proc is not None:
-      logging.info("Terminating X session")
-      desktop.session_proc.terminate()
-    elif desktop.x_proc is None and desktop.session_proc is None:
-      # Both processes have terminated.
-      if (allow_relaunch_self and x_server_inhibitor.failures == 0 and
-          host_inhibitor.failures == 0):
+    # logged out), terminate all processes. The session will be restarted once
+    # everything has exited.
+    if tear_down:
+      desktop.shutdown_all_procs()
+
+      failure_count = 0
+      for inhibitor, _ in all_inhibitors:
+        if inhibitor.running:
+          inhibitor.record_stopped(True)
+        failure_count += inhibitor.failures
+
+      tear_down = False
+
+      if (failure_count == 0):
         # Since the user's desktop is already gone at this point, there's no
         # state to lose and now is a good time to pick up any updates to this
         # script that might have been installed.
         logging.info("Relaunching self")
-        relaunch_self(options.child_process)
+        relaunch_self()
       else:
         # If there is a non-zero |failures| count, restarting the whole script
-        # would lose this information, so just launch the session as normal.
-        if x_server_inhibitor.is_inhibited():
-          logging.info("Waiting before launching X server")
-          relaunch_times.append(x_server_inhibitor.earliest_relaunch_time)
-        else:
-          logging.info("Launching X server and X session.")
-          desktop.launch_session(options.args)
-          x_server_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME,
-                                            backoff_time)
-          allow_relaunch_self = True
+        # would lose this information, so just launch the session as normal,
+        # below.
+        pass
 
-    if desktop.host_proc is None:
-      if host_inhibitor.is_inhibited():
-        logging.info("Waiting before launching host process")
-        relaunch_times.append(host_inhibitor.earliest_relaunch_time)
-      else:
+    relaunch_times = []
+
+    # Set the backoff interval and exit if a process failed too many times.
+    backoff_time = SHORT_BACKOFF_TIME
+    for inhibitor, offline_reason in all_inhibitors:
+      if inhibitor.failures >= MAX_LAUNCH_FAILURES:
+        logging.error("Too many launch failures of '%s', exiting."
+                      % inhibitor.label)
+        desktop.report_offline_reason(host_config, offline_reason)
+        return 1
+      elif inhibitor.failures >= SHORT_BACKOFF_THRESHOLD:
+        backoff_time = LONG_BACKOFF_TIME
+
+      if inhibitor.is_inhibited():
+        relaunch_times.append(inhibitor.earliest_relaunch_time)
+
+    if relaunch_times:
+      # We want to wait until everything is ready to start so we don't end up
+      # launching things in the wrong order due to differing relaunch times.
+      logging.info("Waiting before relaunching")
+    else:
+      if desktop.x_proc is None and desktop.session_proc is None:
+        logging.info("Launching X server and X session.")
+        desktop.launch_session(options.args)
+        x_server_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME,
+                                          backoff_time)
+        session_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME,
+                                         backoff_time)
+      if desktop.host_proc is None:
         logging.info("Launching host process")
 
         extra_start_host_args = []
@@ -1629,10 +1677,9 @@
                 re.split('\s+', os.environ[HOST_EXTRA_PARAMS_ENV_VAR].strip())
         desktop.launch_host(host_config, extra_start_host_args)
 
-        host_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME,
-                                      backoff_time)
+        host_inhibitor.record_started(MINIMUM_PROCESS_LIFETIME, backoff_time)
 
-    deadline = min(relaunch_times) if relaunch_times else 0
+    deadline = max(relaunch_times) if relaunch_times else 0
     pid, status = waitpid_handle_exceptions(-1, deadline)
     if pid == 0:
       continue
@@ -1645,17 +1692,26 @@
     if desktop.x_proc is not None and pid == desktop.x_proc.pid:
       logging.info("X server process terminated")
       desktop.x_proc = None
-      x_server_inhibitor.record_stopped()
+      x_server_inhibitor.record_stopped(False)
+      tear_down = True
 
     if desktop.session_proc is not None and pid == desktop.session_proc.pid:
       logging.info("Session process terminated")
       desktop.session_proc = None
+      # The session may have exited on its own or been brought down by the X
+      # server dying. Check if the X server is still running so we know whom
+      # to penalize.
+      if desktop.check_x_responding():
+        session_inhibitor.record_stopped(False)
+      else:
+        x_server_inhibitor.record_stopped(False)
+      # Either way, we want to tear down the session.
+      tear_down = True
 
     if desktop.host_proc is not None and pid == desktop.host_proc.pid:
       logging.info("Host process terminated")
       desktop.host_proc = None
       desktop.host_ready = False
-      host_inhibitor.record_stopped()
 
       # These exit-codes must match the ones used by the host.
       # See remoting/host/host_error_codes.h.
@@ -1686,6 +1742,16 @@
       elif os.WIFSIGNALED(status):
         logging.info("Host terminated by signal %s." % os.WTERMSIG(status))
 
+      # The host may have exited on it's own or been brought down by the X
+      # server dying. Check if the X server is still running so we know whom to
+      # penalize.
+      if desktop.check_x_responding():
+        host_inhibitor.record_stopped(False)
+      else:
+        x_server_inhibitor.record_stopped(False)
+        # Only tear down if the X server isn't responding.
+        tear_down = True
+
 
 if __name__ == "__main__":
   logging.basicConfig(level=logging.DEBUG,
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index d7666a9..a339376 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -182,6 +182,9 @@
 
 const char kWindowIdSwitchName[] = "window-id";
 
+// Command line switch used to send a custom offline reason and exit.
+const char kReportOfflineReasonSwitchName[] = "report-offline-reason";
+
 // Maximum time to wait for clean shutdown to occur, before forcing termination
 // of the process.
 const int kShutdownTimeoutSeconds = 15;
@@ -440,6 +443,7 @@
 
   int* exit_code_out_;
   bool signal_parent_ = false;
+  std::string report_offline_reason_;
 
   scoped_refptr<PairingRegistry> pairing_registry_;
 
@@ -549,6 +553,16 @@
 
   signal_parent_ = cmd_line->HasSwitch(kSignalParentSwitchName);
 
+  if (cmd_line->HasSwitch(kReportOfflineReasonSwitchName)) {
+    report_offline_reason_ =
+        cmd_line->GetSwitchValueASCII(kReportOfflineReasonSwitchName);
+    if (report_offline_reason_.empty()) {
+      LOG(ERROR) << "--" << kReportOfflineReasonSwitchName
+                 << " requires an argument.";
+      return false;
+    }
+  }
+
   enable_window_capture_ = cmd_line->HasSwitch(kWindowIdSwitchName);
   if (enable_window_capture_) {
 
@@ -821,6 +835,13 @@
     return;
   }
 
+  if (!report_offline_reason_.empty()) {
+    // Don't need to do any UI initialization.
+    context_->network_task_runner()->PostTask(
+        FROM_HERE, base::Bind(&HostProcess::StartOnNetworkThread, this));
+    return;
+  }
+
   policy_watcher_ =
       PolicyWatcher::CreateWithTaskRunner(context_->file_task_runner());
   policy_watcher_->StartWatching(
@@ -907,6 +928,9 @@
 }
 
 void HostProcess::OnHeartbeatSuccessful() {
+  if (state_ != HOST_STARTED) {
+    return;
+  }
   HOST_LOG << "Host ready to receive connections.";
 #if defined(OS_POSIX)
   if (signal_parent_) {
@@ -1445,7 +1469,10 @@
 
   // Start the host if both the config and the policies are loaded.
   if (!serialized_config_.empty()) {
-    if (policy_state_ == POLICY_LOADED) {
+    if (!report_offline_reason_.empty()) {
+      SetState(HOST_GOING_OFFLINE_TO_STOP);
+      GoOffline(report_offline_reason_);
+    } else if (policy_state_ == POLICY_LOADED) {
       StartHost();
     } else if (policy_state_ == POLICY_ERROR_REPORT_PENDING) {
       ReportPolicyErrorAndRestartHost();
@@ -1678,13 +1705,16 @@
   HOST_LOG << "Starting host process: version " << STRINGIZE(VERSION);
 
 #if defined(OS_LINUX)
-  // Required in order for us to run multiple X11 threads.
-  XInitThreads();
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          kReportOfflineReasonSwitchName)) {
+    // Required in order for us to run multiple X11 threads.
+    XInitThreads();
 
-  // Required for any calls into GTK functions, such as the Disconnect and
-  // Continue windows, though these should not be used for the Me2Me case
-  // (crbug.com/104377).
-  gtk_init(nullptr, nullptr);
+    // Required for any calls into GTK functions, such as the Disconnect and
+    // Continue windows, though these should not be used for the Me2Me case
+    // (crbug.com/104377).
+    gtk_init(nullptr, nullptr);
+  }
 
   // Need to prime the host OS version value for linux to prevent IO on the
   // network thread. base::GetLinuxDistro() caches the result.
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd
index d476e3f..08253f83 100644
--- a/remoting/resources/remoting_strings.grd
+++ b/remoting/resources/remoting_strings.grd
@@ -696,7 +696,6 @@
 • Redesigned user interface.
 • Improved performance, responsiveness and reliability.
 • Support for playing audio from Windows or Linux computers.
-• Enhanced keyboard support.
         </message>
       </if>  <!-- is_android or is_ios -->
 
@@ -1099,6 +1098,18 @@
                name="IDS_OFFLINE_REASON_USERNAME_MISMATCH" formatter_data="android_java">
         Invalid host owner.
       </message>
+      <message desc="Error message indicating that the host is offline because the X server keeps dying."
+               name="IDS_OFFLINE_REASON_X_SERVER_RETRIES_EXCEEDED" formatter_data="android_java">
+        X server crashed or failed to start.
+      </message>
+      <message desc="Error message indicating that the host is offline because the session script keeps dying."
+               name="IDS_OFFLINE_REASON_SESSION_RETRIES_EXCEEDED" formatter_data="android_java">
+        Session crashed or failed to start. If ~/.chrome-remote-desktop-session exists on the remote computer, make sure it runs a long-running process such as a desktop environment or window manager.
+      </message>
+      <message desc="Error message indicating that the host is offline because the host keeps dying."
+               name="IDS_OFFLINE_REASON_HOST_RETRIES_EXCEEDED" formatter_data="android_java">
+        Host crashed or failed to start.
+      </message>
       <if expr="is_android">
         <message desc="Description of why host is offline, when client gets a host-offline-reason it doesn't recognize."
                  name="IDS_OFFLINE_REASON_UNKNOWN" formatter_data="android_java">
diff --git a/remoting/webapp/crd/js/host_table_entry.js b/remoting/webapp/crd/js/host_table_entry.js
index d5bae00..5c3b4448 100644
--- a/remoting/webapp/crd/js/host_table_entry.js
+++ b/remoting/webapp/crd/js/host_table_entry.js
@@ -393,7 +393,10 @@
     /*i18n-content*/'OFFLINE_REASON_POLICY_CHANGE_REQUIRES_RESTART',
     /*i18n-content*/'OFFLINE_REASON_POLICY_READ_ERROR',
     /*i18n-content*/'OFFLINE_REASON_SUCCESS_EXIT',
-    /*i18n-content*/'OFFLINE_REASON_USERNAME_MISMATCH'
+    /*i18n-content*/'OFFLINE_REASON_USERNAME_MISMATCH',
+    /*i18n-content*/'OFFLINE_REASON_X_SERVER_RETRIES_EXCEEDED',
+    /*i18n-content*/'OFFLINE_REASON_SESSION_RETRIES_EXCEEDED',
+    /*i18n-content*/'OFFLINE_REASON_HOST_RETRIES_EXCEEDED'
   ];
   var offlineReasonTag = 'OFFLINE_REASON_' + hostOfflineReason;
   if (knownReasonTags.indexOf(offlineReasonTag) != (-1)) {
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 5f81dff5..76eccba 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -365,12 +365,10 @@
   return If((flags & ~kGoodFlags) == 0, Allow()).Else(CrashSIGSYS());
 }
 
-ResultExpr RestrictPrlimitToGetrlimit(pid_t target_pid) {
+ResultExpr RestrictPrlimit(pid_t target_pid) {
   const Arg<pid_t> pid(0);
-  const Arg<uintptr_t> new_limit(2);
-  // Only allow 'get' operations, and only for the current process.
-  return If(AllOf(new_limit == 0, AnyOf(pid == 0, pid == target_pid)), Allow())
-      .Else(Error(EPERM));
+  // Only allow operations for the current process.
+  return If(AnyOf(pid == 0, pid == target_pid), Allow()).Else(Error(EPERM));
 }
 
 }  // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
index c4577dc9..71c56093 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -98,10 +98,10 @@
 // GRND_NONBLOCK.
 SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetRandom();
 
-// Restrict |new_limit| to NULL, and |pid| to the calling process (or 0) for
-// prlimit64().  This allows only getting rlimits on the current process.
-// Otherwise, fail gracefully; see crbug.com/160157.
-SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimitToGetrlimit(pid_t target_pid);
+// Restrict |pid| to the calling process (or 0) for prlimit64().  This allows
+// getting and setting rlimits only on the current process.  Otherwise, fail
+// gracefully; see crbug.com/160157.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimit(pid_t target_pid);
 
 }  // namespace sandbox.
 
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
index 3ab366a..1b2feb0 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -90,12 +90,11 @@
 
   if (rv == -1 && errno == EFAULT) {
     return true;
-  } else {
-    // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
-    CHECK_EQ(-1, rv);
-    CHECK(ENOSYS == errno || EINVAL == errno);
-    return false;
   }
+
+  DCHECK_EQ(-1, rv);
+  DCHECK(ENOSYS == errno || EINVAL == errno);
+  return false;
 }
 
 uint64_t EscapePC() {
diff --git a/services/device/generic_sensor/generic_sensor_service_unittest.cc b/services/device/generic_sensor/generic_sensor_service_unittest.cc
index b80b737..2ca7bf05 100644
--- a/services/device/generic_sensor/generic_sensor_service_unittest.cc
+++ b/services/device/generic_sensor/generic_sensor_service_unittest.cc
@@ -89,12 +89,6 @@
 
 class FakePlatformSensorProvider : public PlatformSensorProvider {
  public:
-  static FakePlatformSensorProvider* GetInstance() {
-    return base::Singleton<
-        FakePlatformSensorProvider,
-        base::LeakySingletonTraits<FakePlatformSensorProvider>>::get();
-  }
-
   FakePlatformSensorProvider() = default;
   ~FakePlatformSensorProvider() override = default;
 
@@ -231,20 +225,36 @@
   }
 
   void TearDown() override {
-    PlatformSensorProvider::SetProviderForTesting(nullptr);
+    io_thread_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&GenericSensorServiceTest::TearDownOnIOThread,
+                                  base::Unretained(this)));
+    io_loop_finished_event_.Wait();
   }
 
   void SetUpOnIOThread() {
+    fake_platform_sensor_provider_ = new FakePlatformSensorProvider();
     PlatformSensorProvider::SetProviderForTesting(
-        FakePlatformSensorProvider::GetInstance());
+        fake_platform_sensor_provider_);
     io_loop_finished_event_.Signal();
   }
 
+  void TearDownOnIOThread() {
+    PlatformSensorProvider::SetProviderForTesting(nullptr);
+
+    DCHECK(fake_platform_sensor_provider_);
+    delete fake_platform_sensor_provider_;
+    fake_platform_sensor_provider_ = nullptr;
+
+    io_loop_finished_event_.Signal();
+  }
   mojom::SensorProviderPtr sensor_provider_;
   scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
   base::WaitableEvent io_loop_finished_event_;
   base::test::ScopedFeatureList scoped_feature_list_;
 
+  // FakePlatformSensorProvider must be created and deleted in IO thread.
+  FakePlatformSensorProvider* fake_platform_sensor_provider_;
+
   DISALLOW_COPY_AND_ASSIGN(GenericSensorServiceTest);
 };
 
@@ -261,13 +271,7 @@
 }
 
 // Tests GetDefaultConfiguration.
-// Failing on Android Tests (dbg); see https://crbug.com/761742.
-#if defined(OS_ANDROID)
-#define MAYBE_GetDefaultConfigurationTest DISABLED_GetDefaultConfigurationTest
-#else
-#define MAYBE_GetDefaultConfigurationTest GetDefaultConfigurationTest
-#endif
-TEST_F(GenericSensorServiceTest, MAYBE_GetDefaultConfigurationTest) {
+TEST_F(GenericSensorServiceTest, GetDefaultConfigurationTest) {
   mojom::SensorPtr sensor;
   auto client = base::MakeUnique<TestSensorClient>(SensorType::ACCELEROMETER);
   base::RunLoop run_loop;
@@ -314,12 +318,7 @@
 // Tests adding an invalid configuation, the max allowed frequency is 50.0 in
 // the mocked SensorImpl, while we add one with 60.0.
 // Failing on Android Tests (dbg); see https://crbug.com/761742.
-#if defined(OS_ANDROID)
-#define MAYBE_InvalidAddConfigurationTest DISABLED_InvalidAddConfigurationTest
-#else
-#define MAYBE_InvalidAddConfigurationTest InvalidAddConfigurationTest
-#endif
-TEST_F(GenericSensorServiceTest, MAYBE_InvalidAddConfigurationTest) {
+TEST_F(GenericSensorServiceTest, InvalidAddConfigurationTest) {
   mojom::SensorPtr sensor;
   auto client =
       base::MakeUnique<TestSensorClient>(SensorType::LINEAR_ACCELERATION);
@@ -387,13 +386,7 @@
 // Tests adding more than one clients. If mojo connection is broken on one
 // client, other clients should not be affected.
 // Failing on Android Tests (dbg); see https://crbug.com/761742.
-#if defined(OS_ANDROID)
-#define MAYBE_ClientMojoConnectionBrokenTest \
-  DISABLED_ClientMojoConnectionBrokenTest
-#else
-#define MAYBE_ClientMojoConnectionBrokenTest ClientMojoConnectionBrokenTest
-#endif
-TEST_F(GenericSensorServiceTest, MAYBE_ClientMojoConnectionBrokenTest) {
+TEST_F(GenericSensorServiceTest, ClientMojoConnectionBrokenTest) {
   mojom::SensorPtr sensor_1;
   auto client_1 = base::MakeUnique<TestSensorClient>(SensorType::AMBIENT_LIGHT);
   sensor_provider_->GetSensor(SensorType::AMBIENT_LIGHT,
@@ -498,12 +491,7 @@
 // early quit of main thread (when there is an unexpected notification by
 // SensorReadingChanged()).
 // Failing on Android Tests (dbg); see https://crbug.com/761742.
-#if defined(OS_ANDROID)
-#define MAYBE_SuspendTest DISABLED_SuspendTest
-#else
-#define MAYBE_SuspendTest SuspendTest
-#endif
-TEST_F(GenericSensorServiceTest, MAYBE_SuspendTest) {
+TEST_F(GenericSensorServiceTest, SuspendTest) {
   mojom::SensorPtr sensor;
   auto client = base::MakeUnique<TestSensorClient>(SensorType::AMBIENT_LIGHT);
   sensor_provider_->GetSensor(SensorType::AMBIENT_LIGHT,
@@ -586,14 +574,7 @@
 // Test suspend when there are more than one client. The suspended client won't
 // receive SensorReadingChanged() notification.
 // Failing on Android Tests (dbg); see https://crbug.com/761742.
-#if defined(OS_ANDROID)
-#define MAYBE_MultipleClientsSuspendAndResumeTest \
-  DISABLED_MultipleClientsSuspendAndResumeTest
-#else
-#define MAYBE_MultipleClientsSuspendAndResumeTest \
-  MultipleClientsSuspendAndResumeTest
-#endif
-TEST_F(GenericSensorServiceTest, MAYBE_MultipleClientsSuspendAndResumeTest) {
+TEST_F(GenericSensorServiceTest, MultipleClientsSuspendAndResumeTest) {
   mojom::SensorPtr sensor_1;
   auto client_1 = base::MakeUnique<TestSensorClient>(SensorType::AMBIENT_LIGHT);
   sensor_provider_->GetSensor(SensorType::AMBIENT_LIGHT,
diff --git a/services/service_manager/public/cpp/connector.cc b/services/service_manager/public/cpp/connector.cc
index 23f2847b..9e0d65e7 100644
--- a/services/service_manager/public/cpp/connector.cc
+++ b/services/service_manager/public/cpp/connector.cc
@@ -56,6 +56,11 @@
                  weak_factory_.GetWeakPtr()));
 }
 
+void Connector::QueryService(const Identity& identity,
+                             mojom::Connector::QueryServiceCallback callback) {
+  connector_->QueryService(identity, std::move(callback));
+}
+
 void Connector::BindInterface(const Identity& target,
                               const std::string& interface_name,
                               mojo::ScopedMessagePipeHandle interface_pipe) {
@@ -119,6 +124,24 @@
   local_binder_overrides_[service_name][interface_name] = binder;
 }
 
+bool Connector::HasBinderOverride(const std::string& service_name,
+                                  const std::string& interface_name) {
+  auto service_overrides = local_binder_overrides_.find(service_name);
+  if (service_overrides == local_binder_overrides_.end())
+    return false;
+
+  return base::ContainsKey(service_overrides->second, interface_name);
+}
+
+void Connector::ClearBinderOverride(const std::string& service_name,
+                                    const std::string& interface_name) {
+  auto service_overrides = local_binder_overrides_.find(service_name);
+  if (service_overrides == local_binder_overrides_.end())
+    return;
+
+  service_overrides->second.erase(interface_name);
+}
+
 void Connector::ClearBinderOverrides() {
   local_binder_overrides_.clear();
 }
diff --git a/services/service_manager/public/cpp/connector.h b/services/service_manager/public/cpp/connector.h
index 152b310..33c6310 100644
--- a/services/service_manager/public/cpp/connector.h
+++ b/services/service_manager/public/cpp/connector.h
@@ -55,6 +55,14 @@
       connector_->OverrideBinderForTesting(service_name, interface_name,
                                            binder);
     }
+    bool HasBinderOverride(const std::string& service_name,
+                           const std::string& interface_name) {
+      return connector_->HasBinderOverride(service_name, interface_name);
+    }
+    void ClearBinderOverride(const std::string& service_name,
+                             const std::string& interface_name) {
+      connector_->ClearBinderOverride(service_name, interface_name);
+    }
     void ClearBinderOverrides() { connector_->ClearBinderOverrides(); }
 
     // Register a callback to be run with the result of an attempt to start a
@@ -89,6 +97,11 @@
                     mojom::ServicePtr service,
                     mojom::PIDReceiverRequest pid_receiver_request);
 
+  // Determines if the service for |Identity| is known, and returns information
+  // about it from the catalog.
+  void QueryService(const Identity& identity,
+                    mojom::Connector::QueryServiceCallback callback);
+
   // Connect to |target| & request to bind |Interface|.
   template <typename Interface>
   void BindInterface(const Identity& target,
@@ -136,6 +149,10 @@
   void OverrideBinderForTesting(const std::string& service_name,
                                 const std::string& interface_name,
                                 const TestApi::Binder& binder);
+  bool HasBinderOverride(const std::string& service_name,
+                         const std::string& interface_name);
+  void ClearBinderOverride(const std::string& service_name,
+                           const std::string& interface_name);
   void ClearBinderOverrides();
   void SetStartServiceCallback(const StartServiceCallback& callback);
   void ResetStartServiceCallback();
diff --git a/services/service_manager/public/cpp/test/test_connector_factory.cc b/services/service_manager/public/cpp/test/test_connector_factory.cc
index 6d3e2b8e..dd784ff9 100644
--- a/services/service_manager/public/cpp/test/test_connector_factory.cc
+++ b/services/service_manager/public/cpp/test/test_connector_factory.cc
@@ -35,6 +35,11 @@
     NOTREACHED();
   }
 
+  void QueryService(const Identity& target,
+                    QueryServiceCallback callback) override {
+    NOTREACHED();
+  }
+
   void StartServiceWithProcess(
       const Identity& identity,
       mojo::ScopedMessagePipeHandle service,
diff --git a/services/service_manager/public/interfaces/connector.mojom b/services/service_manager/public/interfaces/connector.mojom
index cef7cc5..ab256f44 100644
--- a/services/service_manager/public/interfaces/connector.mojom
+++ b/services/service_manager/public/interfaces/connector.mojom
@@ -105,6 +105,28 @@
                 handle<message_pipe> interface_pipe) =>
       (ConnectResult result, Identity user_id);
 
+  // Asks the service manager whether it knows how to manage a given service,
+  // and how the service is to be sandboxed per the mainifest. No processes are
+  // started as a result. QueryService() is typically used before a call to
+  // StartProcessWithService() so the client can determine how to launch a
+  // process.
+  //
+  // Parameters:
+  //
+  //  target
+  //    The identity of the service to query.
+  //
+  // Response parameters:
+  //
+  //  result
+  //    Indicates the result of the QueryService() operation.
+  //
+  //  sandbox_type
+  //    A string describing the kind of sandboxing the service has declared
+  //    for itself in the manifest.
+  //
+  QueryService(Identity target) => (ConnectResult result, string sandbox_type);
+
   // Asks the service manager to create an instance for a service. No action is
   // taken if an instance is already present. If the service is not yet running,
   // it will be initialized and its OnStart() method will be called. A process
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index 42fa804..4ad4adea 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -432,6 +432,15 @@
     service_manager_->Connect(std::move(params));
   }
 
+  void QueryService(const Identity& target,
+                    QueryServiceCallback callback) override {
+    std::string sandbox;
+    bool success = service_manager_->QueryCatalog(target, &sandbox);
+    std::move(callback).Run(success ? mojom::ConnectResult::SUCCEEDED
+                                    : mojom::ConnectResult::INVALID_ARGUMENT,
+                            std::move(sandbox));
+  }
+
   void StartService(const Identity& in_target,
                     StartServiceCallback callback) override {
     Identity target = in_target;
@@ -911,6 +920,17 @@
   Connect(std::move(params));
 }
 
+bool ServiceManager::QueryCatalog(const Identity& identity,
+                                  std::string* sandbox_type) {
+  const catalog::Entry* entry =
+      catalog_.GetInstanceForUserId(identity.user_id())
+          ->Resolve(identity.name());
+  if (!entry)
+    return false;
+  *sandbox_type = entry->sandbox_type();
+  return true;
+}
+
 void ServiceManager::RegisterService(
     const Identity& identity,
     mojom::ServicePtr service,
diff --git a/services/service_manager/service_manager.h b/services/service_manager/service_manager.h
index 44c6ae44..edc3e2e 100644
--- a/services/service_manager/service_manager.h
+++ b/services/service_manager/service_manager.h
@@ -89,6 +89,10 @@
                        mojom::ServicePtr service,
                        mojom::PIDReceiverRequest pid_receiver_request);
 
+  // Determine information about |Identity| from its manifests. Returns
+  // false if the identity does not have a catalog entry.
+  bool QueryCatalog(const Identity& identity, std::string* sandbox_type);
+
   // Completes a connection between a source and target application as defined
   // by |params|. If no existing instance of the target service is running, one
   // will be loaded.
diff --git a/services/service_manager/tests/connect/BUILD.gn b/services/service_manager/tests/connect/BUILD.gn
index 79df3ab..077419e5 100644
--- a/services/service_manager/tests/connect/BUILD.gn
+++ b/services/service_manager/tests/connect/BUILD.gn
@@ -56,6 +56,11 @@
   source = "connect_test_app_b_manifest.json"
 }
 
+service_manifest("connect_test_sandboxed_manifest") {
+  name = "connect_test_sandboxed_app"
+  source = "connect_test_sandboxed_app_manifest.json"
+}
+
 service("connect_test_package") {
   testonly = true
   sources = [
@@ -76,6 +81,7 @@
   packaged_services = [
     ":connect_test_a_manifest",
     ":connect_test_b_manifest",
+    ":connect_test_sandboxed_manifest",
   ]
 }
 
diff --git a/services/service_manager/tests/connect/OWNERS b/services/service_manager/tests/connect/OWNERS
index 36976509..7b1a383 100644
--- a/services/service_manager/tests/connect/OWNERS
+++ b/services/service_manager/tests/connect/OWNERS
@@ -24,3 +24,6 @@
 
 per-file connect_unittests_manifest.json=set noparent
 per-file connect_unittests_manifest.json=file://ipc/SECURITY_OWNERS
+
+per-file connect_test_sandboxed_app_manifest.json=set noparent
+per-file connect_test_sandboxed_app_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/services/service_manager/tests/connect/connect_test_sandboxed_app_manifest.json b/services/service_manager/tests/connect/connect_test_sandboxed_app_manifest.json
new file mode 100644
index 0000000..5da4f33
--- /dev/null
+++ b/services/service_manager/tests/connect/connect_test_sandboxed_app_manifest.json
@@ -0,0 +1,14 @@
+{
+  "name": "connect_test_sandboxed_app",
+  "display_name": "Sandboxed Connect Test App",
+  "sandbox_type": "superduper",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+      },
+      "requires": {
+        "service_manager": [ "service_manager:user_id" ]
+      }
+    }
+  }
+}
diff --git a/services/service_manager/tests/connect/connect_unittest.cc b/services/service_manager/tests/connect/connect_unittest.cc
index 73c4e63b5..0932a11 100644
--- a/services/service_manager/tests/connect/connect_unittest.cc
+++ b/services/service_manager/tests/connect/connect_unittest.cc
@@ -34,6 +34,8 @@
 const char kTestAppName[] = "connect_test_app";
 const char kTestAppAName[] = "connect_test_a";
 const char kTestAppBName[] = "connect_test_b";
+const char kTestNonexistentAppName[] = "connect_test_nonexistent_app";
+const char kTestSandboxedAppName[] = "connect_test_sandboxed_app";
 const char kTestClassAppName[] = "connect_test_class_app";
 const char kTestSingletonAppName[] = "connect_test_singleton_app";
 
@@ -54,6 +56,16 @@
   loop->Quit();
 }
 
+void ReceiveQueryResult(mojom::ConnectResult* out_result,
+                        std::string* out_string,
+                        base::RunLoop* loop,
+                        mojom::ConnectResult in_result,
+                        const std::string& in_string) {
+  *out_result = in_result;
+  *out_string = in_string;
+  loop->Quit();
+}
+
 void ReceiveConnectionResult(mojom::ConnectResult* out_result,
                              Identity* out_target,
                              base::RunLoop* loop,
@@ -206,6 +218,30 @@
   EXPECT_NE(instance_a1, instance_b);
 }
 
+TEST_F(ConnectTest, QueryService) {
+  mojom::ConnectResult result;
+  std::string sandbox_type;
+  base::RunLoop run_loop;
+  connector()->QueryService(
+      Identity(kTestSandboxedAppName, mojom::kInheritUserID, "A"),
+      base::BindOnce(&ReceiveQueryResult, &result, &sandbox_type, &run_loop));
+  run_loop.Run();
+  EXPECT_EQ(mojom::ConnectResult::SUCCEEDED, result);
+  EXPECT_EQ("superduper", sandbox_type);
+}
+
+TEST_F(ConnectTest, QueryNonexistentService) {
+  mojom::ConnectResult result;
+  std::string sandbox_type;
+  base::RunLoop run_loop;
+  connector()->QueryService(
+      Identity(kTestNonexistentAppName, mojom::kInheritUserID, "A"),
+      base::BindOnce(&ReceiveQueryResult, &result, &sandbox_type, &run_loop));
+  run_loop.Run();
+  EXPECT_EQ(mojom::ConnectResult::INVALID_ARGUMENT, result);
+  EXPECT_EQ("", sandbox_type);
+}
+
 // BlockedInterface should not be exposed to this application because it is not
 // in our CapabilityFilter whitelist.
 TEST_F(ConnectTest, BlockedInterface) {
diff --git a/services/shape_detection/OWNERS b/services/shape_detection/OWNERS
index 6966e3cb..16d84b0d 100644
--- a/services/shape_detection/OWNERS
+++ b/services/shape_detection/OWNERS
@@ -1,5 +1,5 @@
 # COMPONENT: Blink>ImageCapture
-# TEAM: device-dev@chromium.org
+# TEAM: media-dev@chromium.org
 
 mcasas@chromium.org
 reillyg@chromium.org
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom
index b7e0e65..af91ca5 100644
--- a/services/ui/public/interfaces/window_manager.mojom
+++ b/services/ui/public/interfaces/window_manager.mojom
@@ -4,12 +4,12 @@
 
 module ui.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
 import "services/ui/public/interfaces/cursor/cursor.mojom";
 import "services/ui/public/interfaces/event_matcher.mojom";
 import "services/ui/public/interfaces/window_manager_constants.mojom";
 import "services/ui/public/interfaces/window_tree_constants.mojom";
+import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 import "skia/public/interfaces/bitmap.mojom";
 import "ui/base/mojo/ui_base_types.mojom";
 import "ui/display/mojo/display.mojom";
diff --git a/services/ui/public/interfaces/window_tree.mojom b/services/ui/public/interfaces/window_tree.mojom
index 7de3fa7..5e6bc3d 100644
--- a/services/ui/public/interfaces/window_tree.mojom
+++ b/services/ui/public/interfaces/window_tree.mojom
@@ -4,7 +4,6 @@
 
 module ui.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
 import "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom";
 import "services/viz/public/interfaces/compositing/surface_info.mojom";
@@ -14,6 +13,7 @@
 import "services/ui/public/interfaces/window_manager.mojom";
 import "services/ui/public/interfaces/window_manager_constants.mojom";
 import "services/ui/public/interfaces/window_tree_constants.mojom";
+import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 import "skia/public/interfaces/bitmap.mojom";
 import "ui/base/mojo/ui_base_types.mojom";
 import "ui/events/mojo/event.mojom";
@@ -366,7 +366,7 @@
   // This is called on the owner of a window when it embeds a client in it,
   // which includes the window manager creating a new window at the request of
   // another client.
-  OnFrameSinkIdAllocated(uint32 window, cc.mojom.FrameSinkId frame_sink_id);
+  OnFrameSinkIdAllocated(uint32 window, viz.mojom.FrameSinkId frame_sink_id);
 
   // Called in response to NewTopLevelWindow() successfully completing.
   // |parent_drawn| is true if the parent of the window is drawn, see
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index 5fd4a6f..3b3cac7 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -304,7 +304,6 @@
   previous_event_ = Event::Clone(event);
   previous_accelerator_match_phase_ = match_phase;
 #endif
-  event_display_id_ = display_id;
 
   if (event.IsKeyEvent()) {
     const ui::KeyEvent* key_event = event.AsKeyEvent();
@@ -313,12 +312,12 @@
           FindAccelerator(*key_event, ui::mojom::AcceleratorPhase::PRE_TARGET);
       if (pre_target) {
         delegate_->OnAccelerator(
-            pre_target->id(), event_display_id_, event,
+            pre_target->id(), display_id, event,
             EventDispatcherDelegate::AcceleratorPhase::PRE);
         return;
       }
     }
-    ProcessKeyEvent(*key_event, match_phase);
+    ProcessKeyEvent(*key_event, display_id, match_phase);
     return;
   }
 
@@ -329,15 +328,17 @@
   if (ShouldUseEventTargeter(*event.AsPointerEvent())) {
     waiting_on_event_targeter_ = true;
     event_targeter_->FindTargetForLocation(
-        event_source,
-        {event.AsPointerEvent()->root_location(), event_display_id_},
+        event_source, {event.AsPointerEvent()->root_location(), display_id},
         base::BindOnce(&EventDispatcher::ProcessPointerEventOnFoundTarget,
                        base::Unretained(this), *event.AsPointerEvent()));
   } else {
+    // Using GetDisplayLocationFromEvent() may alter the display (and location).
+    // We need to always dispatch using the display the event came in on. The
+    // expectation for capture is events are dispatched from the display with
+    // capture, regardless of where the pointer happens to be.
     ProcessPointerEventOnFoundTargetImpl(
         *event.AsPointerEvent(),
-        GetDisplayLocationFromEvent(*event.AsPointerEvent(), display_id),
-        nullptr);
+        {event.AsPointerEvent()->root_location(), display_id}, nullptr);
   }
 }
 
@@ -407,6 +408,7 @@
 }
 
 void EventDispatcher::ProcessKeyEvent(const ui::KeyEvent& event,
+                                      int64_t display_id,
                                       AcceleratorMatchPhase match_phase) {
   Accelerator* post_target =
       FindAccelerator(event, ui::mojom::AcceleratorPhase::POST_TARGET);
@@ -416,7 +418,7 @@
     return;
   }
   ServerWindow* focused_window =
-      delegate_->GetFocusedWindowForEventDispatcher(event_display_id_);
+      delegate_->GetFocusedWindowForEventDispatcher(display_id);
   if (focused_window) {
     // We only hide the cursor when there's a window to receive the key
     // event. We want to hide the cursor when the user is entering text
@@ -428,13 +430,13 @@
     const bool in_nonclient_area = false;
     const ClientSpecificId client_id =
         delegate_->GetEventTargetClientId(focused_window, in_nonclient_area);
-    delegate_->DispatchInputEventToWindow(
-        focused_window, client_id, event_display_id_, event, post_target);
+    delegate_->DispatchInputEventToWindow(focused_window, client_id, display_id,
+                                          event, post_target);
     return;
   }
-  delegate_->OnEventTargetNotFound(event, event_display_id_);
+  delegate_->OnEventTargetNotFound(event, display_id);
   if (post_target)
-    delegate_->OnAccelerator(post_target->id(), event_display_id_, event,
+    delegate_->OnAccelerator(post_target->id(), display_id, event,
                              EventDispatcherDelegate::AcceleratorPhase::POST);
 }
 
@@ -488,11 +490,7 @@
   DCHECK(!waiting_on_event_targeter_);
   // WARNING: |found_target| may be null!
   std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(event);
-  if (display_location.display_id != event_display_id_) {
-    event_display_id_ = display_location.display_id;
-    cloned_event->AsLocatedEvent()->set_root_location(
-        display_location.location);
-  }
+  cloned_event->AsLocatedEvent()->set_root_location(display_location.location);
 
   UpdateCursorRelatedProperties(event, display_location);
 
@@ -525,7 +523,8 @@
   if (capture_window_) {
     SetMouseCursorSourceWindow(capture_window_);
     DispatchToClient(capture_window_, capture_window_client_id_,
-                     *cloned_event->AsPointerEvent());
+                     *cloned_event->AsPointerEvent(),
+                     display_location.display_id);
     return;
   }
 
@@ -539,6 +538,7 @@
         result->deepest_window.in_non_client_area;
     result->pointer_target.is_pointer_down =
         event.type() == ui::ET_POINTER_DOWN;
+    result->pointer_target.display_id = display_location.display_id;
   }
 
   const int32_t pointer_id = event.pointer_details().id;
@@ -557,15 +557,14 @@
       if (is_mouse_event)
         SetMouseCursorSourceWindow(pointer_target.window);
       if (!any_pointers_down) {
-        // Don't attempt to change focus on pointer downs. We assume client code
+        // Don't attempt to change focus on pointer down. We assume client code
         // will do that.
         ServerWindow* capture_window = pointer_target.window;
         if (!capture_window) {
-          gfx::Point event_location =
-              cloned_event->AsPointerEvent()->root_location();
-          int64_t event_display_id = event_display_id_;
-          capture_window = delegate_->GetRootWindowContaining(
-              &event_location, &event_display_id);
+          int64_t event_display_id = display_location.display_id;
+          gfx::Point location = display_location.location;
+          capture_window =
+              delegate_->GetRootWindowContaining(&location, &event_display_id);
         }
         delegate_->SetNativeCapture(capture_window);
       }
@@ -741,21 +740,23 @@
 void EventDispatcher::DispatchToPointerTarget(const PointerTarget& target,
                                               const ui::LocatedEvent& event) {
   if (!target.window) {
-    delegate_->OnEventTargetNotFound(event, event_display_id_);
+    delegate_->OnEventTargetNotFound(event, target.display_id);
     return;
   }
 
   if (target.is_mouse_event)
     mouse_cursor_in_non_client_area_ = target.in_nonclient_area;
 
-  DispatchToClient(target.window, delegate_->GetEventTargetClientId(
-                                      target.window, target.in_nonclient_area),
-                   event);
+  DispatchToClient(target.window,
+                   delegate_->GetEventTargetClientId(target.window,
+                                                     target.in_nonclient_area),
+                   event, target.display_id);
 }
 
 void EventDispatcher::DispatchToClient(ServerWindow* window,
                                        ClientSpecificId client_id,
-                                       const ui::LocatedEvent& event) {
+                                       const ui::LocatedEvent& event,
+                                       int64_t display_id) {
   gfx::Point location = ConvertPointFromRootForEventDispatch(
       delegate_->GetRootWindowForEventDispatch(window), window,
       event.location());
@@ -763,8 +764,8 @@
   clone->AsLocatedEvent()->set_location(location);
   // TODO(jonross): add post-target accelerator support once accelerators
   // support pointer events.
-  delegate_->DispatchInputEventToWindow(window, client_id, event_display_id_,
-                                        *clone, nullptr);
+  delegate_->DispatchInputEventToWindow(window, client_id, display_id, *clone,
+                                        nullptr);
 }
 
 void EventDispatcher::CancelPointerEventsToTarget(ServerWindow* window) {
@@ -857,7 +858,6 @@
 void EventDispatcher::OnWillChangeWindowHierarchy(ServerWindow* window,
                                                   ServerWindow* new_parent,
                                                   ServerWindow* old_parent) {
-  // TODO(sky): moving to a different root likely needs to transfer capture.
   // TODO(sky): this isn't quite right, I think the logic should be (assuming
   // moving in same root and still drawn):
   // . if there is capture and window is still in the same root, continue
@@ -865,10 +865,8 @@
   // . if there isn't capture, then reevaluate each of the pointer targets
   //   sending exit as necessary.
   // http://crbug.com/613646 .
-  if (!new_parent || !new_parent->IsDrawn() ||
-      new_parent->GetRootForDrawn() != old_parent->GetRootForDrawn()) {
+  if (!new_parent || !new_parent->IsDrawn())
     CancelPointerEventsToTarget(window);
-  }
 }
 
 void EventDispatcher::OnWindowVisibilityChanged(ServerWindow* window) {
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h
index 0e48fc7..a85b60e00 100644
--- a/services/ui/ws/event_dispatcher.h
+++ b/services/ui/ws/event_dispatcher.h
@@ -21,6 +21,7 @@
 #include "services/ui/ws/event_targeter_delegate.h"
 #include "services/ui/ws/modal_window_controller.h"
 #include "services/ui/ws/server_window_observer.h"
+#include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace viz {
@@ -182,23 +183,19 @@
 
   // Keeps track of state associated with an active pointer.
   struct PointerTarget {
-    PointerTarget()
-        : window(nullptr),
-          is_mouse_event(false),
-          in_nonclient_area(false),
-          is_pointer_down(false) {}
-
     // The target window, which may be null. null is used in two situations:
     // when there is no valid window target, or there was a target but the
     // window is destroyed before a corresponding release/cancel.
-    ServerWindow* window;
+    ServerWindow* window = nullptr;
 
-    bool is_mouse_event;
+    bool is_mouse_event = false;
 
     // Did the pointer event start in the non-client area.
-    bool in_nonclient_area;
+    bool in_nonclient_area = false;
 
-    bool is_pointer_down;
+    bool is_pointer_down = false;
+
+    int64_t display_id = display::kInvalidDisplayId;
   };
 
   struct DeepestWindowAndTarget {
@@ -228,6 +225,7 @@
                                int64_t new_mouse_display_id);
 
   void ProcessKeyEvent(const ui::KeyEvent& event,
+                       int64_t display_id,
                        AcceleratorMatchPhase match_phase);
 
   // When the user presses a key, we want to hide the cursor if it doesn't
@@ -312,7 +310,8 @@
   // Dispatch |event| to the delegate.
   void DispatchToClient(ServerWindow* window,
                         ClientSpecificId client_id,
-                        const ui::LocatedEvent& event);
+                        const ui::LocatedEvent& event,
+                        int64_t display_id);
 
   // Stops sending pointer events to |window|. This does not remove the entry
   // for |window| from |pointer_targets_|, rather it nulls out the window. This
@@ -374,9 +373,6 @@
   // Id of the display |mouse_pointer_last_location_| is on.
   int64_t mouse_pointer_display_id_ = display::kInvalidDisplayId;
 
-  // Id of the display the most recent event is on.
-  int64_t event_display_id_ = display::kInvalidDisplayId;
-
   std::map<uint32_t, std::unique_ptr<Accelerator>> accelerators_;
 
   // A list of EventMatchers provided by the window manager. When this list is
diff --git a/services/ui/ws/event_dispatcher_unittest.cc b/services/ui/ws/event_dispatcher_unittest.cc
index ec8c6034..17b1613 100644
--- a/services/ui/ws/event_dispatcher_unittest.cc
+++ b/services/ui/ws/event_dispatcher_unittest.cc
@@ -2397,6 +2397,21 @@
             test_event_dispatcher_delegate()->window_that_blocked_event());
 }
 
+TEST_P(EventDispatcherTest, DontCancelWhenMovedToSeparateDisplay) {
+  TestServerWindowDelegate window_delegate2;
+  ServerWindow root2(&window_delegate2, WindowId(1, 100));
+  root2.set_is_activation_parent(true);
+  window_delegate2.set_root_window(&root2);
+  root2.SetVisible(true);
+
+  std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+  event_dispatcher()->SetCaptureWindow(w1.get(), kClientAreaId);
+  ASSERT_EQ(w1.get(), event_dispatcher()->capture_window());
+  test_event_dispatcher_delegate()->set_root(&root2);
+  root2.Add(w1.get());
+  EXPECT_EQ(w1.get(), event_dispatcher()->capture_window());
+}
+
 // Tests that setting capture to a window unrelated to a modal parent works.
 TEST_P(EventDispatcherTest, MouseCursorSourceWindowChangesWithSystemModal) {
   BlockingContainers blocking_containers;
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc
index 43f3cfa3..6570059e 100644
--- a/services/ui/ws/frame_generator.cc
+++ b/services/ui/ws/frame_generator.cc
@@ -132,8 +132,11 @@
     gfx::Size scaled_bounds = gfx::ScaleToCeiledSize(
         pixel_size_, window_manager_surface_info_.device_scale_factor(),
         window_manager_surface_info_.device_scale_factor());
+    bool is_clipped = false;
+    bool are_contents_opaque = false;
     shared_state->SetAll(gfx::Transform(), gfx::Rect(scaled_bounds), bounds,
-                         bounds, false, 1.f, SkBlendMode::kSrcOver, 0);
+                         bounds, is_clipped, are_contents_opaque, 1.f,
+                         SkBlendMode::kSrcOver, 0);
     auto* quad = invert_pass->CreateAndAppendDrawQuad<cc::RenderPassDrawQuad>();
     frame.render_pass_list.back()->filters.Append(
         cc::FilterOperation::CreateInvertFilter(1.f));
@@ -192,11 +195,12 @@
 
   // TODO(fsamuel): These clipping and visible rects are incorrect. They need
   // to be populated from CompositorFrame structs.
-  sqs->SetAll(
-      quad_to_target_transform, gfx::Rect(scaled_bounds) /* layer_rect */,
-      bounds_at_origin /* visible_layer_bounds */,
-      bounds_at_origin /* clip_rect */, false /* is_clipped */,
-      1.0f /* opacity */, SkBlendMode::kSrcOver, 0 /* sorting-context_id */);
+  sqs->SetAll(quad_to_target_transform,
+              gfx::Rect(scaled_bounds) /* layer_rect */,
+              bounds_at_origin /* visible_layer_bounds */,
+              bounds_at_origin /* clip_rect */, false /* is_clipped */,
+              false /* are_contents_opaque */, 1.0f /* opacity */,
+              SkBlendMode::kSrcOver, 0 /* sorting-context_id */);
   auto* quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
   quad->SetAll(sqs, bounds_at_origin /* rect */,
                bounds_at_origin /* visible_rect */, true /* needs_blending*/,
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc
index 38836362..b641d74 100644
--- a/services/ui/ws/platform_display_default.cc
+++ b/services/ui/ws/platform_display_default.cc
@@ -21,7 +21,7 @@
 
 #if defined(OS_WIN)
 #include "ui/platform_window/win/win_window.h"
-#elif defined(USE_X11) && !defined(OS_CHROMEOS)
+#elif defined(USE_X11)
 #include "ui/platform_window/x11/x11_window.h"
 #elif defined(OS_ANDROID)
 #include "ui/platform_window/android/platform_window_android.h"
@@ -74,7 +74,7 @@
 
 #if defined(OS_WIN)
   platform_window_ = base::MakeUnique<ui::WinWindow>(this, bounds);
-#elif defined(USE_X11) && !defined(OS_CHROMEOS)
+#elif defined(USE_X11)
   platform_window_ = base::MakeUnique<ui::X11Window>(this, bounds);
 #elif defined(OS_ANDROID)
   platform_window_ = base::MakeUnique<ui::PlatformWindowAndroid>(this);
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc
index 9afceb1..ef52cd66 100644
--- a/services/ui/ws/window_manager_state.cc
+++ b/services/ui/ws/window_manager_state.cc
@@ -498,12 +498,11 @@
   in_flight_event_dispatch_details_->post_target_accelerator = accelerator;
 
   // Ignore |tree| because it will receive the event via normal dispatch.
-  window_server()->SendToPointerWatchers(
-      event, user_id(), target, tree,
-      in_flight_event_dispatch_details_->display_id);
+  window_server()->SendToPointerWatchers(event, user_id(), target, tree,
+                                         display_id);
 
   tree->DispatchInputEvent(
-      target, event,
+      target, event, display_id,
       base::BindOnce(
           &WindowManagerState::OnEventAck,
           in_flight_event_dispatch_details_->weak_factory.GetWeakPtr(), tree));
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index fd4115c0..ac2aef5 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -75,9 +75,11 @@
  public:
   TargetedEvent(ServerWindow* target,
                 const ui::Event& event,
+                int64_t display_id,
                 WindowTree::DispatchEventCallback callback)
       : target_(target),
         event_(ui::Event::Clone(event)),
+        display_id_(display_id),
         callback_(std::move(callback)) {
     target_->AddObserver(this);
   }
@@ -88,6 +90,7 @@
 
   ServerWindow* target() { return target_; }
   std::unique_ptr<ui::Event> TakeEvent() { return std::move(event_); }
+  int64_t display_id() const { return display_id_; }
   WindowTree::DispatchEventCallback TakeCallback() {
     return std::move(callback_);
   }
@@ -102,6 +105,7 @@
 
   ServerWindow* target_;
   std::unique_ptr<ui::Event> event_;
+  const int64_t display_id_;
   WindowTree::DispatchEventCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(TargetedEvent);
@@ -695,11 +699,12 @@
 
 void WindowTree::DispatchInputEvent(ServerWindow* target,
                                     const ui::Event& event,
+                                    int64_t display_id,
                                     DispatchEventCallback callback) {
   if (event_ack_id_) {
     // This is currently waiting for an event ack. Add it to the queue.
-    event_queue_.push(
-        base::MakeUnique<TargetedEvent>(target, event, std::move(callback)));
+    event_queue_.push(base::MakeUnique<TargetedEvent>(target, event, display_id,
+                                                      std::move(callback)));
     // TODO(sad): If the |event_queue_| grows too large, then this should notify
     // Display, so that it can stop sending events.
     return;
@@ -709,12 +714,12 @@
   // and dispatch the latest event from the queue instead that still has a live
   // target.
   if (!event_queue_.empty()) {
-    event_queue_.push(
-        base::MakeUnique<TargetedEvent>(target, event, std::move(callback)));
+    event_queue_.push(base::MakeUnique<TargetedEvent>(target, event, display_id,
+                                                      std::move(callback)));
     return;
   }
 
-  DispatchInputEventImpl(target, event, std::move(callback));
+  DispatchInputEventImpl(target, event, display_id, std::move(callback));
 }
 
 bool WindowTree::IsWaitingForNewTopLevelWindow(uint32_t wm_change_id) {
@@ -1438,6 +1443,7 @@
 
 void WindowTree::DispatchInputEventImpl(ServerWindow* target,
                                         const ui::Event& event,
+                                        int64_t display_id,
                                         DispatchEventCallback callback) {
   // DispatchInputEventImpl() is called so often that log level 4 is used.
   DVLOG(4) << "DispatchInputEventImpl client=" << id_;
@@ -1449,10 +1455,8 @@
   // Should only get events from windows attached to a host.
   DCHECK(event_source_wms_);
   bool matched_pointer_watcher = EventMatchesPointerWatcher(event);
-  Display* display = GetDisplay(target);
-  DCHECK(display);
   client()->OnWindowInputEvent(
-      event_ack_id_, ClientWindowIdForWindow(target).id, display->GetId(),
+      event_ack_id_, ClientWindowIdForWindow(target).id, display_id,
       ui::Event::Clone(event), matched_pointer_watcher);
 }
 
@@ -1855,16 +1859,18 @@
     ServerWindow* target = nullptr;
     std::unique_ptr<ui::Event> event;
     DispatchEventCallback callback;
+    int64_t display_id = display::kInvalidDisplayId;
     do {
       std::unique_ptr<TargetedEvent> targeted_event =
           std::move(event_queue_.front());
       event_queue_.pop();
       target = targeted_event->target();
       event = targeted_event->TakeEvent();
+      display_id = targeted_event->display_id();
       callback = targeted_event->TakeCallback();
     } while (!event_queue_.empty() && !GetDisplay(target));
     if (target)
-      DispatchInputEventImpl(target, *event, std::move(callback));
+      DispatchInputEventImpl(target, *event, display_id, std::move(callback));
   }
 }
 
diff --git a/services/ui/ws/window_tree.h b/services/ui/ws/window_tree.h
index cf37200..8711929 100644
--- a/services/ui/ws/window_tree.h
+++ b/services/ui/ws/window_tree.h
@@ -199,6 +199,7 @@
   using DispatchEventCallback = base::OnceCallback<void(mojom::EventResult)>;
   void DispatchInputEvent(ServerWindow* target,
                           const ui::Event& event,
+                          int64_t display_id,
                           DispatchEventCallback callback);
 
   bool IsWaitingForNewTopLevelWindow(uint32_t wm_change_id);
@@ -394,6 +395,7 @@
 
   void DispatchInputEventImpl(ServerWindow* target,
                               const ui::Event& event,
+                              int64_t display_id,
                               DispatchEventCallback callback);
 
   // Returns true if the client has a pointer watcher and this event matches.
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc
index 32f5ca91..f9388c0 100644
--- a/services/ui/ws/window_tree_unittest.cc
+++ b/services/ui/ws/window_tree_unittest.cc
@@ -1565,7 +1565,7 @@
   // have switched to ibeam.
   EXPECT_EQ(ui::CursorType::kPointer, cursor_type());
 
-  // Have the window manager mvoe the cursor within the embed window.
+  // Have the window manager move the cursor within the embed window.
   static_cast<mojom::WindowManagerClient*>(wm_tree())
       ->WmMoveCursorToDisplayLocation(gfx::Point(21, 21), -1);
 
diff --git a/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom b/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
index 0253f899..6709ffc7 100644
--- a/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
+++ b/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
@@ -4,11 +4,11 @@
 
 module viz.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
 import "gpu/ipc/common/surface_handle.mojom";
 import "mojo/common/time.mojom";
 import "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom";
+import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_info.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
@@ -42,19 +42,19 @@
 interface FrameSinkManager {
   // Registers |frame_sink_id| will be used. This must be called before
   // Create(Root)CompositorFrameSink() is called.
-  RegisterFrameSinkId(cc.mojom.FrameSinkId frame_sink_id);
+  RegisterFrameSinkId(FrameSinkId frame_sink_id);
 
   // Invalidates |frame_sink_id| which cleans up any unsatisified surface
   // sequences or dangling temporary references assigned to it. If there is a
   // CompositorFrameSink for |frame_sink_id| then it will be destroyed and the
   // message pipe to the client will be closed.
-  InvalidateFrameSinkId(cc.mojom.FrameSinkId frame_sink_id);
+  InvalidateFrameSinkId(FrameSinkId frame_sink_id);
 
   // Create a CompositorFrameSink for a privileged client (e.g. WindowServer).
   // This is only used by privileged clients. The client can call methods that
   // talks to the Display (e.g. ResizeDisplay(), SetDisplayVisible(), etc)
   CreateRootCompositorFrameSink(
-      cc.mojom.FrameSinkId frame_sink_id,
+      FrameSinkId frame_sink_id,
       gpu.mojom.SurfaceHandle widget,
       RendererSettings renderer_settings,
       associated CompositorFrameSink& compositor_frame_sink,
@@ -65,25 +65,25 @@
   // CompositorFrameSink is not a root, and has to be parented by another
   // CompositorFrameSink in order to appear on screen.
   CreateCompositorFrameSink(
-      cc.mojom.FrameSinkId frame_sink_id,
+      FrameSinkId frame_sink_id,
       CompositorFrameSink& compositor_frame_sink,
       CompositorFrameSinkClient compositor_frame_sink_client);
 
   // Set up a BeginFrame relationship between two FrameSinkIds. In this case,
   // the child inherits the viz::BeginFrameSource from the parent if it doesn't
   // already have a viz::BeginFrameSource.
-  RegisterFrameSinkHierarchy(cc.mojom.FrameSinkId parent_frame_sink_id,
-                             cc.mojom.FrameSinkId child_frame_sink_id);
+  RegisterFrameSinkHierarchy(FrameSinkId parent_frame_sink_id,
+                             FrameSinkId child_frame_sink_id);
 
   // Removes a BeginFrame relationship between two FrameSinkIds.
-  UnregisterFrameSinkHierarchy(cc.mojom.FrameSinkId parent_frame_sink_id,
-                               cc.mojom.FrameSinkId child_frame_sink_id);
+  UnregisterFrameSinkHierarchy(FrameSinkId parent_frame_sink_id,
+                               FrameSinkId child_frame_sink_id);
 
   // Assigns the temporary reference for |surface_id| to FrameSinkId |owner|.
   // If |owner| is invalidated before it converts the temporary reference to a
   // surface reference then the temporary reference will be dropped.
   AssignTemporaryReference(SurfaceId surface_id,
-                           cc.mojom.FrameSinkId owner);
+                           FrameSinkId owner);
 
   // Drops the temporary reference for |surface_id|. This will get called when
   // the FrameSinkManagerClient doesn't think |surface_id| will be embedded.
@@ -101,17 +101,17 @@
 
   // The CompositorFrameSink pipe for |frame_sink_id| was closed. The client
   // cannot submit any CompositorFrames to viz after this occurs.
-  OnClientConnectionClosed(cc.mojom.FrameSinkId frame_sink_id);
+  OnClientConnectionClosed(FrameSinkId frame_sink_id);
 
   // Sends |active_handle| and |idle_handle| along with their sizes to the
   // client when they are allocated or resized.
-  OnAggregatedHitTestRegionListUpdated(cc.mojom.FrameSinkId frame_sink_id,
+  OnAggregatedHitTestRegionListUpdated(FrameSinkId frame_sink_id,
                                        handle<shared_buffer> active_handle,
                                        uint32 active_handle_size,
                                        handle<shared_buffer> idle_handle,
                                        uint32 idle_handle_size);
 
   // Tells the client to update the currently active handle.
-  SwitchActiveAggregatedHitTestRegionList(cc.mojom.FrameSinkId frame_sink_id,
+  SwitchActiveAggregatedHitTestRegionList(FrameSinkId frame_sink_id,
                                           uint8 active_handle_index);
 };
diff --git a/services/viz/public/cpp/compositing/frame_sink_id.typemap b/services/viz/public/cpp/compositing/frame_sink_id.typemap
new file mode 100644
index 0000000..76c92fb
--- /dev/null
+++ b/services/viz/public/cpp/compositing/frame_sink_id.typemap
@@ -0,0 +1,12 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/viz/public/interfaces/compositing/frame_sink_id.mojom"
+public_headers = [ "//components/viz/common/surfaces/frame_sink_id.h" ]
+deps = [
+  "//components/viz/common",
+]
+traits_headers =
+    [ "//services/viz/public/cpp/compositing/frame_sink_id_struct_traits.h" ]
+type_mappings = [ "viz.mojom.FrameSinkId=viz::FrameSinkId" ]
diff --git a/services/viz/public/cpp/compositing/frame_sink_id_struct_traits.h b/services/viz/public/cpp/compositing/frame_sink_id_struct_traits.h
new file mode 100644
index 0000000..858019a
--- /dev/null
+++ b/services/viz/public/cpp/compositing/frame_sink_id_struct_traits.h
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FRAME_SINK_ID_STRUCT_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FRAME_SINK_ID_STRUCT_TRAITS_H_
+
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "services/viz/public/interfaces/compositing/frame_sink_id.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<viz::mojom::FrameSinkIdDataView, viz::FrameSinkId> {
+  static uint32_t client_id(const viz::FrameSinkId& frame_sink_id) {
+    return frame_sink_id.client_id();
+  }
+
+  static uint32_t sink_id(const viz::FrameSinkId& frame_sink_id) {
+    return frame_sink_id.sink_id();
+  }
+
+  static bool Read(viz::mojom::FrameSinkIdDataView data,
+                   viz::FrameSinkId* out) {
+    *out = viz::FrameSinkId(data.client_id(), data.sink_id());
+    return true;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FRAME_SINK_ID_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h b/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h
index a6dd5f8..247087f 100644
--- a/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h
+++ b/services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h
@@ -42,6 +42,10 @@
     return input.sqs->is_clipped;
   }
 
+  static bool are_contents_opaque(const OptSharedQuadState& input) {
+    return input.sqs->are_contents_opaque;
+  }
+
   static float opacity(const OptSharedQuadState& input) {
     return input.sqs->opacity;
   }
@@ -79,6 +83,10 @@
     return sqs.is_clipped;
   }
 
+  static bool are_contents_opaque(const viz::SharedQuadState& sqs) {
+    return sqs.are_contents_opaque;
+  }
+
   static float opacity(const viz::SharedQuadState& sqs) { return sqs.opacity; }
 
   static uint32_t blend_mode(const viz::SharedQuadState& sqs) {
@@ -99,6 +107,7 @@
     }
 
     out->is_clipped = data.is_clipped();
+    out->are_contents_opaque = data.are_contents_opaque();
     out->opacity = data.opacity();
     if (data.blend_mode() > static_cast<int>(SkBlendMode::kLastMode))
       return false;
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 472a57c..737d588 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "cc/ipc/copy_output_result_struct_traits.h"
-#include "cc/ipc/frame_sink_id_struct_traits.h"
 #include "cc/ipc/local_surface_id_struct_traits.h"
 #include "cc/ipc/texture_mailbox_struct_traits.h"
 #include "cc/output/compositor_frame.h"
@@ -33,6 +32,7 @@
 #include "services/viz/public/cpp/compositing/copy_output_request_struct_traits.h"
 #include "services/viz/public/cpp/compositing/filter_operation_struct_traits.h"
 #include "services/viz/public/cpp/compositing/filter_operations_struct_traits.h"
+#include "services/viz/public/cpp/compositing/frame_sink_id_struct_traits.h"
 #include "services/viz/public/cpp/compositing/render_pass_struct_traits.h"
 #include "services/viz/public/cpp/compositing/resource_settings_struct_traits.h"
 #include "services/viz/public/cpp/compositing/returned_resource_struct_traits.h"
@@ -376,13 +376,14 @@
   const gfx::Rect visible_layer_rect(12, 34, 56, 78);
   const gfx::Rect clip_rect(123, 456, 789, 101112);
   const bool is_clipped = true;
+  bool are_contents_opaque = true;
   const float opacity = 0.9f;
   const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
   const int sorting_context_id = 1337;
   SharedQuadState input_sqs;
   input_sqs.SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
-                   clip_rect, is_clipped, opacity, blend_mode,
-                   sorting_context_id);
+                   clip_rect, is_clipped, are_contents_opaque, opacity,
+                   blend_mode, sorting_context_id);
   SharedQuadState output_sqs;
   SerializeAndDeserialize<mojom::SharedQuadState>(input_sqs, &output_sqs);
   EXPECT_EQ(quad_to_target_transform, output_sqs.quad_to_target_transform);
@@ -423,13 +424,15 @@
   const gfx::Rect sqs_visible_layer_rect(12, 34, 56, 78);
   const gfx::Rect sqs_clip_rect(123, 456, 789, 101112);
   const bool sqs_is_clipped = true;
+  bool sqs_are_contents_opaque = false;
   const float sqs_opacity = 0.9f;
   const SkBlendMode sqs_blend_mode = SkBlendMode::kSrcOver;
   const int sqs_sorting_context_id = 1337;
   SharedQuadState* sqs = render_pass->CreateAndAppendSharedQuadState();
   sqs->SetAll(sqs_quad_to_target_transform, sqs_layer_rect,
               sqs_visible_layer_rect, sqs_clip_rect, sqs_is_clipped,
-              sqs_opacity, sqs_blend_mode, sqs_sorting_context_id);
+              sqs_are_contents_opaque, sqs_opacity, sqs_blend_mode,
+              sqs_sorting_context_id);
 
   // cc::DebugBorderDrawQuad.
   const gfx::Rect rect1(1234, 4321, 1357, 7531);
@@ -508,6 +511,7 @@
   EXPECT_EQ(sqs_visible_layer_rect, out_sqs->visible_quad_layer_rect);
   EXPECT_EQ(sqs_clip_rect, out_sqs->clip_rect);
   EXPECT_EQ(sqs_is_clipped, out_sqs->is_clipped);
+  EXPECT_EQ(sqs_are_contents_opaque, out_sqs->are_contents_opaque);
   EXPECT_EQ(sqs_opacity, out_sqs->opacity);
   EXPECT_EQ(sqs_blend_mode, out_sqs->blend_mode);
   EXPECT_EQ(sqs_sorting_context_id, out_sqs->sorting_context_id);
@@ -707,14 +711,16 @@
       gfx::Transform(16.1f, 15.3f, 14.3f, 13.7f, 12.2f, 11.4f, 10.4f, 9.8f,
                      8.1f, 7.3f, 6.3f, 5.7f, 4.8f, 3.4f, 2.4f, 1.2f),
       gfx::Rect(1, 2), gfx::Rect(1337, 5679, 9101112, 131415),
-      gfx::Rect(1357, 2468, 121314, 1337), true, 2, SkBlendMode::kSrcOver, 1);
+      gfx::Rect(1357, 2468, 121314, 1337), true, true, 2, SkBlendMode::kSrcOver,
+      1);
 
   SharedQuadState* shared_state_2 = input->CreateAndAppendSharedQuadState();
   shared_state_2->SetAll(
       gfx::Transform(1.1f, 2.3f, 3.3f, 4.7f, 5.2f, 6.4f, 7.4f, 8.8f, 9.1f,
                      10.3f, 11.3f, 12.7f, 13.8f, 14.4f, 15.4f, 16.2f),
       gfx::Rect(1337, 1234), gfx::Rect(1234, 5678, 9101112, 13141516),
-      gfx::Rect(1357, 2468, 121314, 1337), true, 2, SkBlendMode::kSrcOver, 1);
+      gfx::Rect(1357, 2468, 121314, 1337), true, true, 2, SkBlendMode::kSrcOver,
+      1);
 
   // This quad uses the first shared quad state. The next two quads use the
   // second shared quad state.
diff --git a/services/viz/public/cpp/compositing/surface_id_struct_traits.h b/services/viz/public/cpp/compositing/surface_id_struct_traits.h
index b8ecb984..352a99f 100644
--- a/services/viz/public/cpp/compositing/surface_id_struct_traits.h
+++ b/services/viz/public/cpp/compositing/surface_id_struct_traits.h
@@ -5,11 +5,11 @@
 #ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_ID_STRUCT_TRAITS_H_
 #define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_ID_STRUCT_TRAITS_H_
 
-#include "cc/ipc/frame_sink_id_struct_traits.h"
 #include "cc/ipc/local_surface_id_struct_traits.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
 #include "components/viz/common/surfaces/surface_id.h"
+#include "services/viz/public/cpp/compositing/frame_sink_id_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/surface_id.mojom-shared.h"
 
 namespace mojo {
diff --git a/services/viz/public/cpp/compositing/typemaps.gni b/services/viz/public/cpp/compositing/typemaps.gni
index 62b65ca8..da3048b1 100644
--- a/services/viz/public/cpp/compositing/typemaps.gni
+++ b/services/viz/public/cpp/compositing/typemaps.gni
@@ -9,6 +9,7 @@
   "//services/viz/public/cpp/compositing/filter_operation.typemap",
   "//services/viz/public/cpp/compositing/filter_operations.typemap",
   "//services/viz/public/cpp/compositing/copy_output_request.typemap",
+  "//services/viz/public/cpp/compositing/frame_sink_id.typemap",
   "//services/viz/public/cpp/compositing/render_pass.typemap",
   "//services/viz/public/cpp/compositing/resource_settings.typemap",
   "//services/viz/public/cpp/compositing/returned_resource.typemap",
diff --git a/services/viz/public/interfaces/BUILD.gn b/services/viz/public/interfaces/BUILD.gn
index a0b0a54..a20ba4f 100644
--- a/services/viz/public/interfaces/BUILD.gn
+++ b/services/viz/public/interfaces/BUILD.gn
@@ -13,6 +13,7 @@
     "compositing/copy_output_request.mojom",
     "compositing/filter_operation.mojom",
     "compositing/filter_operations.mojom",
+    "compositing/frame_sink_id.mojom",
     "compositing/quads.mojom",
     "compositing/render_pass.mojom",
     "compositing/resource_settings.mojom",
diff --git a/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom b/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
index 54fe43e..c998d68 100644
--- a/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
+++ b/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
@@ -4,11 +4,9 @@
 
 module viz.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
 import "services/viz/public/interfaces/compositing/begin_frame_args.mojom";
 import "services/viz/public/interfaces/compositing/compositor_frame.mojom";
-import "services/viz/public/interfaces/compositing/copy_output_request.mojom";
 import "services/viz/public/interfaces/compositing/returned_resource.mojom";
 import "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
diff --git a/services/viz/public/interfaces/compositing/frame_sink_id.mojom b/services/viz/public/interfaces/compositing/frame_sink_id.mojom
new file mode 100644
index 0000000..580fa11b
--- /dev/null
+++ b/services/viz/public/interfaces/compositing/frame_sink_id.mojom
@@ -0,0 +1,10 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module viz.mojom;
+
+struct FrameSinkId {
+  uint32 client_id;
+  uint32 sink_id;
+};
diff --git a/services/viz/public/interfaces/compositing/shared_quad_state.mojom b/services/viz/public/interfaces/compositing/shared_quad_state.mojom
index 25e9b0d..a6d8222 100644
--- a/services/viz/public/interfaces/compositing/shared_quad_state.mojom
+++ b/services/viz/public/interfaces/compositing/shared_quad_state.mojom
@@ -22,6 +22,10 @@
   gfx.mojom.Rect clip_rect;
 
   bool is_clipped;
+
+  // Indicates whether the quads share this sqs contains opaque content.
+  bool are_contents_opaque;
+
   float opacity;
   // TODO(fsamuel): Change this to an SkXfermode enum once native enums are
   // supported.
diff --git a/services/viz/public/interfaces/compositing/surface_id.mojom b/services/viz/public/interfaces/compositing/surface_id.mojom
index fcc991f8..e41f262 100644
--- a/services/viz/public/interfaces/compositing/surface_id.mojom
+++ b/services/viz/public/interfaces/compositing/surface_id.mojom
@@ -4,8 +4,8 @@
 
 module viz.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
+import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 
 // A surface ID is composed of two parts: a FrameSinkID, and a LocalSurfaceId.
 // The FrameSinkId uniquely identifies the FrameSink associated with the
@@ -15,6 +15,6 @@
 // The LocalSurfaceId are allocated by the client using any scheme
 // that avoids duplicates and makes IDs unguessable respectively.
 struct SurfaceId {
-  cc.mojom.FrameSinkId frame_sink_id;
+  FrameSinkId frame_sink_id;
   cc.mojom.LocalSurfaceId local_surface_id;
 };
diff --git a/services/viz/public/interfaces/compositing/surface_sequence.mojom b/services/viz/public/interfaces/compositing/surface_sequence.mojom
index d23159f..7d59501 100644
--- a/services/viz/public/interfaces/compositing/surface_sequence.mojom
+++ b/services/viz/public/interfaces/compositing/surface_sequence.mojom
@@ -4,12 +4,12 @@
 
 module viz.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
+import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 
 // A per-surface-namespace sequence number that's used to coordinate
 // dependencies between frames. A sequence number may be satisfied once, and
 // may be depended on once.
 struct SurfaceSequence {
-  cc.mojom.FrameSinkId frame_sink_id;
+  FrameSinkId frame_sink_id;
   uint32 sequence;
 };
diff --git a/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom b/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom
index 124d8be..a10ad184 100644
--- a/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom
+++ b/services/viz/public/interfaces/hit_test/hit_test_region_list.mojom
@@ -4,8 +4,8 @@
 
 module viz.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
+import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_id.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/gfx/mojo/transform.mojom";
@@ -35,7 +35,7 @@
   uint32 flags;
 
   // FrameSinkId of this region.
-  cc.mojom.FrameSinkId frame_sink_id;
+  FrameSinkId frame_sink_id;
 
   // LocalSurfaceId is required when flags include kHitTestChildSurface.
   cc.mojom.LocalSurfaceId? local_surface_id;
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index e3b5554..60995bf 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -220,10 +220,6 @@
 #define SK_SUPPORT_LEGACY_TILED_BITMAPS
 #endif
 
-#ifndef SK_JUMPER_LEGACY_X86_8BIT
-#define SK_JUMPER_LEGACY_X86_8BIT
-#endif
-
 #ifndef SK_LEGACY_SUPPORT_INTEGER_SMALL_RADII
 #define SK_LEGACY_SUPPORT_INTEGER_SMALL_RADII
 #endif
diff --git a/storage/browser/test/test_file_system_context.cc b/storage/browser/test/test_file_system_context.cc
index 0f003f1..074be842 100644
--- a/storage/browser/test/test_file_system_context.cc
+++ b/storage/browser/test/test_file_system_context.cc
@@ -24,18 +24,21 @@
   additional_providers.push_back(base::MakeUnique<TestFileSystemBackend>(
       base::ThreadTaskRunnerHandle::Get().get(), base_path));
   return CreateFileSystemContextWithAdditionalProvidersForTesting(
-      quota_manager_proxy, std::move(additional_providers), base_path);
+      base::ThreadTaskRunnerHandle::Get().get(),
+      base::ThreadTaskRunnerHandle::Get().get(), quota_manager_proxy,
+      std::move(additional_providers), base_path);
 }
 
 storage::FileSystemContext*
 CreateFileSystemContextWithAdditionalProvidersForTesting(
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    scoped_refptr<base::SequencedTaskRunner> file_task_runner,
     storage::QuotaManagerProxy* quota_manager_proxy,
     std::vector<std::unique_ptr<storage::FileSystemBackend>>
         additional_providers,
     const base::FilePath& base_path) {
   return new storage::FileSystemContext(
-      base::ThreadTaskRunnerHandle::Get().get(),
-      base::ThreadTaskRunnerHandle::Get().get(),
+      io_task_runner.get(), file_task_runner.get(),
       storage::ExternalMountPoints::CreateRefCounted().get(),
       make_scoped_refptr(new MockSpecialStoragePolicy()).get(),
       quota_manager_proxy, std::move(additional_providers),
diff --git a/storage/browser/test/test_file_system_context.h b/storage/browser/test/test_file_system_context.h
index f6f5f9b..5b103af 100644
--- a/storage/browser/test/test_file_system_context.h
+++ b/storage/browser/test/test_file_system_context.h
@@ -26,6 +26,8 @@
 // |additional_providers| if needed.
 storage::FileSystemContext*
 CreateFileSystemContextWithAdditionalProvidersForTesting(
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    scoped_refptr<base::SequencedTaskRunner> file_task_runner,
     storage::QuotaManagerProxy* quota_manager_proxy,
     std::vector<std::unique_ptr<storage::FileSystemBackend>>
         additional_providers,
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index 861a1f3..5187e92 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -177,7 +177,7 @@
 enum <i>enumname</i> : <i>base-type</i></code></td>
 <td>Provide enums as full classes, with no implicit conversion to booleans or integers. Provide an explicit underlying type for enum classes and regular enums.</td>
 <td><a href="http://en.cppreference.com/w/cpp/language/enum">enumeration declaration</a></td>
-<td>Enum classes are still enums and follow enum naming rules (which means SHOUTY_CASE in the <a href="http://www.chromium.org/developers/coding-style#Naming">Chromium Style Guide</a>). <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/Q5WmkAImanc">Discussion thread</a></td>
+<td>Enum classes are still enums and follow enum naming rules. <a href="https://google.github.io/styleguide/cppguide.html#Enumerator_Names">Google Style Guide</a>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/Q5WmkAImanc">Discussion thread</a></td>
 </tr>
 
 <tr>
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 4a3d72e8..7c1461b 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -615,6 +615,9 @@
     ]
   },
   "Android N5X Swarm Builder": {
+    "additional_compile_targets": [
+      "monochrome_static_initializers"
+    ],
     "gtest_tests": [
       {
         "args": [
@@ -4988,7 +4991,7 @@
             }
           ],
           "expiration": 10800,
-          "hard_timeout": 960,
+          "hard_timeout": 1920,
           "output_links": [
             {
               "link": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0d1cd38..d97c4fc5 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -10890,6 +10890,21 @@
       }
     ]
   },
+  "Jumbo Linux x64": {
+    "additional_compile_targets": [
+      "all"
+    ]
+  },
+  "Jumbo Mac": {
+    "additional_compile_targets": [
+      "all"
+    ]
+  },
+  "Jumbo Win x64": {
+    "additional_compile_targets": [
+      "all"
+    ]
+  },
   "Linux ARM": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index e42e10f..03cfaab 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -769,7 +769,6 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -801,7 +800,6 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -833,7 +831,6 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -865,7 +862,6 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -905,7 +901,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -931,7 +926,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -957,7 +951,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -983,7 +976,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -1013,7 +1005,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -1045,7 +1036,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -1085,7 +1075,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -1111,7 +1100,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -1137,7 +1125,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -1164,7 +1151,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -2310,7 +2296,6 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -2347,7 +2332,6 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -2373,58 +2357,13 @@
   },
   "GPU Linux Builder": {},
   "GPU Linux Builder (dbg)": {},
+  "GPU Linux Ozone Builder": {},
   "GPU Mac Builder": {},
   "GPU Mac Builder (dbg)": {},
   "GPU Win Builder": {},
   "GPU Win Builder (dbg)": {},
   "GPU Win x64 Builder": {},
   "GPU Win x64 Builder (dbg)": {},
-  "Linux ChromiumOS Builder": {
-    "additional_compile_targets": [
-      "All"
-    ]
-  },
-  "Linux ChromiumOS Ozone (Intel)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": false,
-          "dimension_sets": [
-            {
-              "gpu": "8086:1912",
-              "os": "Ubuntu"
-            }
-          ]
-        },
-        "test": "angle_end2end_tests",
-        "use_xvfb": false
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0",
-          "--no-xvfb"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": false,
-          "dimension_sets": [
-            {
-              "gpu": "8086:1912",
-              "os": "Ubuntu"
-            }
-          ]
-        },
-        "test": "angle_unittests",
-        "use_xvfb": false
-      }
-    ],
-    "isolated_scripts": []
-  },
-  "Linux ChromiumOS Ozone Builder": {},
   "Linux Debug (NVIDIA)": {
     "gtest_tests": [
       {
@@ -2967,6 +2906,46 @@
       }
     ]
   },
+  "Linux Ozone (Intel)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1912",
+              "os": "Ubuntu"
+            }
+          ]
+        },
+        "test": "angle_end2end_tests",
+        "use_xvfb": false
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--no-xvfb"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1912",
+              "os": "Ubuntu"
+            }
+          ]
+        },
+        "test": "angle_unittests",
+        "use_xvfb": false
+      }
+    ],
+    "isolated_scripts": []
+  },
   "Linux Release (AMD R7 240)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 4dd3445..fb194a1 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -6,7 +6,8 @@
   },
   "Android Builder": {
     "additional_compile_targets": [
-      "cronet_test_instrumentation_apk"
+      "cronet_test_instrumentation_apk",
+      "monochrome_static_initializers"
     ]
   },
   "Android Clang Builder (dbg)": {
@@ -4214,6 +4215,13 @@
           ],
           "shards": 6
         }
+      },
+      {
+        "isolate_name": "webkit_python_tests",
+        "name": "webkit_python_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
       }
     ],
     "scripts": [
@@ -4226,10 +4234,6 @@
         "script": "webkit_lint.py"
       },
       {
-        "name": "webkit_python_tests",
-        "script": "webkit_python_tests.py"
-      },
-      {
         "name": "checkperms",
         "script": "checkperms.py"
       }
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 934998562..5bd969a 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -1700,16 +1700,19 @@
           "can_use_on_swarming_builders": true,
           "shards": 2
         }
+      },
+      {
+        "isolate_name": "webkit_python_tests",
+        "name": "webkit_python_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
       }
     ],
     "scripts": [
       {
         "name": "webkit_lint",
         "script": "webkit_lint.py"
-      },
-      {
-        "name": "webkit_python_tests",
-        "script": "webkit_python_tests.py"
       }
     ]
   },
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 3667e81..ce52121 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -1650,16 +1650,19 @@
           "can_use_on_swarming_builders": true,
           "shards": 2
         }
+      },
+      {
+        "isolate_name": "webkit_python_tests",
+        "name": "webkit_python_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
       }
     ],
     "scripts": [
       {
         "name": "webkit_lint",
         "script": "webkit_lint.py"
-      },
-      {
-        "name": "webkit_python_tests",
-        "script": "webkit_python_tests.py"
       }
     ]
   },
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index 7a0cb4e4..29ac18d9 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -22,7 +22,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -48,7 +47,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -74,7 +72,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -100,7 +97,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -132,7 +128,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -172,7 +167,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -198,7 +192,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -224,7 +217,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
@@ -251,7 +243,6 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "android_devices": "1",
               "device_os": "M",
               "device_type": "bullhead",
               "os": "Android"
diff --git a/testing/buildbot/filters/fuchsia.content_unittests.filter b/testing/buildbot/filters/fuchsia.content_unittests.filter
index 5a8b308..7b369761 100644
--- a/testing/buildbot/filters/fuchsia.content_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.content_unittests.filter
@@ -1,6 +1,5 @@
 # Being ported, https://crbug.com/754861.
 
--ChildMemoryCoordinatorImplTest.MultipleClients
 -LegacyInputRouterImplTest.AckedTouchEventState
 -MediaStreamManagerTest.MakeAndCancelMultipleRequests
 -MediaStreamManagerTest.MakeMediaAccessRequest
@@ -79,3 +78,9 @@
 -QuotaPolicyCookieStoreTest.TestDestroyOnBackgroundThread
 -QuotaPolicyCookieStoreTest.TestPersistence
 -QuotaPolicyCookieStoreTest.TestPolicy
+
+# https://crbug.com/761214
+-RendererAudioOutputStreamFactoryIntegrationTest.StreamIntegrationTest
+
+# https://crbug.com/762125
+-VideoCaptureBufferPoolTest.BufferPool/*
diff --git a/testing/buildbot/filters/fuchsia.net_unittests.filter b/testing/buildbot/filters/fuchsia.net_unittests.filter
index cc4780f..584c006 100644
--- a/testing/buildbot/filters/fuchsia.net_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.net_unittests.filter
@@ -1,26 +1,32 @@
-# TODO(fuchsia): Fix these tests and remove the filter. crbug.com/731302 .
+# TODO(fuchsia): Fix these tests and remove the filter. https://crbug.com/731302 .
 -*HTTPS*
 -*QuicEndToEndTest.Large*
 -*QuicEndToEndTest.TokenBinding*
 -*QuicEndToEndTest.Uber*
 -CertVerifyProcInternalTest.*
 -CloseOnConnectHttpServerTest.ServerImmediatelyClosesConnection
--DiskCacheEntryTest*AsyncIO*  # Flaky on the bots
--DiskCacheTest.BlockFiles_Grow  # Flaky timeouts
--HttpCache.RangeGET_ParallelValidationDifferentRanges  # https://crbug.com/755552
--HttpCache.RangeGET_ParallelValidationOverlappingRanges  # https://crbug.com/758221
--HttpNetworkTransactionTest.UploadUnreadableFile
 -HttpServerTest.*
 -NetworkInterfacesTest.GetNetworkList
--NetworkQualityEstimatorTest*
--Proxy*
+-ProxyScriptFetcherImplTest.Priority
 -PythonUtils*
--ReportingUploader*
--SpdyNetworkTransactionTest.UnreadableFilePost
 -SQLite*
--SSL*
 -TokenBindingURLRequest*
 -UnixDomain*Socket*
--URLFetcher*
--URLRequest*
+-URLRequest*FTP*
+-URLRequestQuic*
+-URLRequestTestHTTP.HeadersCallbacks
 -WebSocket*
+
+# Following tests pass locally, but flake on bots.
+-DiskCacheEntryTest*AsyncIO*
+-DiskCacheTest.BlockFiles_Grow
+-DiskCacheBackendTest.SimpleCacheDeleteQuickly
+-URLRequestTestHTTP.GetTest_ManyCookies
+
+# https://crbug.com/755552
+-HttpCache.RangeGET_ParallelValidationDifferentRanges
+-HttpCache.RangeGET_ParallelValidationOverlappingRanges
+
+# base::MakeFileUnreadable() doesn't work. https://crbug.com/759853
+-HttpNetworkTransactionTest.UploadUnreadableFile
+-SpdyNetworkTransactionTest.UnreadableFilePost
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index 5faf3d254..16560e0 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -87,8 +87,6 @@
 -PreviewsStateResourceDispatcherHostBrowserTest.ShouldEnableLoFiModeReload
 -PreviewsStateResourceDispatcherHostBrowserTest.ShouldEnableLoFiModeReloadDisableLoFi
 -RenderFrameHostImplBrowserTest.StreamHandleReleasedOnRendererCrash
--RenderFrameMessageFilterBrowserTest.Cookies
--RenderFrameMessageFilterBrowserTest.SameSiteCookies
 -RenderThreadImplBrowserTest.NonResourceDispatchIPCTasksDontGoThroughScheduler
 -RenderThreadImplBrowserTest.ResourceDispatchIPCTasksGoThroughScheduler
 -RenderViewBrowserTest.ConfirmCacheInformationPlumbed
@@ -134,10 +132,6 @@
 -WebContentsImplBrowserTest.UserAgentOverride
 -WorkerFetchTest.*
 
-# crbug.com/760581
--ResourceFetcherTests.ResourceFetcherTimeout
--ResourceFetcherTests.ResourceFetcherDeletedInCallback
-
 # content/network/url_loader_impl.cc should handle failure in
 # URLLoaderImpl::OnResponseBodyStreamRead(). Note this is flaky, so it will pass
 # sometimes.
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index e09f5bb..5a5445cef 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -754,6 +754,10 @@
     "label": "//mojo/android:mojo_test_apk",
     "type": "console_test_launcher",
   },
+  "monochrome_static_initializers": {
+    "label": "//chrome/android:monochrome_static_initializers",
+    "type": "additional_compile_target",
+  },
   "mus_browser_tests": {
     "label": "//chrome/test:mus_browser_tests",
     "label_type": "group",
@@ -1135,6 +1139,14 @@
       "--results-directory", "${ISOLATED_OUTDIR}/layout-test-results",
     ],
   },
+  "webkit_python_tests": {
+    "label": "//:webkit_python_tests",
+    "type": "script",
+    "script": "//testing/scripts/run_isolated_script_test.py",
+    "args": [
+      "../../third_party/WebKit/Tools/Scripts/test-webkitpy"
+    ]
+  },
   "webkit_unit_tests": {
     "label": "//third_party/WebKit/Source/controller:webkit_unit_tests",
     "type": "console_test_launcher",
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f3e9c609..0c3e5c17 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -372,6 +372,31 @@
             ]
         }
     ],
+    "BookmarkInProductHelp": [
+        {
+            "platforms": [
+                "linux",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_1",
+                    "params": {
+                        "availability": "any",
+                        "event_bookmark_added": "name:bookmark_added;comparator:==0;window:3650;storage:3650",
+                        "event_bookmark_session_time_met": "name:bookmark_session_time_met;comparator:>=1;window:3650;storage:3650",
+                        "event_trigger": "name:bookmark_trigger;comparator:any;window:3650;storage:3650",
+                        "event_used": "name:bookmark_clicked;comparator:any;window:3650;storage:3650",
+                        "session_rate": "<=3",
+                        "x_promo_string": "IDS_BOOKMARK_PROMO_1"
+                    },
+                    "enable_features": [
+                        "IPH_Bookmark"
+                    ]
+                }
+            ]
+        }
+    ],
     "BrowserBlacklist": [
         {
             "platforms": [
@@ -1065,6 +1090,18 @@
             ]
         }
     ],
+    "ExternalDataUseObserver": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled"
+                }
+            ]
+        }
+    ],
     "GoogleBrandedContextMenu": [
         {
             "platforms": [
@@ -1184,25 +1221,6 @@
             ]
         }
     ],
-    "IdleTimeSpellChecking": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "linux",
-                "mac",
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "IdleTimeSpellChecking"
-                    ]
-                }
-            ]
-        }
-    ],
     "ImportantSitesInCBD": [
         {
             "platforms": [
@@ -1507,7 +1525,7 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled-ChromeReader-ReducedPersistent",
+                    "name": "ReducedPersistent",
                     "enable_features": [
                         "NTPArticleSuggestions"
                     ]
@@ -2433,21 +2451,6 @@
             ]
         }
     ],
-    "ReducedSoftTileMemoryLimitOnLowEndAndroid": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ReducedSoftTileMemoryLimitOnLowEndAndroid"
-                    ]
-                }
-            ]
-        }
-    ],
     "RefreshTokenDeviceId": [
         {
             "platforms": [
@@ -2883,6 +2886,21 @@
             ]
         }
     ],
+    "SkipCompositingSmallScrollers": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "SkipCompositingSmallScrollers"
+                    ]
+                }
+            ]
+        }
+    ],
     "SocketReadIfReady": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 132bbff7..d2cc1f6f 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -4347,6 +4347,7 @@
 crbug.com/591099 fast/block/positioning/inline-block-relposition.html [ Failure Pass ]
 crbug.com/591099 fast/block/positioning/leftmargin-topmargin.html [ Failure ]
 crbug.com/591099 fast/block/positioning/move-with-auto-width.html [ Failure ]
+crbug.com/591099 fast/block/positioning/offsetLeft-offsetTop-multicolumn.html [ Failure ]
 crbug.com/591099 fast/block/positioning/offsetLeft-relative-iframe.html [ Crash Failure ]
 crbug.com/591099 fast/block/positioning/offsetLeft-relative-td.html [ Crash Failure ]
 crbug.com/591099 fast/block/positioning/padding-percent.html [ Crash Failure ]
@@ -9309,8 +9310,6 @@
 crbug.com/757767 fast/multicol/change-height.html [ Crash ]
 crbug.com/591099 fast/multicol/client-rect-after-spanner.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/client-rect-nested.html [ Failure Timeout ]
-crbug.com/591099 fast/multicol/client-rect-overflowing-multicol-2-columns.html [ Failure ]
-crbug.com/591099 fast/multicol/client-rect-overflowing-multicol.html [ Failure ]
 crbug.com/591099 fast/multicol/client-rect-trailing-column.html [ Failure ]
 crbug.com/757767 fast/multicol/client-rects-crossing-boundaries-nested.html [ Timeout ]
 crbug.com/591099 fast/multicol/client-rects-crossing-boundaries.html [ Failure Timeout ]
@@ -9329,7 +9328,6 @@
 crbug.com/591099 fast/multicol/composited-layer-multiple-fragments.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-layer-nested.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-layer-single-fragment.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-layer-will-change.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-layer.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-opacity-2nd-and-3rd-column.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-relpos-clipped.html [ Failure ]
@@ -9372,7 +9370,6 @@
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-spanner-with-inner-multicol-with-spanner-crash.html [ Failure ]
 crbug.com/757767 fast/multicol/dynamic/insert-spanner-before-content.html [ Crash ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-between-out-of-flow-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/insert-spanner-between-out-of-flow.html [ Failure ]
 crbug.com/757767 fast/multicol/dynamic/insert-spanner-into-content.html [ Crash ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-into-stf-constrained-width.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-into-stf-unconstrained-width.html [ Failure ]
@@ -9384,6 +9381,7 @@
 crbug.com/757767 fast/multicol/dynamic/insert-spanner-pseudo-before.html [ Crash ]
 crbug.com/591099 fast/multicol/dynamic/invalid-spanner-container-becomes-valid.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/multicol-with-abspos-svg-with-foreignobject-with-multicol-crash.html [ Failure ]
+crbug.com/591099 fast/multicol/dynamic/relayout-abspos-in-relpos-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/relpos-becomes-static-has-abspos.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/remove-abspos-next-to-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/remove-and-insert-block-after-spanner.html [ Failure ]
@@ -9467,7 +9465,6 @@
 crbug.com/591099 fast/multicol/hit-test-float.html [ Failure ]
 crbug.com/591099 fast/multicol/hit-test-gap-between-pages-flipped.html [ Failure ]
 crbug.com/591099 fast/multicol/hit-test-gap-between-pages.html [ Failure ]
-crbug.com/591099 fast/multicol/hit-test-translate-z.html [ Failure ]
 crbug.com/757767 fast/multicol/huge-column-count.html [ Crash Timeout ]
 crbug.com/757767 fast/multicol/huge-column-gap-crash.html [ Crash ]
 crbug.com/591099 fast/multicol/image-inside-nested-blocks-with-border.html [ Failure ]
@@ -9556,14 +9553,11 @@
 crbug.com/591099 fast/multicol/newmulticol/breaks-2-columns-3-no-balancing.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/breaks-2-columns-3.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/breaks-3-columns-3.html [ Failure Timeout ]
-crbug.com/591099 fast/multicol/newmulticol/clipping-overflow-hidden.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/clipping-top-overflow.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/clipping.html [ Failure ]
-crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-auto.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-balance-2.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-balance.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-lr.html [ Failure ]
-crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-rl.html [ Failure ]
 crbug.com/757767 fast/multicol/newmulticol/leading-margin.html [ Timeout ]
 crbug.com/757767 fast/multicol/newmulticol/multicol-becomes-regular-block.html [ Crash ]
 crbug.com/757767 fast/multicol/newmulticol/orphans-and-widows-balance.html [ Crash ]
@@ -9594,7 +9588,6 @@
 crbug.com/591099 fast/multicol/pageLogicalOffset-vertical.html [ Failure Pass ]
 crbug.com/757767 fast/multicol/paged-becomes-multicol-auto-height.html [ Crash ]
 crbug.com/757767 fast/multicol/paged-becomes-multicol-fixed-height.html [ Crash ]
-crbug.com/591099 fast/multicol/paged-becomes-multicol-with-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/paged-in-multicol-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/paginate-block-replaced.html [ Failure ]
 crbug.com/591099 fast/multicol/paginated-layer-crash.html [ Failure ]
@@ -9605,7 +9598,6 @@
 crbug.com/757767 fast/multicol/pushed-line-affected-by-float.html [ Crash ]
 crbug.com/757767 fast/multicol/regular-block-becomes-multicol.html [ Crash ]
 crbug.com/757767 fast/multicol/relayout-and-push-float.html [ Crash ]
-crbug.com/591099 fast/multicol/relpos-inside-inline-block.html [ Failure ]
 crbug.com/591099 fast/multicol/remove-all-children.html [ Failure ]
 crbug.com/591099 fast/multicol/remove-style-multicol-with-nested-layers.html [ Failure ]
 crbug.com/757767 fast/multicol/renderer-positioned-assert-crash.html [ Crash ]
@@ -9716,13 +9708,11 @@
 crbug.com/591099 fast/multicol/tall-content-in-inner-with-fixed-height.html [ Failure ]
 crbug.com/591099 fast/multicol/tall-float1.html [ Failure ]
 crbug.com/757767 fast/multicol/tall-float2.html [ Crash ]
-crbug.com/591099 fast/multicol/tall-line-in-short-block.html [ Failure ]
 crbug.com/757767 fast/multicol/tall-unbreakable-in-nested-crash.html [ Crash ]
 crbug.com/757767 fast/multicol/text-shadow-at-column-boundaries.html [ Crash ]
 crbug.com/591099 fast/multicol/textarea-with-placeholder-as-multicol-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/three-inner-rows.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/transform-inside-opacity.html [ Failure ]
-crbug.com/591099 fast/multicol/transform-with-fixedpos.html [ Failure ]
 crbug.com/757767 fast/multicol/triply-nested-with-padding-crash.html [ Crash ]
 crbug.com/591099 fast/multicol/unbreakable-block-too-tall-at-column-start.html [ Failure ]
 crbug.com/591099 fast/multicol/unbreakable-block-too-tall-to-fit.html [ Failure ]
@@ -10760,6 +10750,7 @@
 crbug.com/591099 fast/text/whitespace/pre-wrap-spaces-after-newline.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/select-new-line-with-line-break-normal.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/tab-character-basics.html [ Failure ]
+crbug.com/636993 fast/text/whitespace/text-align-justify-and-whitespace-pre.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/whitespace-in-pre.html [ Failure ]
 crbug.com/591099 fast/text/wide-preformatted.html [ Failure ]
 crbug.com/591099 fast/text/word-break.html [ Failure Pass ]
@@ -11044,10 +11035,9 @@
 crbug.com/757767 fragmentation/change-fragmentainer-height-line-float.html [ Crash ]
 crbug.com/591099 fragmentation/class-c-break-after-clearance.html [ Failure ]
 crbug.com/591099 fragmentation/collapsing-class-a-breakpoints.html [ Failure ]
-crbug.com/591099 fragmentation/content-preceding-first-fragmentainer.html [ Failure ]
-crbug.com/591099 fragmentation/first-child-large-top-margin.html [ Failure ]
 crbug.com/591099 fragmentation/float-after-forced-break.html [ Failure ]
 crbug.com/591099 fragmentation/float-pushed-to-next-fragmentainer-by-floats.html [ Failure ]
+crbug.com/591099 fragmentation/float-margin-top.html [ Failure ]
 crbug.com/591099 fragmentation/forced-break-clearance-unsplittable-content.html [ Failure ]
 crbug.com/591099 fragmentation/forced-break-inside-float.html [ Failure ]
 crbug.com/591099 fragmentation/fragmented-rowspan-alignment.html [ Failure ]
@@ -11055,16 +11045,13 @@
 crbug.com/591099 fragmentation/fragmented-table-cell.html [ Failure ]
 crbug.com/591099 fragmentation/fragmented-table-with-fixed-height.html [ Failure ]
 crbug.com/591099 fragmentation/image-block-as-first-child.html [ Failure ]
-crbug.com/591099 fragmentation/margin-bottom-at-top-of-fragmentainer.html [ Failure ]
 crbug.com/591099 fragmentation/margin-top-at-top-of-fragmentainer.html [ Failure ]
 crbug.com/591099 fragmentation/multi-line-cells-paginated.html [ Failure ]
 crbug.com/591099 fragmentation/multi-line-cells.html [ Failure ]
 crbug.com/591099 fragmentation/overflow-crossing-boundary.html [ Failure ]
-crbug.com/591099 fragmentation/overhanging-float-change-fragmentainer-height.html [ Failure ]
 crbug.com/591099 fragmentation/relayout-abspos.html [ Failure ]
 crbug.com/757767 fragmentation/remove-unbreakable-block-in-line-float.html [ Crash ]
 crbug.com/591099 fragmentation/repeating-thead-exceeds-page-size.html [ Failure ]
-crbug.com/591099 fragmentation/repeating-thead-multiple-tables-page-border.html [ Failure ]
 crbug.com/591099 fragmentation/repeating-thead-multiple-tables.html [ Failure Timeout ]
 crbug.com/591099 fragmentation/repeating-thead-no-room-for-content-row-on-first-page.html [ Failure ]
 crbug.com/591099 fragmentation/single-cell-repeating-thead-break-inside-avoid-content.html [ Failure ]
@@ -11078,6 +11065,7 @@
 crbug.com/591099 fragmentation/single-line-cells-multiple-tables-caption-repeating-thead-tfoot-with-border-spacing-at-top-of-row-3.html [ Failure Timeout ]
 crbug.com/591099 fragmentation/single-line-cells-multiple-tables-caption-repeating-thead-tfoot-with-border-spacing-at-top-of-row-4.html [ Failure ]
 crbug.com/591099 fragmentation/single-line-cells-multiple-tables-caption-repeating-thead-tfoot-with-border-spacing-at-top-of-row.html [ Failure ]
+crbug.com/591099 fragmentation/single-line-cells-multiple-tables-caption-repeating-thead-with-border-spacing-at-top-of-row-3.html [ Failure ]
 crbug.com/591099 fragmentation/single-line-cells-nested-repeating-thead-2.html [ Failure ]
 crbug.com/591099 fragmentation/single-line-cells-nested-repeating-thead-3.html [ Failure ]
 crbug.com/591099 fragmentation/single-line-cells-nested-repeating-thead-4.html [ Failure ]
@@ -13112,7 +13100,7 @@
 crbug.com/591099 http/tests/workers/worker-workerScriptNotThere.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/XMLHttpRequestException.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/abort-should-destroy-responseText.html [ Failure ]
-crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-data-saver.html [ Failure Timeout ]
+crbug.com/591099 http/tests/xmlhttprequest/chromium/access-control-preflight-data-saver.html [ Failure Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-preflight-request-headers-origin.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-response-with-body-sync.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/access-control-response-with-body.html [ Failure ]
@@ -16127,33 +16115,7 @@
 crbug.com/591099 vibration/vibration-exceptions.html [ Failure ]
 crbug.com/591099 vibration/vibration-iframe.html [ Timeout ]
 crbug.com/591099 vibration/vibration-patterns.html [ Failure ]
-crbug.com/591099 virtual/android/fast/rootscroller/browser-controls-gradient-background-iframe-scroller.html [ Failure ]
-crbug.com/591099 virtual/android/fast/rootscroller/browser-controls-gradient-background.html [ Failure ]
-crbug.com/591099 virtual/android/fast/rootscroller/scroll-non-descendant-of-root-scroller.html [ Failure ]
-crbug.com/591099 virtual/android/fast/rootscroller/set-root-scroller.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/exit-full-screen-iframe.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-cancel-nested.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-child-not-allowed-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-crash-offsetLeft.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-element-stack.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-frameset.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-iframe-allowed-nested.html [ Crash Timeout ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-iframe-allowed-video.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-iframe-allowed.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-iframe-not-allowed.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-iframe-without-allow-attribute-allowed-from-parent.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-line-boxes-crash.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-placeholder.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-request-removed.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-table-section.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-with-css-reference-filter.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/full-screen-with-flex-item.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/video-controls-override.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/video-controls-timeline.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/video-fail-to-enter-full-screen.html [ Crash Failure ]
-crbug.com/591099 virtual/android/fullscreen/video-scrolled-iframe.html [ Failure ]
-crbug.com/591099 virtual/android/fullscreen/video-specified-size.html [ Crash Failure ]
+crbug.com/591099 virtual/android/ [ Skip ]
 crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/OffscreenCanvas-constructor-in-worker.html [ Failure ]
 crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/OffscreenCanvas-invalid-args-in-worker.html [ Crash Failure ]
 crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/OffscreenCanvas-transferable-exceptions.html [ Crash Failure ]
@@ -16217,120 +16179,8 @@
 crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/webgl/texture-color-profile.html [ Crash Failure ]
 crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/webgl/webgl-texture-binding-preserved.html [ Crash Failure ]
 crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/webgl/webgl-viewport-parameters-preserved.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/12-55.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/182.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/2-comp.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/2-dht.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/23-55.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/55.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/alt-text-wrapping.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/animated-background-image-crash.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/animated-png.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-jpeg-with-color-profile.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-background-clip-text.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-border-image-source.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-border-radius.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-drag-image.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-filter.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-group.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-iframe.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-image-filter-all.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-image-object-fit.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-image-profile-match.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-image-pseudo-content.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-image-shape.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-image.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-layer-filter.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-layer.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-mask-image-svg.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-munsell-adobe-to-srgb.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/color-profile-svg-foreign-object.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-background-size.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-blending.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-invalidation.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-overflow-position.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-simple.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-sizing.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-svg-size-diff.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-svg-size.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/cross-fade-tiled.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/destroyed-image-load-event.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/drag-svg-image.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/embed-does-not-propagate-dimensions-to-object-ancestor.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/exif-orientation-css.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/exif-orientation-height-image-document.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/exif-orientation-image-document.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/exif-orientation.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/extra-image-in-image-document.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/favicon-as-image.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/gif-loop-count.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/gif-short-app-extension-string.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/gray-scale-jpeg-with-color-profile.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/gray-scale-png-with-color-profile.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/icon-0colors.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/icon-decoding.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-click-scale-restore-zoomed-image.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-css3-content-data.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-document-write-assert.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-empty-data.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-hover-display-alt.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-in-map.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-invalid-data.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-load-event-in-fragment.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-map-anchor-children.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-map-multiple-xhtml.xhtml [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-map-multiple.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-map-zoom-alt-content.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-map-zoom.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-page-injected-script-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-zoom-to-25.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/image-zoom-to-500.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-circle-focus-ring.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-in-positioned-container.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-explicitly-inherited-from-map.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-outline-color-not-inherited-from-map.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-outline-color.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-with-paint-root-offset.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-with-scale-transform.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-zero-outline-width.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring-zoom.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-focus-ring.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-overflowing-circle-focus-ring.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-overflowing-polygon-focus-ring.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-polygon-focus-ring.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/imagemap-scroll.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/link-body-content-imageDimensionChanged-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/load-img-with-empty-src.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/motion-jpeg-single-frame.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/pdf-as-background.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/pdf-as-tiled-background.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/percent-height-image.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/pixel-crack-image-background-webkit-transform-scale.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/png-extra-row-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/png-suite/test.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/png_per_row_alpha_decoding.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-0px-images-quirk.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-0px-images.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-10px-images.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-16px-images.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-1px-images.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-block-flow-images.html [ Failure Timeout ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-images-empty-alt.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/rendering-broken-images.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/script-counter-imageDimensionChanged-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/sprite-no-bleed.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/style-access-during-imageChanged-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/text-content-crash-2.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/text-content-crash.html [ Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/viewport-in-standalone-image-document.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/webp-flip.html [ Crash Failure ]
-crbug.com/591099 virtual/exotic-color-space/images/zoomed-img-size.html [ Crash Failure ]
-crbug.com/591099 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-no-reload.html [ Timeout ]
-crbug.com/591099 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-reload.html [ Timeout ]
-crbug.com/591099 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy.html [ Timeout ]
-crbug.com/591099 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-disabled.php [ Timeout ]
-crbug.com/591099 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-enabledforall.php [ Timeout ]
-crbug.com/591099 virtual/feature-policy-experimental-features/http/tests/feature-policy-experimental-features/vibrate-enabledforself.php [ Timeout ]
+crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
+crbug.com/591099 virtual/feature-policy-experimental-features/ [ Skip ]
 crbug.com/591099 virtual/gpu-rasterization/images/12-55.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/182.html [ Crash Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/2-comp.html [ Crash Failure ]
@@ -16508,161 +16358,8 @@
 crbug.com/591099 virtual/mojo-localstorage/ [ Skip ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
 crbug.com/591099 virtual/outofblink-cors/ [ Skip ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-scrolling-with-clip-path-text.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/accelerated-scrolling-with-clip-path.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/ancestor-overflow.html [ Crash Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/avoid-ancestor-clip-for-scroll-children.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-on-grandparent-composited-grandchild.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-on-parent-composited-grandchild.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-on-two-ancestors-composited-grandchild.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-outside-bounds-of-compositing-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/border-radius-styles-with-composited-child.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clip-descendents.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clip-parent-across-transform-boundary.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clip-parent-reset.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clipping-ancestor-with-accelerated-scrolling-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-layer-under-border-radius-under-composited-layer.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-nested-sticky-left.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/composited-scrolling-paint-phases.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-gains-scrollbars.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/content-loses-scrollbars.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/fixed-position-ancestor-clip.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/fractional-sized-scrolling-layer.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/grandchild-composited-with-border-radius-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/grandchild-with-border-radius-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/iframe-inside-overflow-clipping.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-filter.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/mask-with-small-content-rect.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/nested-border-radius-clipping.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/nested-render-surfaces-with-intervening-clip.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/nested-render-surfaces-with-rotation.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/nested-render-surfaces.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/nested-scrolling.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/no-excessive-clip-parent-if-parent-escaped.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch-toggle.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-auto-with-touch.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-clip-with-accelerated-scrolling-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-compositing-descendant.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-overlay-with-touch.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-positioning.html [ Failure Pass ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scroll-with-local-image-background.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scroll-with-pointer-events-toggle.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scroll.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/overflow-scrollbar-layers.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/parent-overflow.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/remove-overflow-crash2.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/reparented-scrollbars-non-sc-anc.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/resize-painting.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scaled-mask.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scaled-overflow.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-ancestor-update.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-neg-z-index-and-composited-child.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute-with-backdrop-filter.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-absolute.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scroll-parent-with-non-stacking-context-composited-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-painting.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbars-with-clipped-owner.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrolling-content-clip-to-viewport.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/siblings-composited-with-border-radius-ancestor-one-clipped.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/siblings-composited-with-border-radius-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/siblings-with-border-radius-ancestor.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch.html [ Crash Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/theme-affects-visual-overflow.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/tiled-mask.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/universal-accelerated-overflow-scroll.html [ Failure Timeout ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/zero-size-overflow.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/auto-scrollbar-fades-out.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/auto-scrollbar-fit-content.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/basic-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-appearance-property.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-enable-changes-thickness-with-iframe.html [ Failure Pass ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-with-incomplete-style.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/disabled-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/hidden-iframe-scrollbar-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/hidden-scrollbar-prevents-layout.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/listbox-scrollbar-combinations.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/overlay-scrollbars-within-overflow-scroll.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/resize-scales-with-dpi-150.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/rtl-resizer-position.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/rtl/overflow-scroll-rtl.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-buttons.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-click-does-not-blur-content.html [ Crash Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-content-crash.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-crash-on-refresh.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-miss-mousemove-disabled.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-miss-mousemove.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-orientation.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-owning-renderer-crash.html [ Failure Pass ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-percent-padding-crash.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-pointer-events.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbar-visibility-hidden.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/scrollbars-on-positioned-content.html [ Failure ]
-crbug.com/591099 virtual/prefer_compositing_to_lcd_text/scrollbars/viewport-scrollbar-corner-with-percent-padding-crash.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/rootscroller/scroll-non-descendant-of-root-scroller.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/rootscroller/set-root-scroller.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/abspos-relayout-overflow-style-change.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/content-box-smaller-than-scrollbar.html [ Crash Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/custom-scrollbar-style-applied.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/editor-command-scroll-page-scale.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/fractional-scroll-height-chaining.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/fractional-scroll-offset-document.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/hover-during-scroll.html [ Failure Timeout ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/html-element-client-rect-excludes-scrollbars.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/keyboard-scroll-page-scale.html [ Failure Timeout ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/overflow-auto-ltr.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/overflow-scrollability.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scroll-clears-fragment-anchor.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scroll-element-into-view.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scroll-into-view-collapsed-div.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scroll-max-value.html [ Crash Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scrollable-area-frame-overflow-hidden.html [ Crash Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scrollbar-mousedown-mouseup.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scrollbar-mousedown-move-mouseup.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scrollbar-prevent-default.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Timeout ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scrolling-apis-nan-scroll-position.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scrolling-apis-subpixel.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/auto-scrollbar-fades-out.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/auto-scrollbar-fit-content.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/basic-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/custom-scrollbar-changing-style-relayout-body-scrollablearea.html [ Crash Pass Timeout ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/custom-scrollbar-enable-changes-thickness-with-iframe.html [ Failure Pass ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/custom-scrollbar-with-incomplete-style.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/disabled-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/hidden-iframe-scrollbar-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/hidden-scrollbar-prevents-layout.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/listbox-scrollbar-combinations.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/overlay-scrollbars-within-overflow-scroll.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/rtl-resizer-position.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/rtl/overflow-scroll-rtl.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-added-during-drag.html [ Timeout ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-buttons.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-click-does-not-blur-content.html [ Crash Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-content-crash.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-crash-on-refresh.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-miss-mousemove-disabled.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-miss-mousemove.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-orientation.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-owning-renderer-crash.html [ Failure Pass ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-percent-padding-crash.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-pointer-events.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbar-visibility-hidden.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollbars/viewport-scrollbar-corner-with-percent-padding-crash.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollingcoordinator/non-fast-scrollable-region-nested.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollingcoordinator/non-fast-scrollable-region-scaled-iframe.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollingcoordinator/non-fast-scrollable-region-transformed-iframe.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollingcoordinator/non-fast-scrollable-transform-changed.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollingcoordinator/non-fast-scrollable-visibility-change.html [ Failure ]
-crbug.com/591099 virtual/rootlayerscrolls/scrollingcoordinator/plugin-with-wheel-handler.html [ Failure ]
+crbug.com/591099 virtual/prefer_compositing_to_lcd_text/ [ Skip ]
+crbug.com/591099 virtual/rootlayerscrolls/ [ Skip ]
 crbug.com/591099 virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure ]
 crbug.com/591099 virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Crash Failure ]
 crbug.com/591099 virtual/scalefactor150/fast/hidpi/static/drag-image.html [ Failure ]
@@ -16681,492 +16378,15 @@
 crbug.com/591099 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure ]
 crbug.com/591099 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ Failure ]
 crbug.com/591099 virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/basic-multi-touch-events-limited.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/basic-multi-touch-events.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/basic-single-touch-events.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-animation.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-global.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-iframes.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-many.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-squashing.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-trigger-commit.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/document-create-touch-list-crash.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/document-create-touch-list.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/document-create-touch.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/context-menu-on-long-press.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/context-menu-on-long-tap.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/context-menu-on-two-finger-tap-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/context-menu-on-two-finger-tap.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/focus-selectionchange-on-tap.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-click-on-inline-continations.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-click.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-dblclick.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-scroll-by-page.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-scroll-by-pixel.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-scroll-object-crash.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-scrollbar-textarea.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-active-state-hidden-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-active-state-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-active-state.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-cancel-hover-state.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-click-common-ancestor.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-div-removed.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-frame-move.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-frame-removed.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-frame-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-frame-scrolled.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-hover-clear.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-hover-state-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-mouse-events-between-frames.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-near-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-on-hover-element.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-paragraph-end.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-result.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-scrolled.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/long-press-drag-drop-touch-editing-combined-in-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/long-press-drag-drop-touch-editing-combined.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/long-press-focuses-frame.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/long-press-on-draggable-element-in-iframe-triggers-drag.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/long-press-on-draggable-element-in-nested-iframes-triggers-drag.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/long-press-on-draggable-element-triggers-drag.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/long-press-selects-word-when-touch-editing-enabled.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/no-context-menu-on-long-tap-alone.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/pad-gesture-cancel.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/pad-gesture-fling.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/right-click-gestures-set-cursor-at-correct-position.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/tap-target-matches-active.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-fling-with-page-scale.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-fully-scrolled-iframe-propagates.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-noscroll-body-propagated.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-noscroll-body-xhidden.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-noscroll-body-yhidden.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-noscroll-body.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-noscroll-div.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-noscroll-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div-not-propagated.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div-past-extent-diagonally.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div-past-extent.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div-removed.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div-scaled.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div-twice-past-extent.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div-zoomed.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-div.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-iframe-editable.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-iframe-not-propagated.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-iframe-past-extent.html [ Timeout ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-listbox.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-page-not-propagated.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-page-past-extent.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-page-zoomed.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-page.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/gesture/touch-gesture-scroll-shy-target.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/layout-triggers.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/multi-touch-grouped-targets.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/multi-touch-inside-iframes.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/multi-touch-inside-nested-iframes.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/multi-touch-partial-sequence.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/page-scaled-touch-gesture-click.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/send-oncancel-event.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/tap-highlight-color.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-action-range-input-csp.html [ Timeout ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-action-range-input.html [ Timeout ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-action-touch-handlers.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-before-pressing-spin-button.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-browser-zoom-scales-radius.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-event-dispatch-no-crash.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-event-source-device-event-sender.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-fractional-coordinates.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-handler-assert-input-range.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-handler-count.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-handler-iframe-plugin-assert.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-handler-iframe-unload-assert.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-input-element-change-documents.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-inside-iframe-scrolled.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-inside-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-over-hidden-iframe.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-rect-assert-first-layer-special.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-rect-crash-on-unpromote-layer.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-slider-no-js-touch-listener.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-slider.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-target-limited.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-target-move-documents.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/events/touch/touch-target.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/bordered-container-child-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/main-frame-pinch-scrolls-layout-viewport.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/main-frame-scroll-in-quirks-mode.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/main-frame-scroll-in-standards-mode.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/no-erroneous-auto-scroll-pinch-zoom.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/overflow-scroll-animates.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/overflow-scroll-loses-composited-scrolling.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/overflow-scroll-precise-deltas-dont-animate.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/overflow-scroll-root-frame-animates.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/overflow-scroll-triggers-layout.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/parse-scroll-behavior.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/scroll-into-view-scrolls-layout-viewport.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/smooth-scroll/keyboard-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/smooth-scroll/scroll-during-selection.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/smooth-scroll/track-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scroll-behavior/subframe-interrupted-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/abspos-relayout-overflow-style-change.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/content-box-smaller-than-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/custom-scrollbar-style-applied.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/editor-command-scroll-page-scale.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/fractional-scroll-height-chaining.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/fractional-scroll-offset-document.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/hover-during-scroll.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/html-element-client-rect-excludes-scrollbars.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/keyboard-scroll-page-scale.html [ Failure Timeout ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/overflow-auto-ltr.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/overflow-scrollability.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scroll-clears-fragment-anchor.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scroll-element-into-view.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scroll-into-view-collapsed-div.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scroll-max-value.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scrollable-area-frame-overflow-hidden.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scrollbar-mousedown-mouseup.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scrollbar-mousedown-move-mouseup.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scrollbar-prevent-default.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Timeout ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scrolling-apis-nan-scroll-position.html [ Failure ]
-crbug.com/591099 virtual/scroll_customization/fast/scrolling/scrolling-apis-subpixel.html [ Failure ]
-crbug.com/591099 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/fetch-frame-resource.https.html [ Crash Timeout ]
-crbug.com/591099 virtual/service-worker-script-streaming/http/tests/serviceworker/chromium/frame-detached-by-navigation.html [ Crash Failure ]
-crbug.com/591099 virtual/service-worker-script-streaming/http/tests/serviceworker/chromium/resolve-after-window-close.html [ Failure Timeout ]
-crbug.com/591099 virtual/service-worker-script-streaming/http/tests/serviceworker/chromium/service-worker-gc.html [ Failure ]
-crbug.com/591099 virtual/service-worker-script-streaming/http/tests/serviceworker/chromium/window-close-during-registration.html [ Failure ]
-crbug.com/591099 virtual/service-worker-script-streaming/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Timeout ]
+crbug.com/591099 virtual/scroll_customization/ [ Skip ]
+crbug.com/591099 virtual/service-worker-script-streaming/ [ Skip ]
 crbug.com/591099 virtual/spv2/compositing/framesets/composited-frame-alignment.html [ Failure ]
 crbug.com/591099 virtual/spv2/compositing/geometry/outline-change.html [ Failure Pass ]
 crbug.com/757767 virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash3.html [ Crash ]
 crbug.com/591099 virtual/spv2/paint/invalidation/margin.html [ Failure Pass ]
-crbug.com/591099 virtual/stable/fast/css3-text/css3-text-decoration/stable/getComputedStyle-text-decoration.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/anchor-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/anchor-frames-cross-origin.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/anchor-frames-gbk.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/anchor-frames-same-origin.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/anchor-frames.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/anchor-goback.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/back-to-slow-frame.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/cross-origin-fragment-navigation-is-async.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/form-targets-cross-site-frame-get.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/form-targets-cross-site-frame-no-referrer.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/form-targets-cross-site-frame-post.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/form-with-enctype-targets-cross-site-frame.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/forward-to-fragment-fires-onload.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/history-back-across-form-submission-to-fragment.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/javascriptlink-basic.html [ Crash Failure Timeout ]
-crbug.com/591099 virtual/stable/http/tests/navigation/javascriptlink-goback.html [ Crash Failure Timeout ]
-crbug.com/591099 virtual/stable/http/tests/navigation/lockedhistory-iframe.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/metaredirect-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/metaredirect-goback.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/no-referrer-reset.html [ Failure Timeout ]
-crbug.com/591099 virtual/stable/http/tests/navigation/onload-navigation-iframe-2.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/post-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/post-frames-goback1.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/post-frames.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/post-goback-same-url.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/post-goback1.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/post-goback2.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/postredirect-basic.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/postredirect-frames-goback1.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/postredirect-frames.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/postredirect-goback1.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/postredirect-goback2.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/redirect302-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/redirect302-goback.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/relativeanchor-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/relativeanchor-goback.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/rename-subframe-goback.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/replacestate-base-illegal.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/restore-form-state-https.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/same-and-different-back.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/same-origin-fragment-navigation-is-sync.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/slowmetaredirect-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/slowtimerredirect-basic.html [ Crash Failure Timeout ]
-crbug.com/591099 virtual/stable/http/tests/navigation/success200-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/success200-goback.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/success200-loadsame.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/success200-reload.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/timerredirect-basic.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/timerredirect-goback.html [ Crash Failure ]
-crbug.com/591099 virtual/stable/http/tests/navigation/useragent.php [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-allowance.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-cookie.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-cross-origin-redirect-blob.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-cross-origin-redirect.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-cross-origin.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-cross-origin.https.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-detached-no-crash.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/sendbeacon/beacon-same-origin.html [ Failure ]
-crbug.com/591099 virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Pass Timeout ]
-crbug.com/591099 virtual/stable/webexposed/custom-elements.html [ Failure ]
-crbug.com/591099 virtual/stable/webexposed/element-instance-property-listing.html [ Timeout ]
-crbug.com/591099 virtual/stable/webexposed/event-target-in-prototype.html [ Failure ]
-crbug.com/591099 virtual/stable/webexposed/global-constructors-attributes-worker.html [ Failure ]
-crbug.com/591099 virtual/stable/webexposed/global-constructors-attributes.html [ Failure ]
-crbug.com/591099 virtual/stable/webexposed/global-interface-listing-compositor-worker.html [ Failure ]
-crbug.com/591099 virtual/stable/webexposed/global-interface-listing-dedicated-worker.html [ Failure Timeout ]
-crbug.com/591099 virtual/stable/webexposed/global-interface-listing-shared-worker.html [ Failure Timeout ]
-crbug.com/591099 virtual/stable/webexposed/global-interface-listing.html [ Timeout ]
-crbug.com/591099 virtual/stable/webexposed/nonstable-css-properties.html [ Failure ]
-crbug.com/591099 virtual/stable/webexposed/permissions-attribute.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/3d/change-transform-in-end-event.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/animations/3d/state-at-end-event-transform.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/animations/animation-css-rule-types.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/animations-parsing.html [ Timeout ]
-crbug.com/591099 virtual/threaded/animations/computed-style.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/display-change-does-not-terminate-animation.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/animations/display-inline-style-adjust.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/animations/display-none-cancel-computedstyle.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/display-none-terminates-animation.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/events/animation-events-create.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/events/delay-start-event.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/events/negative-delay-events.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/events/play-state-initially-paused-start-event.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/hit-testing/inline-element-animation-end-hit-test.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/interpolation/backdrop-filter-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/background-image-interpolation.html [ Crash Pass Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/background-size-interpolation.html [ Pass Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/border-image-slice-interpolation.html [ Crash Pass Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/border-image-width-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/line-height-interpolation.html [ Crash Pass Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/svg-d-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/svg-stroke-dasharray-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/transform-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/webkit-clip-path-interpolation.html [ Crash Timeout ]
-crbug.com/757767 virtual/threaded/animations/interpolation/webkit-column-count-interpolation.html [ Crash Pass ]
-crbug.com/591099 virtual/threaded/animations/interpolation/webkit-transform-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/keyframes-rule.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/lazy-detached-animation-stop.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/play-state.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/prefixed/animation-inherit-initial-unprefixed.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/prefixed/keyframes-cssom-prefixed-02.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/prefixed/keyframes-cssom-unprefixed-02.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/responsive/interpolation/line-height-responsive.html [ Pass Timeout ]
-crbug.com/591099 virtual/threaded/animations/rotate-transform-equivalent.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/animations/skew-notsequential-compositor.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/animations/stability/animation-end-event-destroy-renderer.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/animation-iteration-event-destroy-renderer.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/animation-on-inline-crash.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/animation-start-event-destroy-renderer.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/element-animate-float-crash.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/animations/stability/empty-keyframe-animation-composited.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/empty-keyframes-composited.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/empty-keyframes.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/import-crash.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/length-zero-percent-crash.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/animations/stability/pause-crash.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/zero-duration-infinite-iterations.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/stability/zero-duration-large-start-delay.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/state-at-end-event.html [ Failure Pass Timeout ]
-crbug.com/591099 virtual/threaded/animations/svg-attribute-interpolation/svg-d-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/timing/animation-duration-infinite.html [ Failure ]
-crbug.com/591099 virtual/threaded/animations/timing/timing-model.html [ Pass Timeout ]
-crbug.com/591099 virtual/threaded/compositing/visibility/compositing-and-visibility-turned-off-together.html [ Failure ]
-crbug.com/591099 virtual/threaded/compositing/visibility/hidden-iframe.html [ Failure ]
-crbug.com/591099 virtual/threaded/compositing/visibility/layer-visible-content.html [ Failure ]
-crbug.com/591099 virtual/threaded/compositing/visibility/visibility-composited-transforms.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/compositing/visibility/visibility-composited.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/compositing/visibility/visibility-image-layers-dynamic.html [ Failure ]
-crbug.com/591099 virtual/threaded/compositing/visibility/visibility-on-distant-descendant.html [ Failure ]
-crbug.com/591099 virtual/threaded/compositing/webgl/webgl-background-color.html [ Failure ]
-crbug.com/591099 virtual/threaded/compositing/webgl/webgl-nonpremultiplied-blend.html [ Failure ]
-crbug.com/591099 virtual/threaded/compositing/webgl/webgl-reflection.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/compositorworker/request-animation-frame.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/bordered-container-child-scroll.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/first-scroll-runs-on-compositor.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/main-frame-pinch-scrolls-layout-viewport.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/main-frame-scroll-in-quirks-mode.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/main-frame-scroll-in-standards-mode.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/no-erroneous-auto-scroll-pinch-zoom.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/overflow-scroll-animates.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/overflow-scroll-loses-composited-scrolling.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/overflow-scroll-precise-deltas-dont-animate.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/overflow-scroll-root-frame-animates.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/overflow-scroll-triggers-layout.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/parse-scroll-behavior.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/scroll-into-view-scrolls-layout-viewport.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/smooth-scroll/fixed-background-in-iframe.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/smooth-scroll/keyboard-scroll.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added.html [ Failure ]
-crbug.com/591099 virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/anonymous-image-object.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/buffer-usage.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/category-filter.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/console-timeline.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/decode-resize.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/frame-model.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/hit-test.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/idle-callback.html [ Crash Failure Timeout ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/scroll-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/compile-script.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-gc-event.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-microtasks.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-open-function-call.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Crash Failure Pass ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-script-id.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-layout/timeline-layout.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-details.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-filtering.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-load-event.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-mark-timeline.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-model.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-parse-html.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-range-stats.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-record-reload.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-search.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-tree-search.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-trivial.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-window-filter.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-network/timeline-network-resource-details.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-network/timeline-network-resource.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-image.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-paint/update-layer-tree.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/parse-author-style-sheet.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-time-stamp.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-time.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-timer-fired-from-eval-call-site.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-timer.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-usertiming.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/tracing-timeline-load.html [ Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/worker-events.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/http/tests/devtools/tracing/worker-js-frames.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/printing/absolute-position-headers-and-footers.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/absolute-positioned.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/allowed-page-breaks.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/css2.1/page-break-after-000.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/css2.1/page-break-after-002.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/css2.1/page-break-after-003.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/css2.1/page-break-after-004.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/css2.1/page-break-before-000.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/custom-page-size-style.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/ellipsis-printing-style.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/fixed-positioned-but-static-headers-and-footers.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/fixed-positioned-headers-and-footers-absolute-covering-some-pages.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/fixed-positioned-headers-and-footers-clipped.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/fixed-positioned-headers-and-footers-inside-transform.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/printing/fixed-positioned-headers-and-footers-larger-than-page.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/fixed-positioned-headers-and-footers.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/fixed-positioned.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/forced-break-tree-dump-only.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/iframe-print.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/list-item-with-empty-first-line.html [ Crash Failure ]
-crbug.com/757767 virtual/threaded/printing/multicol-2-pages.html [ Crash ]
-crbug.com/757767 virtual/threaded/printing/multicol.html [ Crash ]
-crbug.com/591099 virtual/threaded/printing/no-content-empty-pages.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/numberOfPages.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-after-avoid.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-always.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-avoid.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-before-avoid.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-display-none.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-inside-avoid.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-margin-collapsed.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-orphans-and-widows.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-orphans.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-break-widows.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-count-layout-overflow.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-count-percentage-height.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-count-relayout-shrink.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/page-format-data.html [ Failure ]
-crbug.com/757767 virtual/threaded/printing/page-height-zero.html [ Crash ]
-crbug.com/591099 virtual/threaded/printing/page-rule-selection.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/pageNumerForElementById.html [ Failure ]
-crbug.com/757767 virtual/threaded/printing/pageProperty-with-multicol.html [ Crash ]
-crbug.com/591099 virtual/threaded/printing/pseudo-class-outside-page.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/quirks-percentage-height-body.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/quirks-percentage-height.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/respect-layout-overflow-from-pagination.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/return-from-printing-mode.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/simultaneous-position-float-change.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/single-line-must-not-be-split-into-two-pages.html [ Timeout ]
-crbug.com/591099 virtual/threaded/printing/standards-percentage-heights.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/printing/stretch-to-view-height.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/subframes-percentage-height.html [ Failure Pass ]
-crbug.com/591099 virtual/threaded/printing/tfoot-repeats-at-bottom-of-each-page-multiple-tables.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/tfoot-repeats-at-bottom-of-each-page.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ Failure ]
-crbug.com/591099 virtual/threaded/printing/thead-repeats-at-top-of-each-page.html [ Failure ]
-crbug.com/757767 virtual/threaded/printing/viewport-size-dependant-iframe-with-multicol-crash.html [ Crash ]
-crbug.com/591099 virtual/threaded/transitions/3d/interrupted-transition.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/bad-transition-shorthand-crash.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/inherit-other-props-do-not-affect-transition-property.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/inherit-other-props.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/inherit.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/interrupted-immediately.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/matched-transform-functions.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/opacity-transform-transitions-inside-iframe.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/transitions/opacity-transition-zindex.html [ Failure Pass Timeout ]
-crbug.com/591099 virtual/threaded/transitions/override-transition-crash.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/retargetted-transition.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/shadow.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-all-properties.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-attributes.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-container.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-destroy-iframe.html [ Crash Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-destroy-renderer.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-left.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-multiple-01.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-multiple-02.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-multiple-03.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-nested.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-prefixed-01.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-prefixed-02.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-prefixed-03.html [ Failure Timeout ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-rendering.html [ Failure Pass Timeout ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-set-none.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-transform.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-unprefixed-01.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-unprefixed-02.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-unprefixed-03.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-unprefixed-04.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-end-event-window.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-inherit-initial-unprefixed.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-property-explicit-initial.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-shape-outside-crash.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transition-transform-translate-calculated-length-crash.html [ Failure ]
-crbug.com/591099 virtual/threaded/transitions/transitions-parsing.html [ Failure Timeout ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Failure Pass ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheel-event-dispatch-event.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheel-fling-cancel.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheel-in-scrollbar.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheelevent-basic.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheelevent-constructor.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheelevent-ctrl.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheelevent-document-createevent.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheelevent-handler-count.html [ Failure ]
-crbug.com/591099 virtual/wheelscrolllatching/fast/events/wheel/wheelevent-mousewheel-interaction.html [ Failure ]
+crbug.com/591099 virtual/stable/ [ Skip ]
+crbug.com/591099 virtual/threaded/ [ Skip ]
+crbug.com/591099 virtual/wheelscrolllatching/ [ Skip ]
 crbug.com/591099 webaudio/BiquadFilter/tail-time-lowpass.html [ Timeout ]
 crbug.com/591099 webaudio/internals/audiocontext-lock-threading-race.html [ Failure ]
 crbug.com/591099 webaudio/internals/cycle-connection-gc.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 9be55de..07e18cc3 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -987,7 +987,6 @@
 # Less invalidations or different invalidations without pixel failures.
 # Some might be good. Some might be under-invalidations for which under-invalidation
 # checking failed.
-Bug(none) paint/invalidation/child-of-sub-pixel-offset-composited-layer.html [ Failure ]
 Bug(none) paint/invalidation/compositing/compositing-reason-removed.html [ Failure ]
 Bug(none) paint/invalidation/compositing/should-invoke-deferred-compositing.html [ Failure ]
 Bug(none) paint/invalidation/css-grid-layout/grid-item-z-index-change-repaint.html [ Failure ]
@@ -1784,6 +1783,15 @@
 crbug.com/738613 paint/invalidation/overflow-auto-in-overflow-auto-scrolled.html [ Failure ]
 crbug.com/738613 paint/invalidation/overflow-scroll-in-overflow-scroll-scrolled.html [ Failure ]
 
+# "flattenInheritedTransform" of FrameView scroll translation.
+Bug(none) paint/invalidation/animated-gif-background-offscreen-firstline.html [ Failure ]
+Bug(none) paint/invalidation/animated-gif-background-offscreen.html [ Failure ]
+Bug(none) paint/invalidation/animated-gif-offscreen.html [ Failure ]
+Bug(none) paint/invalidation/animated-png-offscreen.html [ Failure ]
+Bug(none) paint/invalidation/animated-webp-offscreen.html [ Failure ]
+Bug(none) paint/invalidation/svg/animated-svg-as-image-background-offscreen.html [ Failure ]
+Bug(none) paint/invalidation/svg/animated-svg-as-image-offscreen.html [ Failure ]
+
 # Unlike SPV1, there is no raster invalidation when a scrollbar layer disappears
 # because the scrollbar layer is completely composited. This will match the
 # SPV1 result once compositing reasons no longer cause the scrollbar to be
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index c2e8c3c..f8721b6 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -596,6 +596,7 @@
 # ====== DevTools test migration failures from here ======
 
 ### virtual/mojo-loading/http/tests/devtools
+crbug.com/667560 http/tests/devtools/console/console-search.js [ Skip ]
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/console/console-search.js [ Skip ]
 
 crbug.com/667560 http/tests/devtools/elements/styles-3/styles-change-node-while-editing.html [ Pass Failure ]
@@ -1759,6 +1760,11 @@
 crbug.com/761952 virtual/outofblink-cors/external/wpt/service-workers/service-worker/link-element-register-security-error.https.html [ Failure Pass ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html [ Failure ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html [ Failure ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/the-img-element/relevant-mutations.html [ Timeout ]
+crbug.com/626703 [ Android Linux Mac ] external/wpt/html/semantics/embedded-content/the-object-element/object-events.html [ Timeout ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/the-video-element/video_initially_paused.html [ Failure ]
 crbug.com/626703 external/wpt/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/payment-request/algorithms-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/payment-request/user-abort-algorithm-manual.https.html [ Skip ]
@@ -2258,6 +2264,7 @@
 crbug.com/626703 external/wpt/workers/opaque-origin.html [ Failure Crash Timeout ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-quirks-mode.html [ Pass Crash ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-standards-mode.html [ Pass Crash Failure ]
+crbug.com/762017 external/wpt/html/semantics/embedded-content/media-elements/video_loop_base.html [ Pass Crash ]
 
 # Other untriaged test failures, timeouts and crashes from newly-imported WPT tests.
 crbug.com/666703 external/wpt/html/browsers/sandboxing/sandbox-disallow-same-origin.html [ Timeout ]
@@ -2313,6 +2320,7 @@
 crbug.com/697971 [ Mac10.12 ] fast/text/flexbox-selection-nested.html [ Skip ]
 crbug.com/697971 [ Mac10.12 ] fast/text/flexbox-selection.html [ Skip ]
 crbug.com/678481 http/tests/inspector/appcache/appcache-manifest-with-non-existing-file.html [ Timeout Failure Pass ]
+crbug.com/678481 http/tests/inspector/appcache/appcache-iframe-manifests.html [ Timeout Failure Pass ]
 crbug.com/678481 virtual/mojo-loading/http/tests/inspector/appcache/appcache-iframe-manifests.html [ Timeout Failure Pass ]
 
 crbug.com/701047 [ Mac10.12 ] editing/caret/caret-color.html [ Failure ]
@@ -2356,8 +2364,8 @@
 
 crbug.com/660295 http/tests/devtools/elements/elements-panel-restore-selection-when-node-comes-later.html [ Pass Failure ]
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/elements/elements-panel-restore-selection-when-node-comes-later.html [ Pass Failure ]
-crbug.com/735245 http/tests/inspector/application-panel/storage-view-reports-quota.html [ Pass Timeout ]
-crbug.com/735245 virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota.html [ Pass Timeout ]
+crbug.com/735245 http/tests/inspector/application-panel/storage-view-reports-quota.html [ Pass Timeout Failure ]
+crbug.com/735245 virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota.html [ Pass Timeout Failure ]
 
 # [css-grid]
 crbug.com/659610 fast/css-grid-layout/grid-baseline.html [ Failure ]
@@ -2749,6 +2757,7 @@
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/sources/debugger-ui/watch-expressions-panel-switch.html [ Pass Timeout ]
 
 crbug.com/747751 http/tests/inspector/application-panel/resources-panel-resource-preview.html [ Failure Pass ]
+crbug.com/747751 virtual/mojo-loading/http/tests/inspector/application-panel/resources-panel-resource-preview.html [ Failure Pass ]
 
 crbug.com/689781 external/wpt/media-source/mediasource-duration.html [ Failure Pass ]
 
@@ -3633,20 +3642,38 @@
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.html [ Pass Failure Crash ]
 
 # Tests timing out on WebKit Linux Trusty MSAN
+crbug.com/760543 [ Linux Release ] http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/console-timeline.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/console-timeline.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-time/timeline-usertiming.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-time/timeline-usertiming.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint.html [ Pass Timeout ]
 
-# Tests failing on WebKit Mac10.11, WebKit Mac10.10, WebKit Mac10.9
-crbug.com/760967 [ Mac ] external/wpt/payment-request/payment-request-ctor-pmi-handling.https.html [ Pass Failure ]
-
 crbug.com/761891 [ Win7 Debug ] virtual/threaded/animations/transition-and-animation-3.html [ Pass Failure Timeout ]
+
+# Test flaky (crashing) on WebKit Android (Nexus4)
+crbug.com/762008 [ Android ] http/tests/appcache/abort-cache-onchecking-resource-404.html [ Pass Crash ]
+
+# Sheriff failure 2017-09-06
+crbug.com/762390 [ Android ] http/tests/devtools/console/only-one-deprecation-warning.html [ Pass Crash ]
+crbug.com/762423 [ Android ] http/tests/dom/create-contextual-fragment-from-svg-document-range.html [ Pass Crash ]
+crbug.com/762399 [ Android ] http/tests/cache/zero-length-xhr.html [ Pass Crash ]
+crbug.com/762486 [ Win7 Debug ] virtual/mojo-loading/http/tests/security/xss-DENIED-iframe-src-alias.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index 7735adb6..84efee2 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -202,71 +202,6 @@
 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-object-fixed.html [ Skip ]
 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-object-percentage.html [ Skip ]
 
-# crbug.com/498120: Using absolute URL links.
-external/wpt/html/semantics/embedded-content/media-elements/audio_loop_base.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/error-codes/error.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_canplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_canplay_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_loadstart.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_loadstart_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_canplaythrough.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_playing.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_order_loadstart_progress.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_pause.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_pause_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_play.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_play_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_playing.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_playing_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_progress.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_progress_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate_noautoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/autoplay-overrides-preload.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/networkState_during_loadstart.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/networkState_during_progress.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/paused_false_during_play.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/paused_true_during_pause.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplay.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplaythrough.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/readyState_during_playing.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html [ Skip ]
-external/wpt/html/semantics/embedded-content/media-elements/video_loop_base.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-canvas-element [ Skip ]
-external/wpt/html/semantics/embedded-content/the-embed-element/embed-dimension.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-03.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-img-element/relevant-mutations.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-object-element/object-events.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-object-element/object-fallback.html [ Skip ]
-external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_absolute.htm [ Skip ]
-external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_relative.htm [ Skip ]
-external/wpt/html/semantics/embedded-content/the-video-element/video_initially_paused.html [ Skip ]
-
 # The wpt tools (including manifest and wptserve) are checked in to
 # webkitpy/thirdparty/wpt so that we can manually update them and keep
 # a stable pinned version.
diff --git a/third_party/WebKit/LayoutTests/accessibility/clickable-expected.txt b/third_party/WebKit/LayoutTests/accessibility/clickable-expected.txt
index 5fec021..3bb90b56 100644
--- a/third_party/WebKit/LayoutTests/accessibility/clickable-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/clickable-expected.txt
@@ -30,6 +30,7 @@
 PASS isAXElementClickable('keydown-listener') is false
 PASS isAXElementClickable('click-listener') is true
 PASS isAXElementClickable('mousedown-listener') is true
+PASS isAXElementClickable('click-listener-on-ancestor') is false
 PASS axRole('empty-anchor') is 'AXRole: AXAnchor'
 PASS axRole('href-anchor') is 'AXRole: AXLink'
 PASS axRole('onclick-anchor') is 'AXRole: AXLink'
diff --git a/third_party/WebKit/LayoutTests/accessibility/clickable.html b/third_party/WebKit/LayoutTests/accessibility/clickable.html
index 8da8695..1b3c3ea 100644
--- a/third_party/WebKit/LayoutTests/accessibility/clickable.html
+++ b/third_party/WebKit/LayoutTests/accessibility/clickable.html
@@ -31,6 +31,9 @@
   <div id="keydown-listener">Key down listener</div>
   <div id="click-listener">Click listener</div>
   <div id="mousedown-listener">Mouse down listener</div>
+  <div id="ancestor-with-click-listener">
+    <div id="click-listener-on-ancestor">Click listener on ancestor</div>
+  </div>
   <div>
     <a id="empty-anchor" tabindex=0>Empty anchor</a>
     <a id="href-anchor" href="#">Anchor with href</a>
@@ -41,6 +44,7 @@
     document.getElementById('keydown-listener').addEventListener('keydown', function() {}, false);
     document.getElementById('click-listener').addEventListener('click', function() {}, false);
     document.getElementById('mousedown-listener').addEventListener('mousedown', function() {}, false);
+    document.getElementById('ancestor-with-click-listener').addEventListener('click', function() {}, false);
     document.getElementById('click-listener-anchor').addEventListener('click', function() {}, false);
   </script>
 </div>
@@ -87,6 +91,7 @@
     shouldBe("isAXElementClickable('keydown-listener')", "false");
     shouldBe("isAXElementClickable('click-listener')", "true");
     shouldBe("isAXElementClickable('mousedown-listener')", "true");
+    shouldBe("isAXElementClickable('click-listener-on-ancestor')", "false");
 
     shouldBe("axRole('empty-anchor')", "'AXRole: AXAnchor'");
     shouldBe("axRole('href-anchor')", "'AXRole: AXLink'");
diff --git a/third_party/WebKit/LayoutTests/compositing/absolute-inside-out-of-view-fixed-expected.txt b/third_party/WebKit/LayoutTests/compositing/absolute-inside-out-of-view-fixed-expected.txt
index 5f6bd009..e6cf1ca 100644
--- a/third_party/WebKit/LayoutTests/compositing/absolute-inside-out-of-view-fixed-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/absolute-inside-out-of-view-fixed-expected.txt
@@ -4,13 +4,26 @@
       "name": "LayoutView #document",
       "bounds": [785, 2513],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [0, 200],
       "bounds": [100, 100],
-      "contentsOpaque": true
+      "contentsOpaque": true,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt
index 88fe6ba..5356caf 100644
--- a/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/contents-opaque/layer-transform-expected.txt
@@ -8,17 +8,26 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
-      "position": [8, 8],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.866025403784439, 0.5, 0, 0],
         [-0.5, 0.866025403784439, 0, 0],
         [0, 0, 1, 0],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/compositing/culling/scrolled-within-boxshadow-expected.png
rename to third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/compositing/culling/translated-boxshadow-expected.png
rename to third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/compositing/culling/unscrolled-within-boxshadow-expected.png
rename to third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt
index 4e8300b7..1bc949f 100644
--- a/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/fixed-body-background-positioned-expected.txt
@@ -49,7 +49,8 @@
     {
       "name": "LayoutView #document",
       "bounds": [785, 3700],
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "Frame Vertical Scrollbar Layer",
@@ -58,6 +59,17 @@
       "contentsOpaque": true,
       "drawsContent": false
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt
index 3382920..39c0d0e0 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change-expected.txt
@@ -8,11 +8,10 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
-      "position": [8, 8],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -22,6 +21,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change.html b/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change.html
index 120ea334..147e938 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change.html
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/ancestor-overflow-change.html
@@ -29,11 +29,8 @@
       height: 100px;
       background-color: red;
     }
-
-    #layers {
-      opacity: 0; /* Hide from pixel results */
-    }
   </style>
+  <script src="../../resources/run-after-layout-and-paint.js"></script>
   <script type="text/javascript" charset="utf-8">
     if (window.testRunner) {
       testRunner.dumpAsTextWithPixelResults();
@@ -44,16 +41,16 @@
     {
       document.getElementById('container').className = 'changed';
 
-      if (window.testRunner)
-        document.getElementById('layers').innerText = window.internals.layerTreeAsText(document);
+      if (window.testRunner && window.internals)
+        testRunner.setCustomTextOutput(internals.layerTreeAsText(document));
       
       if (window.testRunner)
         testRunner.notifyDone();
     }
     
-    window.addEventListener('load', function() {
-      window.setTimeout(changeOverflow, 0);
-    }, false);
+    onload = function() {
+      runAfterLayoutAndPaint(changeOverflow, true);
+    };
   </script>
 </head>
 <body>
@@ -62,7 +59,5 @@
   <div id="container">
     <div class="box"></div>
   </div>
-  
-<pre id="layers">Layer tree goes here in DRT</pre>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt
index a3f3899..a1acbe5 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/bounds-clipped-composited-child-expected.txt
@@ -8,9 +8,8 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='container'",
-      "position": [58, 8],
       "bounds": [200, 100],
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -20,6 +19,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [58, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [-50, 0, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt
index ff5571b..bf97120 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/clip-expected.txt
@@ -10,10 +10,9 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box'",
-      "position": [15, 15],
       "bounds": [110, 110],
       "backgroundColor": "#808080",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Ancestor Clipping Layer",
@@ -23,10 +22,9 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
-      "position": [-5, -5],
       "bounds": [120, 120],
       "backgroundColor": "#00000033",
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
@@ -36,17 +34,39 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, 0, 1, 1]
+        [15, 15, 0, 1]
       ]
     },
     {
       "id": 2,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [210, 10, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt
index 780816b..e7c5aaa 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/clip-inside-expected.txt
@@ -10,11 +10,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box'",
-      "position": [25, 35],
       "bounds": [90, 80],
       "contentsOpaque": true,
       "backgroundColor": "#808080",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Ancestor Clipping Layer",
@@ -24,10 +23,9 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
-      "position": [-15, -25],
       "bounds": [120, 120],
       "backgroundColor": "#00000033",
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
@@ -37,17 +35,39 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, 0, 1, 1]
+        [25, 35, 0, 1]
       ]
     },
     {
       "id": 2,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [210, 10, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt
index 82f5b1ea7c..5694079 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/clip-with-shadow-expected.txt
@@ -8,10 +8,9 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited box'",
-      "position": [15, 15],
       "bounds": [110, 110],
       "backgroundColor": "#808080",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Ancestor Clipping Layer",
@@ -21,10 +20,9 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited inner'",
-      "position": [-5, -5],
       "bounds": [120, 120],
       "backgroundColor": "#00000033",
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
@@ -34,17 +32,39 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, 0, 1, 1]
+        [15, 15, 0, 1]
       ]
     },
     {
       "id": 2,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [210, 10, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
index 98ce953..20309a0 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
@@ -15,10 +15,9 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='negative child'",
-      "position": [59, 59],
       "bounds": [50, 50],
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='main box' (foreground) Layer",
@@ -41,7 +40,7 @@
       "name": "LayoutBlockFlow (positioned) DIV class='negative child'",
       "bounds": [50, 50],
       "drawsContent": false,
-      "transform": 2
+      "transform": 4
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='main box' (foreground) Layer",
@@ -56,11 +55,31 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, 0, 1, 1]
+        [78, 148, 0, 1]
       ]
     },
     {
       "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [422, 78, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-deep-switch.html b/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-deep-switch.html
index 6bfaa8da..f3e7f6d6 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-deep-switch.html
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-deep-switch.html
@@ -43,7 +43,8 @@
     }
     
   </style>
-  <script type="text/javascript" charset="utf-8">
+  <script src="../../resources/run-after-layout-and-paint.js"></script>
+  <script>
     if (window.testRunner) {
         testRunner.dumpAsText();
         testRunner.waitUntilDone();
@@ -51,36 +52,30 @@
     var text = "";
     function showTree(which)
     {
-        setTimeout(function() {
-            if (window.testRunner) {
-                text += "\n" + which + " dump layer tree:\n";
-                text += window.internals.layerTreeAsText(document);
-                document.getElementById('layers').innerText = text;
-            }
-        }, 0);
+        if (!window.testRunner || !window.internals)
+            return;
+        text += "\n" + which + " dump layer tree:\n";
+        text += internals.layerTreeAsText(document);
+        testRunner.setCustomTextOutput(text);
     }
 
     function doTest()
     {
-        if (window.testRunner)
-            //document.getElementById('layers').innerText = "";
         showTree("First");
 
-        //Put child in compositing mode
-        setTimeout(function() {
+        // Put child in compositing mode
+        runAfterLayoutAndPaint(function() {
             document.getElementById("greatgrandchild").style.webkitTransform = "perspective(400)  translate3D(-30px, 30px, 100px) rotateY(60deg)";
             showTree("Second");
             
             // Take it back out of compositing mode
-            setTimeout(function() {
+            runAfterLayoutAndPaint(function() {
                 document.getElementById("greatgrandchild").style.webkitTransform = "";
                 showTree("Third");
-                
-                setTimeout(function() {
+                if (window.testRunner)
                     testRunner.notifyDone();
-                }, 0);
-            }, 100);
-        }, 100);
+            });
+        });
     }
 
     window.addEventListener('load', doTest, false);
@@ -103,8 +98,6 @@
           </div>
       </div>
   </div>
-  
-  <pre id="layers">Layer tree goes here in DRT</pre>
 </body>
 </html>
 
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-switch.html b/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-switch.html
index d531d346..312ef12 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-switch.html
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/layer-due-to-layer-children-switch.html
@@ -24,7 +24,8 @@
     }
     
   </style>
-  <script type="text/javascript" charset="utf-8">
+  <script src="../../resources/run-after-layout-and-paint.js"></script>
+  <script>
     if (window.testRunner) {
         testRunner.dumpAsText();
         testRunner.waitUntilDone();
@@ -32,36 +33,31 @@
     var text = "";
     function showTree(which)
     {
-        setTimeout(function() {
-            if (window.testRunner) {
-                text += "\n" + which + " dump layer tree:\n";
-                text += window.internals.layerTreeAsText(document);
-                document.getElementById('layers').innerText = text;
-            }
-        }, 0);
+        if (!window.testRunner || !window.internals)
+            return;
+        text += "\n" + which + " dump layer tree:\n";
+        text += internals.layerTreeAsText(document);
+        testRunner.setCustomTextOutput(text);
     }
 
     function doTest()
     {
-        if (window.testRunner)
-            //document.getElementById('layers').innerText = "";
         showTree("First");
             
-        //Put child in compositing mode
-        setTimeout(function() {
+        // Put child in compositing mode
+        runAfterLayoutAndPaint(function() {
             document.getElementById("child").style.webkitTransform = "perspective(600) translate3D(-50px, 10px, 100px) rotateY(45deg)";
             showTree("Second");
             
             // Take it back out of compositing mode
-            setTimeout(function() {
+            runAfterLayoutAndPaint(function() {
                 document.getElementById("child").style.webkitTransform = "";
                 showTree("Third");
                 
-                setTimeout(function() {
+                if (window.testRunner)
                     testRunner.notifyDone();
-                }, 0);
-            }, 100);
-        }, 100);
+            });
+        });
     }
 
     window.addEventListener('load', doTest, false);
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt
index 1fda75f8..dc27791 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-nested-iframes-expected.txt
@@ -5,161 +5,200 @@
       "name": "LayoutView #document",
       "bounds": [785, 1650],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutIFrame IFRAME",
       "position": [20, 150],
-      "bounds": [284, 204]
+      "bounds": [284, 204],
+      "transform": 1
     },
     {
       "name": "Frame Overflow Controls Host Layer",
       "position": [22, 152],
       "bounds": [280, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Clipping Layer",
       "position": [22, 152],
       "bounds": [280, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Scrolling Layer",
       "position": [22, 152],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Content Root Layer",
       "position": [22, 152],
       "bounds": [280, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutView #document",
       "position": [22, 152],
-      "bounds": [280, 200]
+      "bounds": [280, 200],
+      "transform": 1
     },
     {
       "name": "LayoutIFrame IFRAME",
       "position": [30, 160],
-      "bounds": [252, 172]
+      "bounds": [252, 172],
+      "transform": 1
     },
     {
       "name": "Frame Overflow Controls Host Layer",
       "position": [31, 161],
       "bounds": [250, 170],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Clipping Layer",
       "position": [31, 161],
       "bounds": [250, 170],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Scrolling Layer",
       "position": [31, 161],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Content Root Layer",
       "position": [31, 161],
       "bounds": [250, 230],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutView #document",
       "position": [31, 161],
       "bounds": [250, 230],
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "position": [49, 171],
       "bounds": [210, 210],
       "contentsOpaque": true,
-      "backgroundColor": "#0000FF"
+      "backgroundColor": "#0000FF",
+      "transform": 1
     },
     {
       "name": "LayoutIFrame IFRAME",
       "position": [20, 374],
-      "bounds": [284, 204]
+      "bounds": [284, 204],
+      "transform": 1
     },
     {
       "name": "Frame Overflow Controls Host Layer",
       "position": [22, 376],
       "bounds": [280, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Clipping Layer",
       "position": [22, 376],
       "bounds": [280, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Scrolling Layer",
       "position": [22, 376],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Content Root Layer",
       "position": [22, 376],
       "bounds": [280, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutView #document",
       "position": [22, 376],
-      "bounds": [280, 200]
+      "bounds": [280, 200],
+      "transform": 1
     },
     {
       "name": "LayoutIFrame IFRAME",
       "position": [30, 384],
-      "bounds": [252, 172]
+      "bounds": [252, 172],
+      "transform": 1
     },
     {
       "name": "Frame Overflow Controls Host Layer",
       "position": [31, 385],
       "bounds": [250, 170],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Clipping Layer",
       "position": [31, 385],
       "bounds": [250, 170],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Frame Scrolling Layer",
       "position": [31, 385],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Content Root Layer",
       "position": [31, 385],
       "bounds": [250, 230],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutView #document",
       "position": [31, 385],
       "bounds": [250, 230],
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "position": [49, 395],
       "bounds": [210, 210],
       "contentsOpaque": true,
-      "backgroundColor": "#0000FF"
+      "backgroundColor": "#0000FF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='banner'",
       "position": [0, 100],
       "bounds": [785, 120],
-      "backgroundColor": "#00000080"
+      "backgroundColor": "#00000080",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
index b62bf7f3..72fa39d 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
@@ -39,14 +39,16 @@
       "name": "LayoutView #document",
       "position": [43, 43],
       "bounds": [508, 608],
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='iframe-content' class='box'",
       "position": [151, 143],
       "bounds": [200, 200],
       "contentsOpaque": true,
-      "backgroundColor": "#0000FF"
+      "backgroundColor": "#0000FF",
+      "transform": 1
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
@@ -71,6 +73,17 @@
       "bounds": [50, 50],
       "backgroundColor": "#00000033"
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-80, -80, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-and-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-and-transform-expected.txt
index 0375673..4082b7be 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-and-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-and-transform-expected.txt
@@ -4,21 +4,35 @@
       "name": "LayoutView #document",
       "bounds": [785, 5021],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='indicator'",
       "position": [100, 1100],
       "bounds": [256, 256],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='overlap'",
       "position": [0, 1000],
       "bounds": [500, 500],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt
index 3ae71b6..a33a3d8 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-positioning-expected.txt
@@ -14,11 +14,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positionedAndTransformed fixed'",
-      "position": [20, -80],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -28,6 +27,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [20, -80, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 100, 0, 1]
       ]
     }
@@ -40,15 +49,15 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positionedAndTransformed fixed'",
-      "position": [20, -70],
       "bounds": [50, 50],
       "contentsOpaque": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 1
+      "transform": 3
     }
   ],
   "transforms": [
@@ -58,6 +67,26 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [0, -10, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, -70, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 100, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-scaled-scroll-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-scaled-scroll-expected.txt
index a3e7db9..c0d8669 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-scaled-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-out-of-view-scaled-scroll-expected.txt
@@ -5,42 +5,59 @@
       "name": "LayoutView #document",
       "bounds": [4008, 4016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [108, 0],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [108, 1108],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [1100, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [700, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [100, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-100, -100, 0, 1]
+      ]
     }
   ]
 }
@@ -51,42 +68,59 @@
       "name": "LayoutView #document",
       "bounds": [4008, 4016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [108, 0],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [108, 1108],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [1100, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [700, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [100, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-100, -100, 0, 1]
+      ]
     }
   ]
 }
@@ -97,42 +131,59 @@
       "name": "LayoutView #document",
       "bounds": [4008, 4016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [108, 0],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [108, 1108],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [1100, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [700, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='fixed'",
       "position": [100, 100],
       "bounds": [10, 10],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-100, -100, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt
index 0760cde2..593a178 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/fixed-position-under-transform-expected.txt
@@ -4,21 +4,22 @@
       "name": "LayoutView #document",
       "bounds": [785, 5021],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='transform'",
-      "position": [108, 113],
       "bounds": [256, 256],
       "contentsOpaque": true,
-      "transform": 1
+      "transform": 3
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='overlap'",
       "position": [0, 1000],
       "bounds": [500, 500],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
     }
   ],
   "transforms": [
@@ -28,6 +29,26 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [108, 113, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 1000, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt
index 6b16aa8..1bca74b6 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-clipping-expected.txt
@@ -8,11 +8,10 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='to-animate1' class='box animating1'",
-      "position": [18, 120],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='container'",
@@ -29,19 +28,17 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box gray force-layer'",
-      "position": [10, 10],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#808080",
-      "transform": 2
+      "transform": 4
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='to-animate2' class='box animating2'",
-      "position": [10, 230],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 6
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box yellow'",
@@ -70,6 +67,7 @@
     },
     {
       "id": 2,
+      "parent": 1,
       "transform": [
         [...],
         [...],
@@ -85,6 +83,35 @@
         [...],
         [...]
       ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    },
+    {
+      "id": 5,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    },
+    {
+      "id": 6,
+      "parent": 5,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt
index 0030553..1bc45ac 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-container-expected.txt
@@ -9,11 +9,10 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='to-animate1' class='box animating1'",
-      "position": [18, 120],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='container'",
@@ -28,11 +27,10 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box gray force-layer'",
-      "position": [22, 11],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#808080",
-      "transform": 2
+      "transform": 4
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box yellow')",
@@ -52,12 +50,34 @@
     },
     {
       "id": 2,
+      "parent": 1,
       "transform": [
         [...],
         [...],
         [...],
         [...]
       ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ],
+      "flattenInheritedTransform": false
     }
   ]
 }
@@ -73,11 +93,10 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='to-animate1' class='box animating1'",
-      "position": [18, 120],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='container'",
@@ -88,18 +107,16 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box gray force-layer'",
-      "position": [11, 11],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#808080",
-      "transform": 2
+      "transform": 4
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='first-green-box' class='box green rotate-45deg'",
-      "position": [10, 120],
       "bounds": [102, 102],
       "backgroundColor": "#008000",
-      "transform": 3
+      "transform": 6
     },
     {
       "name": "Squashing Containment Layer",
@@ -108,10 +125,9 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box green rotate-45deg'",
-      "position": [10, 230],
       "bounds": [102, 102],
       "backgroundColor": "#008000",
-      "transform": 4
+      "transform": 8
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box green')",
@@ -131,6 +147,7 @@
     },
     {
       "id": 2,
+      "parent": 1,
       "transform": [
         [...],
         [...],
@@ -145,11 +162,30 @@
         [...],
         [...],
         [...]
-      ],
-      "origin": [51, 51]
+      ]
     },
     {
       "id": 4,
+      "parent": 3,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    },
+    {
+      "id": 5,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ]
+    },
+    {
+      "id": 6,
+      "parent": 5,
       "transform": [
         [...],
         [...],
@@ -157,6 +193,28 @@
         [...]
       ],
       "origin": [51, 51]
+    },
+    {
+      "id": 7,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 8,
+      "parent": 7,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
+      ],
+      "origin": [51, 51],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt
index 2fdbc33..9280548 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-animation-expected.txt
@@ -19,11 +19,10 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='to-animate' class='animating box'",
-      "position": [10, 10],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
@@ -41,6 +40,16 @@
         [...],
         [...],
         [...]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [...],
+        [...],
+        [...],
+        [...]
       ],
       "origin": [50, 50]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt
index 26e5b5a..03ec6c85 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-3d-expected.txt
@@ -9,11 +9,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='green-box' class='box green center composited'",
-      "position": [108, 108],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -23,6 +22,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [108, 108, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 0, -1, 1]
       ]
     }
@@ -44,11 +53,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='green-box' class='box green center composited rotated-3d'",
-      "position": [108, 108],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top left')",
@@ -60,12 +68,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [108, 108, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0.707106781186548, 0, 0],
         [-0.707106781186548, 0.707106781186548, 0, 0],
         [0, 0, 1, 0],
         [0, 0, -1, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt
index 9ed1049..8db857c 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-expected.txt
@@ -8,17 +8,16 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='container'",
-      "position": [23, 8],
       "bounds": [256, 256],
       "contentsOpaque": true,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='composited'",
-      "position": [408, 8],
+      "position": [385, 0],
       "contentsOpaque": true,
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='green'",
@@ -34,6 +33,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [23, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [-10, 0, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt
index 6f2a746..e0f7139 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-layer-with-transform-body-expected.txt
@@ -13,17 +13,16 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='container'",
-      "position": [15, 0],
       "bounds": [256, 256],
       "contentsOpaque": true,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='composited'",
-      "position": [400, 0],
+      "position": [385, 0],
       "contentsOpaque": true,
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='green'",
@@ -40,6 +39,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [23, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [-10, 0, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt
index 330ecf39..45025d3 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transformed-preserved-3d-expected.txt
@@ -16,49 +16,49 @@
     {
       "name": "Child Transform Layer",
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow DIV id='camera' class='rotate-3d-start'",
       "contentsOpaque": true,
       "drawsContent": false,
-      "transform": 2
+      "transform": 3
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-1'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 3
+      "transform": 4
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-2'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 4
+      "transform": 5
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-3'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 5
+      "transform": 6
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-4'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 6
+      "transform": 7
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-5'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 7
+      "transform": 8
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-6'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 8
+      "transform": 9
     }
   ],
   "transforms": [
@@ -67,16 +67,25 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
-        [0, 0, 1, -0.005],
-        [0, 0, 0, 1]
-      ],
-      "origin": [50, 50],
-      "flattenInheritedTransform": false
+        [0, 0, 1, 0],
+        [108, 108, 0, 1]
+      ]
     },
     {
       "id": 2,
       "parent": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.005],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
         [0.353553390593274, 0.25, -0.5, 0],
         [0, 0.353553390593274, 0.707106781186548, 0],
         [0.353553390593274, -0.25, 0.5, 0],
@@ -87,19 +96,20 @@
       "renderingContext": 1
     },
     {
-      "id": 3,
-      "parent": 2,
+      "id": 4,
+      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 50, 1]
       ],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 4,
-      "parent": 2,
+      "id": 5,
+      "parent": 3,
       "transform": [
         [0, 0, -1, 0],
         [0, 1, 0, 0],
@@ -107,11 +117,12 @@
         [50, 0, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 5,
-      "parent": 2,
+      "id": 6,
+      "parent": 3,
       "transform": [
         [-1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -119,11 +130,12 @@
         [0, 0, -50, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 6,
-      "parent": 2,
+      "id": 7,
+      "parent": 3,
       "transform": [
         [0, 0, 1, 0],
         [0, 1, 0, 0],
@@ -131,11 +143,12 @@
         [-50, 0, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 7,
-      "parent": 2,
+      "id": 8,
+      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 0, 1, 0],
@@ -143,11 +156,12 @@
         [0, -50, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 8,
-      "parent": 2,
+      "id": 9,
+      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 0, -1, 0],
@@ -155,6 +169,7 @@
         [0, 50, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     }
   ]
@@ -178,49 +193,49 @@
     {
       "name": "Child Transform Layer",
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow DIV id='camera' class='rotate-3d-start rotate-3d-end'",
       "contentsOpaque": true,
       "drawsContent": false,
-      "transform": 2
+      "transform": 3
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-1'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 3
+      "transform": 4
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-2'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 4
+      "transform": 5
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-3'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 5
+      "transform": 6
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-4'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 6
+      "transform": 7
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-5'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 7
+      "transform": 8
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='side side-6'",
       "bounds": [100, 100],
       "backgroundColor": "#00FF00CC",
-      "transform": 8
+      "transform": 9
     },
     {
       "name": "Squashing Containment Layer",
@@ -245,16 +260,25 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
-        [0, 0, 1, -0.005],
-        [0, 0, 0, 1]
-      ],
-      "origin": [50, 50],
-      "flattenInheritedTransform": false
+        [0, 0, 1, 0],
+        [108, 108, 0, 1]
+      ]
     },
     {
       "id": 2,
       "parent": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.005],
+        [0, 0, 0, 1]
+      ],
+      "origin": [50, 50]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
         [0.707106781186548, 0.5, -0.5, 0],
         [0, 0.707106781186548, 0.707106781186548, 0],
         [0.707106781186548, -0.5, 0.5, 0],
@@ -265,19 +289,20 @@
       "renderingContext": 1
     },
     {
-      "id": 3,
-      "parent": 2,
+      "id": 4,
+      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 50, 1]
       ],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 4,
-      "parent": 2,
+      "id": 5,
+      "parent": 3,
       "transform": [
         [0, 0, -1, 0],
         [0, 1, 0, 0],
@@ -285,11 +310,12 @@
         [50, 0, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 5,
-      "parent": 2,
+      "id": 6,
+      "parent": 3,
       "transform": [
         [-1, 0, 0, 0],
         [0, 1, 0, 0],
@@ -297,11 +323,12 @@
         [0, 0, -50, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 6,
-      "parent": 2,
+      "id": 7,
+      "parent": 3,
       "transform": [
         [0, 0, 1, 0],
         [0, 1, 0, 0],
@@ -309,11 +336,12 @@
         [-50, 0, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 7,
-      "parent": 2,
+      "id": 8,
+      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 0, 1, 0],
@@ -321,11 +349,12 @@
         [0, -50, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     },
     {
-      "id": 8,
-      "parent": 2,
+      "id": 9,
+      "parent": 3,
       "transform": [
         [1, 0, 0, 0],
         [0, 0, -1, 0],
@@ -333,6 +362,7 @@
         [0, 50, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt
index 42d9c40..05d06f13 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/overlap-transforms-expected.txt
@@ -19,11 +19,10 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='transformed box'",
-      "position": [10, 10],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -33,6 +32,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [19, 19, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
index 7c9d429..f804919 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
@@ -20,10 +20,9 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate15'",
-      "position": [167, 23],
       "bounds": [110, 110],
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
@@ -36,10 +35,9 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate45'",
-      "position": [311, 23],
       "bounds": [110, 110],
       "backgroundColor": "#0000FF",
-      "transform": 2
+      "transform": 4
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
@@ -51,22 +49,46 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [167, 23, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.965925826289068, 0.258819045102521, 0, 0],
         [-0.258819045102521, 0.965925826289068, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [55, 55]
+      "origin": [55, 55],
+      "flattenInheritedTransform": false
     },
     {
-      "id": 2,
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [311, 23, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
       "transform": [
         [0.707106781186548, 0.707106781186548, 0, 0],
         [-0.707106781186548, 0.707106781186548, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [55, 55]
+      "origin": [55, 55],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
index 3b93cc2..3aba64b 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective-expected.txt
@@ -15,35 +15,33 @@
       "name": "Child Transform Layer",
       "bounds": [200, 200],
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Scrolling Layer",
       "bounds": [185, 185],
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Scrolling Contents Layer",
       "bounds": [185, 290],
       "drawsContent": false,
-      "transform": 1
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='child first'",
-      "position": [0, 65],
-      "bounds": [60, 200],
-      "contentsOpaque": true,
-      "backgroundColor": "#008000",
       "transform": 2
     },
     {
+      "name": "LayoutBlockFlow (positioned) DIV class='child first'",
+      "bounds": [60, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 4
+    },
+    {
       "name": "LayoutBlockFlow (positioned) DIV class='child second'",
-      "position": [65, 65],
       "bounds": [60, 200],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 3
+      "transform": 6
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -75,10 +73,9 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
-        [0, 0, 1, -0.01],
-        [0, 0, 0, 1]
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
       ],
-      "origin": [100, 100],
       "flattenInheritedTransform": false
     },
     {
@@ -87,19 +84,55 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [0, 0, 10, 1]
-      ]
+        [0, 0, 1, -0.01],
+        [0, 0, 0, 1]
+      ],
+      "origin": [100, 100],
+      "flattenInheritedTransform": false
     },
     {
       "id": 3,
-      "parent": 1,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 65, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 10, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 5,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [65, 65, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 6,
+      "parent": 5,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 20, 1]
-      ]
+      ],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt
index f94f6c40..4f40993 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/clip-descendents-expected.txt
@@ -14,11 +14,10 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
-      "position": [2, 12],
       "bounds": [100, 150],
       "contentsOpaque": true,
       "backgroundColor": "#808080",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Ancestor Clipping Layer",
@@ -28,49 +27,46 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
-      "position": [2, 12],
-      "bounds": [100, 150],
-      "contentsOpaque": true,
-      "backgroundColor": "#808080",
-      "transform": 2
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='container'",
-      "position": [48, 230],
-      "bounds": [60, 70]
-    },
-    {
-      "name": "Child Containment Layer",
-      "position": [48, 230],
-      "bounds": [60, 70],
-      "drawsContent": false
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='box'",
-      "position": [2, 12],
-      "bounds": [100, 150],
-      "contentsOpaque": true,
-      "backgroundColor": "#808080",
-      "transform": 3
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='container'",
-      "position": [240, 230],
-      "bounds": [60, 70]
-    },
-    {
-      "name": "Child Containment Layer",
-      "position": [240, 230],
-      "bounds": [60, 70],
-      "drawsContent": false
-    },
-    {
-      "name": "LayoutBlockFlow DIV class='box'",
-      "position": [2, 12],
       "bounds": [100, 150],
       "contentsOpaque": true,
       "backgroundColor": "#808080",
       "transform": 4
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='container'",
+      "position": [48, 230],
+      "bounds": [60, 70]
+    },
+    {
+      "name": "Child Containment Layer",
+      "position": [48, 230],
+      "bounds": [60, 70],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutBlockFlow DIV class='box'",
+      "bounds": [100, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#808080",
+      "transform": 6
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV class='container'",
+      "position": [240, 230],
+      "bounds": [60, 70]
+    },
+    {
+      "name": "Child Containment Layer",
+      "position": [240, 230],
+      "bounds": [60, 70],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutBlockFlow DIV class='box'",
+      "bounds": [100, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#808080",
+      "transform": 8
     }
   ],
   "transforms": [
@@ -80,17 +76,20 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
-        [0, 0, 1, 1]
-      ]
+        [50, 50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
     },
     {
       "id": 2,
+      "parent": 1,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 1, 1]
-      ]
+      ],
+      "flattenInheritedTransform": false
     },
     {
       "id": 3,
@@ -98,11 +97,52 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [242, 50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 1, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 5,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [50, 242, 0, 1]
+      ]
+    },
+    {
+      "id": 6,
+      "parent": 5,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
     },
     {
-      "id": 4,
+      "id": 7,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [242, 242, 0, 1]
+      ]
+    },
+    {
+      "id": 8,
+      "parent": 7,
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/scrollbar-layer-placement-expected.png b/third_party/WebKit/LayoutTests/compositing/overflow/scrollbar-layer-placement-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/scrollbar-layer-placement-expected.png
rename to third_party/WebKit/LayoutTests/compositing/overflow/scrollbar-layer-placement-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
index 692abac0..93b3d01c 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/universal-accelerated-overflow-scroll-expected.txt
@@ -24,7 +24,8 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [12, 12],
-      "bounds": [85, 144]
+      "bounds": [85, 144],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -84,7 +85,8 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [132, 12],
-      "bounds": [105, 144]
+      "bounds": [105, 144],
+      "transform": 2
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -144,7 +146,8 @@
       "name": "Scrolling Contents Layer",
       "position": [252, 12],
       "bounds": [85, 144],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 3
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -208,7 +211,8 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [372, 12],
-      "bounds": [85, 144]
+      "bounds": [85, 144],
+      "transform": 4
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -268,7 +272,8 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [12, 132],
-      "bounds": [105, 144]
+      "bounds": [105, 144],
+      "transform": 5
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -328,7 +333,8 @@
       "name": "Scrolling Contents Layer",
       "position": [132, 132],
       "bounds": [85, 144],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 6
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -389,7 +395,8 @@
       "name": "Scrolling Contents Layer",
       "position": [252, 132],
       "bounds": [105, 144],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 7
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -445,7 +452,8 @@
       "name": "Scrolling Contents Layer",
       "position": [372, 132],
       "bounds": [105, 144],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 8
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -500,7 +508,8 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [12, 252],
-      "bounds": [85, 144]
+      "bounds": [85, 144],
+      "transform": 9
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -563,7 +572,8 @@
       "name": "Scrolling Contents Layer",
       "position": [132, 252],
       "bounds": [85, 144],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 10
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -625,7 +635,8 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [252, 252],
-      "bounds": [85, 144]
+      "bounds": [85, 144],
+      "transform": 11
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -688,7 +699,8 @@
       "name": "Scrolling Contents Layer",
       "position": [372, 252],
       "bounds": [85, 144],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 12
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -970,6 +982,128 @@
       "position": [376, 253],
       "bounds": [75, 80]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 5,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 6,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 7,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 8,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 9,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 10,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 11,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 12,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -59, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt b/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt
index 4d4857e..6d04d5b9b 100644
--- a/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rendering-contexts-expected.txt
@@ -8,32 +8,35 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='grandparent' class='composited'",
-      "position": [8, 8],
-      "bounds": [100, 100],
-      "contentsOpaque": true,
-      "backgroundColor": "#008000",
-      "transform": 1
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='parent' class='composited'",
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
       "transform": 2
     },
     {
-      "name": "LayoutBlockFlow DIV id='child' class='composited'",
+      "name": "LayoutBlockFlow DIV id='parent' class='composited'",
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
       "transform": 3
+    },
+    {
+      "name": "LayoutBlockFlow DIV id='child' class='composited'",
+      "bounds": [100, 100],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 4
     }
   ],
   "transforms": [
     {
       "id": 1,
-      "flattenInheritedTransform": false,
-      "renderingContext": 1
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
     },
     {
       "id": 2,
@@ -44,6 +47,11 @@
       "id": 3,
       "parent": 2,
       "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 4,
+      "parent": 3,
       "renderingContext": 2
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-expected.txt
index a8d081bc..bdc35c3b 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-expected.txt
@@ -4,14 +4,27 @@
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned layer'",
       "position": [265, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-215, 0, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-scrolled-expected.txt
index bbca6046..f0483479 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-absolute-overflow-scrolled-expected.txt
@@ -4,14 +4,27 @@
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='layer' class='positioned'",
       "position": [51, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-1, 0, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.png
index 92bd01a..1e34e81 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.txt
index fdde5369..4ce0b9b 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-expected.txt
@@ -4,21 +4,35 @@
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'",
       "position": [265, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned layer'",
       "position": [265, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-215, 0, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png
new file mode 100644
index 0000000..d7951a5d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled-expected.txt
index 28cf526c..1215d9e8 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled-expected.txt
@@ -4,21 +4,35 @@
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'",
       "position": [51, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned layer'",
       "position": [51, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-1, 0, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled.html b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled.html
index cd6faa4c..dbfdb3fd 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled.html
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow-scrolled.html
@@ -49,10 +49,10 @@
 
         window.setTimeout(function() {
             window.scrollTo(offset, 0);
-            if (window.testRunner) {
+            if (window.testRunner && window.internals) {
                 runAfterLayoutAndPaint(function() {
                     if (top == self)
-                        document.getElementById('layertree').innerText = window.internals.layerTreeAsText(document);
+                        testRunner.setCustomTextOutput(internals.layerTreeAsText(document));
                     testRunner.notifyDone();
                 });
             }
@@ -64,7 +64,5 @@
     <div id="root"></div>
     <div class="positioned indicator"></div>
     <div class="positioned layer"></div>
-
-    <pre id="layertree"></pre>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow.html b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow.html
index 62f4c20..09dbc88 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow.html
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-fixed-overflow.html
@@ -38,9 +38,9 @@
 </style>
 <script>
     function doTest() {
-        if (window.testRunner) {
+        if (window.testRunner && window.internals) {
             if (top == self)
-                document.getElementById('layertree').innerText = window.internals.layerTreeAsText(document);
+                testRunner.setCustomTextOutput(internals.layerTreeAsText(document));
             testRunner.dumpAsTextWithPixelResults();
         }
     }
@@ -50,7 +50,5 @@
     <div id="root"></div>
     <div class="positioned indicator"></div>
     <div class="positioned layer"></div>
-
-    <pre id="layertree"></pre>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
index 6f8ecd61..dee79ff 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-expected.txt
@@ -33,14 +33,16 @@
     {
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned layer'",
       "position": [665, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
@@ -59,6 +61,17 @@
       "position": [385, 385],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-615, 0, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
index b310e561..5685ea57 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-absolute-overflow-scrolled-expected.txt
@@ -33,14 +33,16 @@
     {
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='layer' class='positioned'",
       "position": [51, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
@@ -59,6 +61,17 @@
       "position": [385, 385],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-615, 0, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
index c43660c..8f27ec2 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-expected.txt
@@ -33,21 +33,24 @@
     {
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'",
       "position": [665, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned layer'",
       "position": [665, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
@@ -66,6 +69,17 @@
       "position": [385, 385],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-615, 0, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
index c43660c..8f27ec2 100644
--- a/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/rtl/rtl-iframe-fixed-overflow-scrolled-expected.txt
@@ -33,21 +33,24 @@
     {
       "name": "LayoutView #document",
       "bounds": [1000, 1000],
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned indicator'",
       "position": [665, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='positioned layer'",
       "position": [665, 50],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
     },
     {
       "name": "Frame Horizontal Scrollbar Layer",
@@ -66,6 +69,17 @@
       "position": [385, 385],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-615, 0, 0, 1]
+      ]
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
index d129936..8b854d2 100644
--- a/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/scrollbars/nested-overlay-scrollbars-expected.txt
@@ -20,63 +20,74 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [10, 10],
-      "bounds": [400, 704]
+      "bounds": [400, 704],
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='inner'",
       "position": [10, 510],
-      "bounds": [204, 204]
+      "bounds": [204, 204],
+      "transform": 1
     },
     {
       "name": "Scrolling Layer",
       "position": [12, 512],
       "bounds": [200, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Scrolling Contents Layer",
       "position": [12, 512],
-      "bounds": [5000, 9000]
+      "bounds": [5000, 9000],
+      "transform": 1
     },
     {
       "name": "Squashing Containment Layer",
       "position": [10, 10],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='grey'",
       "position": [12, 512],
       "bounds": [100, 800],
       "contentsOpaque": true,
-      "backgroundColor": "#808080"
+      "backgroundColor": "#808080",
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='spacer')",
       "position": [12, 2512],
-      "bounds": [5000, 1000]
+      "bounds": [5000, 1000],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
       "position": [12, 512],
       "bounds": [204, 204],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Horizontal Scrollbar Layer",
       "position": [14, 707],
       "bounds": [193, 7],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Vertical Scrollbar Layer",
       "position": [207, 514],
       "bounds": [7, 193],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "Scroll Corner Layer",
       "position": [207, 707],
-      "bounds": [7, 7]
+      "bounds": [7, 7],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -90,6 +101,18 @@
       "bounds": [7, 400],
       "drawsContent": false
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -304, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt
index 531085e..1222eff 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt
@@ -70,18 +70,21 @@
           "rect": [0, 0, 200, 100],
           "reason": "subtree"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited background'",
       "position": [100, 230],
       "bounds": [300, 300],
       "contentsOpaque": true,
-      "backgroundColor": "#D3D3D3"
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
     },
     {
       "name": "Squashing Containment Layer",
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='paragraph-c' class='overlapping cyan'",
@@ -100,7 +103,8 @@
           "rect": [0, 0, 200, 100],
           "reason": "compositing update"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV id='paragraph-d' class='overlapping lime')",
@@ -122,6 +126,18 @@
           "rect": [0, 0, 200, 100],
           "reason": "compositing update"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -80, 0, 1]
       ]
     }
   ],
@@ -171,30 +187,46 @@
       "name": "LayoutView #document",
       "bounds": [785, 1400],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited background'",
       "position": [100, 270],
       "bounds": [300, 300],
       "contentsOpaque": true,
-      "backgroundColor": "#D3D3D3"
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
     },
     {
       "name": "Squashing Containment Layer",
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='paragraph-c' class='overlapping cyan'",
       "position": [0, 200],
       "bounds": [200, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#00FFFF"
+      "backgroundColor": "#00FFFF",
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV id='paragraph-d' class='overlapping lime')",
       "position": [0, 300],
-      "bounds": [200, 300]
+      "bounds": [200, 300],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -120, 0, 1]
+      ]
     }
   ]
 }
@@ -232,18 +264,21 @@
           "rect": [0, 0, 200, 100],
           "reason": "subtree"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='composited background'",
       "position": [100, 320],
       "bounds": [300, 300],
       "contentsOpaque": true,
-      "backgroundColor": "#D3D3D3"
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
     },
     {
       "name": "Squashing Containment Layer",
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='paragraph-d' class='overlapping lime'",
@@ -262,7 +297,8 @@
           "rect": [0, 0, 200, 100],
           "reason": "compositing update"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV id='paragraph-e' class='overlapping cyan')",
@@ -284,6 +320,18 @@
           "rect": [0, 0, 200, 100],
           "reason": "compositing update"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -170, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt
index e2de19b..cfa8fda 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-2-expected.txt
@@ -39,7 +39,8 @@
       "name": "LayoutView #document",
       "bounds": [785, 4050],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='fixed'",
@@ -47,7 +48,8 @@
       "bounds": [400, 200],
       "contentsOpaque": true,
       "backfaceVisibility": "hidden",
-      "backgroundColor": "#0000FF"
+      "backgroundColor": "#0000FF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV id='compositedInsideFixed'",
@@ -55,14 +57,27 @@
       "bounds": [50, 50],
       "contentsOpaque": true,
       "backfaceVisibility": "hidden",
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='container'",
       "position": [100, 50],
       "bounds": [200, 4000],
       "contentsOpaque": true,
-      "backgroundColor": "#00FFFF"
+      "backgroundColor": "#00FFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -80, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt
index b6d6443..d471bdc2 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-3-expected.txt
@@ -47,35 +47,51 @@
       "name": "LayoutView #document",
       "bounds": [785, 4100],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='backgroundFixed'",
       "position": [0, 10],
       "bounds": [400, 400],
       "contentsOpaque": true,
-      "backgroundColor": "#808080"
+      "backgroundColor": "#808080",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='container'",
       "position": [100, 100],
       "bounds": [100, 4000],
       "contentsOpaque": true,
-      "backgroundColor": "#008000"
+      "backgroundColor": "#008000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerFixed'",
       "position": [100, 160],
       "bounds": [200, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#0000FF"
+      "backgroundColor": "#0000FF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerScrolling'",
       "position": [200, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#00FF00"
+      "backgroundColor": "#00FF00",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -10, 0, 1]
+      ]
     }
   ]
 }
@@ -86,14 +102,16 @@
       "name": "LayoutView #document",
       "bounds": [785, 4100],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='backgroundFixed'",
       "position": [0, 110],
       "bounds": [400, 400],
       "contentsOpaque": true,
-      "backgroundColor": "#808080"
+      "backgroundColor": "#808080",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='container'",
@@ -106,14 +124,27 @@
           "rect": [100, 0, 100, 100],
           "reason": "compositing update"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='innerFixed'",
       "position": [100, 260],
       "bounds": [200, 100],
       "contentsOpaque": true,
-      "backgroundColor": "#0000FF"
+      "backgroundColor": "#0000FF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -110, 0, 1]
+      ]
     }
   ],
   "objectPaintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt
index 9b6955c..d6c6619 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-onto-transform-backing-expected.txt
@@ -12,11 +12,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='compositedAndRotated box behind'",
-      "position": [100, 100],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box middle')",
@@ -28,12 +27,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [100, 100, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0.707106781186548, 0, 0],
         [-0.707106781186548, 0.707106781186548, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt
index b4e415f..2e2f21b4 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-same-transform-ancestor-expected.txt
@@ -8,37 +8,44 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='transform-parent'",
-      "position": [8, 8],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Containment Layer",
-      "position": [8, 8],
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='squashing'",
-      "position": [8, 8],
       "bounds": [1, 1],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='squashed')",
-      "position": [-92, 8],
+      "position": [-100, 0],
       "bounds": [200, 200],
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.866025403784439, -0.5, 0, 0],
         [0.5, 0.866025403784439, 0, 0],
         [0, 0, 1, 0],
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt
index c97414c8..fdcae45 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-expected.txt
@@ -19,11 +19,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
-      "position": [20, 20],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#00FF00",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -35,12 +34,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, 20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0.707106781186548, 0, 0],
         [-0.707106781186548, 0.707106781186548, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt
index a7d7851..7b66da86 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-child-expected.txt
@@ -20,11 +20,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
-      "position": [20, 20],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#00FF00",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -36,12 +35,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, 20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0.707106781186548, 0, 0],
         [-0.707106781186548, 0.707106781186548, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ]
 }
@@ -67,7 +78,6 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
-      "position": [20, 20],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
@@ -78,7 +88,7 @@
           "reason": "style change"
         }
       ],
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -90,12 +100,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, 20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0.707106781186548, 0, 0],
         [-0.707106781186548, 0.707106781186548, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ],
   "objectPaintInvalidations": [
@@ -127,7 +149,6 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
-      "position": [20, 20],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
@@ -143,7 +164,7 @@
           "reason": "style change"
         }
       ],
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -155,12 +176,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, 20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0.707106781186548, 0, 0],
         [-0.707106781186548, 0.707106781186548, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ],
   "objectPaintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt
index 5c65b7e..2aaad09 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squash-transform-repainting-transformed-child-expected.txt
@@ -20,11 +20,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
-      "position": [20, 20],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#00FF00",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -36,12 +35,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, 20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.927183854566787, 0.374606593415912, 0, 0],
         [-0.374606593415912, 0.927183854566787, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ]
 }
@@ -67,7 +78,6 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
-      "position": [20, 20],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
@@ -78,7 +88,7 @@
           "reason": "style change"
         }
       ],
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -90,12 +100,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, 20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.927183854566787, 0.374606593415912, 0, 0],
         [-0.374606593415912, 0.927183854566787, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ],
   "objectPaintInvalidations": [
@@ -127,7 +149,6 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='box middle'",
-      "position": [20, 20],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
@@ -143,7 +164,7 @@
           "reason": "style change"
         }
       ],
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='box top')",
@@ -155,12 +176,24 @@
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [20, 20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.927183854566787, 0.374606593415912, 0, 0],
         [-0.374606593415912, 0.927183854566787, 0, 0],
         [0, 0, 1, 0],
         [0, 0, 0, 1]
       ],
-      "origin": [50, 50]
+      "origin": [50, 50],
+      "flattenInheritedTransform": false
     }
   ],
   "objectPaintInvalidations": [
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt b/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt
index e006f987..c362684 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt
@@ -15,23 +15,23 @@
     {
       "name": "Child Transform Layer",
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Containment Layer",
       "drawsContent": false,
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
       "bounds": [200, 200],
       "contentsOpaque": true,
       "backgroundColor": "#00008B",
-      "transform": 2
+      "transform": 3
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV)",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -40,11 +40,9 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
-        [0, 0, 1, -0.001],
-        [0, 0, 0, 1]
-      ],
-      "origin": [0, 0],
-      "flattenInheritedTransform": false
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
     },
     {
       "id": 2,
@@ -52,9 +50,21 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
+        [0, 0, 1, -0.001],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
         [0, 0, 1, 0],
         [0, 74, 200, 1]
-      ]
+      ],
+      "flattenInheritedTransform": false
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
index c311df0..df51df84 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/blending/svg-blend-multiply-alpha-expected.png b/third_party/WebKit/LayoutTests/css3/blending/svg-blend-multiply-alpha-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/linux/css3/blending/svg-blend-multiply-alpha-expected.png
rename to third_party/WebKit/LayoutTests/css3/blending/svg-blend-multiply-alpha-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt b/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt
index cc187eb..e0c130f 100644
--- a/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/filters/filtered-compositing-descendant-expected.txt
@@ -13,11 +13,10 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='compositing box'",
-      "position": [22, 22],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#FF0000",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -27,6 +26,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [30, 30, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/add-during-dispatch-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/add-during-dispatch-expected.txt
deleted file mode 100644
index adf411c..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/add-during-dispatch-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Test no fire listeners added during event dispatch.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS deviceMotionEvent.acceleration.x is mockEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is mockEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is mockEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is mockEvent.interval
-PASS numSecondListenerCalls is 1
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/add-during-dispatch.html b/third_party/WebKit/LayoutTests/device_orientation/motion/add-during-dispatch.html
index 8c4c6d0..6c6b926 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/add-during-dispatch.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/add-during-dispatch.html
@@ -1,79 +1,33 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/device-orientation-helpers.js"></script>
 <script>
-description('Test no fire listeners added during event dispatch.');
+'use strict';
 
-var mockEvent;
-function setMockMotion(accelerationX, accelerationY, accelerationZ,
-                       accelerationIncludingGravityX, accelerationIncludingGravityY, accelerationIncludingGravityZ,
-                       rotationRateAlpha, rotationRateBeta, rotationRateGamma,
-                       interval) {
-
-    mockEvent = {accelerationX: accelerationX, accelerationY: accelerationY, accelerationZ: accelerationZ,
-                 accelerationIncludingGravityX: accelerationIncludingGravityX, accelerationIncludingGravityY: accelerationIncludingGravityY, accelerationIncludingGravityZ: accelerationIncludingGravityZ,
-                 rotationRateAlpha: rotationRateAlpha, rotationRateBeta: rotationRateBeta, rotationRateGamma: rotationRateGamma,
-                 interval: interval};
-
-    if (window.testRunner)
-        testRunner.setMockDeviceMotion(null != mockEvent.accelerationX, null == mockEvent.accelerationX ? 0 : mockEvent.accelerationX,
-                                       null != mockEvent.accelerationY, null == mockEvent.accelerationY ? 0 : mockEvent.accelerationY,
-                                       null != mockEvent.accelerationZ, null == mockEvent.accelerationZ ? 0 : mockEvent.accelerationZ,
-                                       null != mockEvent.accelerationIncludingGravityX, null == mockEvent.accelerationIncludingGravityX ? 0 : mockEvent.accelerationIncludingGravityX,
-                                       null != mockEvent.accelerationIncludingGravityY, null == mockEvent.accelerationIncludingGravityY ? 0 : mockEvent.accelerationIncludingGravityY,
-                                       null != mockEvent.accelerationIncludingGravityZ, null == mockEvent.accelerationIncludingGravityZ ? 0 : mockEvent.accelerationIncludingGravityZ,
-                                       null != mockEvent.rotationRateAlpha, null == mockEvent.rotationRateAlpha ? 0 : mockEvent.rotationRateAlpha,
-                                       null != mockEvent.rotationRateBeta, null == mockEvent.rotationRateBeta ? 0 : mockEvent.rotationRateBeta,
-                                       null != mockEvent.rotationRateGamma, null == mockEvent.rotationRateGamma ? 0 : mockEvent.rotationRateGamma,
-                                       interval);
-    else
-        debug('This test can not be run without the TestRunner');
-}
-
-
-var deviceMotionEvent;
-function checkMotion(event) {
-    deviceMotionEvent = event;
-    shouldBe('deviceMotionEvent.acceleration.x', 'mockEvent.accelerationX');
-    shouldBe('deviceMotionEvent.acceleration.y', 'mockEvent.accelerationY');
-    shouldBe('deviceMotionEvent.acceleration.z', 'mockEvent.accelerationZ');
-
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.x', 'mockEvent.accelerationIncludingGravityX');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.y', 'mockEvent.accelerationIncludingGravityY');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.z', 'mockEvent.accelerationIncludingGravityZ');
-
-    shouldBe('deviceMotionEvent.rotationRate.alpha', 'mockEvent.rotationRateAlpha');
-    shouldBe('deviceMotionEvent.rotationRate.beta', 'mockEvent.rotationRateBeta');
-    shouldBe('deviceMotionEvent.rotationRate.gamma', 'mockEvent.rotationRateGamma');
-
-    shouldBe('deviceMotionEvent.interval', 'mockEvent.interval');
-}
-
-function firstListener(event) {
-    checkMotion(event);
+async_test(test => {
+  assertTestRunner();
+  var numSecondListenerCalls = 0;
+  var motionData = generateMotionData(1, 2, 3,
+                                      4, 5, 6,
+                                      7, 8, 9,
+                                      10);
+  setMockMotion(motionData);
+  window.addEventListener('devicemotion', function firstListener(event) {
+    test.step(() => {
+      checkMotion(event, motionData);
+    });
     window.removeEventListener('devicemotion', firstListener);
-    window.addEventListener('devicemotion', secondListener);
-    setTimeout(function(){finish();}, 100);
-}
-
-var numSecondListenerCalls = 0;
-function secondListener(event) {
-    ++numSecondListenerCalls;
-}
-
-function finish() {
-    shouldBe('numSecondListenerCalls', '1');
-    finishJSTest();
-}
-
-setMockMotion(1, 2, 3,
-              4, 5, 6,
-              7, 8, 9,
-              10);
-window.addEventListener('devicemotion', firstListener);
-
-window.jsTestIsAsync = true;
+    window.addEventListener('devicemotion', () => {
+      ++numSecondListenerCalls;
+    });
+    setTimeout(test.step_func_done(() => {
+      assert_equals(numSecondListenerCalls, 1);
+    }), 100);
+  });
+}, 'Test no fire listeners added during event dispatch.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/add-listener-from-callback-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/add-listener-from-callback-expected.txt
deleted file mode 100644
index 671278d5..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/add-listener-from-callback-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Tests that adding a new devicemotion event listener from a callback works as expected.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-TEST MODE enabled
-PASS deviceMotionEvent.acceleration.x is mockAccelerationX
-PASS deviceMotionEvent.acceleration.y is mockAccelerationY
-PASS deviceMotionEvent.acceleration.z is mockAccelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockAccelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockAccelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockAccelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockRotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockRotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockRotationRateGamma
-PASS deviceMotionEvent.interval is mockInterval
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/add-listener-from-callback.html b/third_party/WebKit/LayoutTests/device_orientation/motion/add-listener-from-callback.html
index 9994abe0..4457b06 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/add-listener-from-callback.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/add-listener-from-callback.html
@@ -1,58 +1,39 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/device-orientation-helpers.js"></script>
 <script>
-description('Tests that adding a new devicemotion event listener from a callback works as expected.');
+'use strict';
 
-var mockAccelerationX = 1.1;
-var mockAccelerationY = 2.1;
-var mockAccelerationZ = 3.1;
+async_test(test => {
+  assertTestRunner();
+  var motionData = generateMotionData(1.1, 2.1, 3.1,
+                                      1.2, 2.2, 3.2,
+                                      1.3, 2.3, 3.3,
+                                      100);
 
-var mockAccelerationIncludingGravityX = 1.2;
-var mockAccelerationIncludingGravityY = 2.2;
-var mockAccelerationIncludingGravityZ = 3.2;
+  var firstListenerEvents = 0;
+  var firstListener = test.step_func(event => {
+    checkMotion(event, motionData);
+    window.removeEventListener('devicemotion', firstListener);
+    if (++firstListenerEvents == 1)
+      window.addEventListener('devicemotion', secondListener);
+  });
 
-var mockRotationRateAlpha = 1.3;
-var mockRotationRateBeta = 2.3;
-var mockRotationRateGamma = 3.3;
+  var secondListenerEvents = 0;
+  var secondListener = test.step_func(event => {
+    checkMotion(event, motionData);
+    ++secondListenerEvents;
+    assert_equals(firstListenerEvents, 1, "Too many events fired for the first listener");
+    assert_equals(secondListenerEvents, 1, "Too many events fired for the second listener");
+    test.done();
+  });
 
-var mockInterval = 100;
-
-if (window.testRunner) {
-    testRunner.setMockDeviceMotion(true, mockAccelerationX, true, mockAccelerationY, true, mockAccelerationZ,
-                                   true, mockAccelerationIncludingGravityX, true, mockAccelerationIncludingGravityY, true, mockAccelerationIncludingGravityZ,
-                                   true, mockRotationRateAlpha, true, mockRotationRateBeta, true, mockRotationRateGamma,
-                                   mockInterval);
-    debug('TEST MODE enabled');
-} else
-    debug('This test can not be run without the TestRunner');
-
-var deviceMotionEvent;
-function checkMotion(event) {
-    deviceMotionEvent = event;
-    shouldBe('deviceMotionEvent.acceleration.x', 'mockAccelerationX');
-    shouldBe('deviceMotionEvent.acceleration.y', 'mockAccelerationY');
-    shouldBe('deviceMotionEvent.acceleration.z', 'mockAccelerationZ');
-
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.x', 'mockAccelerationIncludingGravityX');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.y', 'mockAccelerationIncludingGravityY');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.z', 'mockAccelerationIncludingGravityZ');
-
-    shouldBe('deviceMotionEvent.rotationRate.alpha', 'mockRotationRateAlpha');
-    shouldBe('deviceMotionEvent.rotationRate.beta', 'mockRotationRateBeta');
-    shouldBe('deviceMotionEvent.rotationRate.gamma', 'mockRotationRateGamma');
-
-    shouldBe('deviceMotionEvent.interval', 'mockInterval');
-}
-
-function listener(event) {
-    checkMotion(event);
-    finishJSTest();
-}
-
-window.addEventListener('devicemotion', listener);
-window.jsTestIsAsync = true;
+  setMockMotion(motionData);
+  window.addEventListener('devicemotion', firstListener);
+}, 'Tests that adding a new devicemotion event listener from a callback works as expected.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/create-event-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/create-event-expected.txt
deleted file mode 100644
index 6f882e4..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/create-event-expected.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Tests that document.createEvent() works with DeviceMotionEvent.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS typeof event == 'object' is true
-PASS event.__proto__ is DeviceMotionEvent.prototype
-PASS 'type' in event is true
-PASS 'bubbles' in event is true
-PASS 'cancelable' in event is true
-PASS 'acceleration' in event is true
-PASS 'accelerationIncludingGravity' in event is true
-PASS 'rotationRate' in event is true
-PASS 'interval' in event is true
-PASS typeof newEvent.type == 'string' is true
-PASS newEvent.type is "devicemotion"
-PASS typeof newEvent.bubbles == 'boolean' is true
-PASS event.bubbles is false
-PASS newEvent.bubbles is false
-PASS typeof newEvent.cancelable == 'boolean' is true
-PASS event.cancelable is false
-PASS newEvent.cancelable is false
-PASS typeof event.acceleration == 'object' is true
-PASS typeof event.accelerationIncludingGravity == 'object' is true
-PASS typeof event.rotationRate == 'object' is true
-PASS typeof event.interval == 'number' is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/create-event.html b/third_party/WebKit/LayoutTests/device_orientation/motion/create-event.html
index e96b99f..33a851c 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/create-event.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/create-event.html
@@ -1,43 +1,45 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-description("Tests that document.createEvent() works with DeviceMotionEvent.");
+'use strict';
 
-var event = document.createEvent('DeviceMotionEvent');
-var newEvent = new CustomEvent("devicemotion", {
-    bubbles: false, cancelable: false,
-    acceleration: {x:1.5,y:2.5,z:3.5},
-    accelerationIncludingGravity: {x:4.5,y:5.5,z:6.5},
-    rotationRate: {alpha:7.5,beta:8.5,gamma:9.5},
-    interval: 0.5
-});
+test(test => {
+  var event = document.createEvent('DeviceMotionEvent');
+  var newEvent = new CustomEvent("devicemotion", {
+      bubbles: false, cancelable: false,
+      acceleration: {x:1.5,y:2.5,z:3.5},
+      accelerationIncludingGravity: {x:4.5,y:5.5,z:6.5},
+      rotationRate: {alpha:7.5,beta:8.5,gamma:9.5},
+      interval: 0.5
+  });
 
-shouldBeTrue("typeof event == 'object'");
-shouldBe("event.__proto__", "DeviceMotionEvent.prototype");
+  assert_equals(typeof event, 'object');
+  assert_equals(event.__proto__, DeviceMotionEvent.prototype);
 
-shouldBeTrue("'type' in event");
-shouldBeTrue("'bubbles' in event");
-shouldBeTrue("'cancelable' in event");
-shouldBeTrue("'acceleration' in event");
-shouldBeTrue("'accelerationIncludingGravity' in event");
-shouldBeTrue("'rotationRate' in event");
-shouldBeTrue("'interval' in event");
+  assert_true('type' in event);
+  assert_true('bubbles' in event);
+  assert_true('cancelable' in event);
+  assert_true('acceleration' in event);
+  assert_true('accelerationIncludingGravity' in event);
+  assert_true('rotationRate' in event);
+  assert_true('interval' in event);
 
-shouldBeTrue("typeof newEvent.type == 'string'");
-shouldBeEqualToString("newEvent.type", "devicemotion");
-shouldBeTrue("typeof newEvent.bubbles == 'boolean'");
-shouldBeFalse("event.bubbles");
-shouldBeFalse("newEvent.bubbles");
-shouldBeTrue("typeof newEvent.cancelable == 'boolean'");
-shouldBeFalse("event.cancelable");
-shouldBeFalse("newEvent.cancelable");
-shouldBeTrue("typeof event.acceleration == 'object'");
-shouldBeTrue("typeof event.accelerationIncludingGravity == 'object'");
-shouldBeTrue("typeof event.rotationRate == 'object'");
-shouldBeTrue("typeof event.interval == 'number'");
-
+  assert_equals(typeof newEvent.type, 'string');
+  assert_equals(newEvent.type, "devicemotion");
+  assert_equals(typeof newEvent.bubbles, 'boolean');
+  assert_false(event.bubbles);
+  assert_false(newEvent.bubbles);
+  assert_equals(typeof newEvent.cancelable, 'boolean');
+  assert_false(event.cancelable);
+  assert_false(newEvent.cancelable);
+  assert_equals(typeof event.acceleration, 'object');
+  assert_equals(typeof event.accelerationIncludingGravity, 'object');
+  assert_equals(typeof event.rotationRate, 'object');
+  assert_equals(typeof event.interval, 'number');
+}, 'Tests that document.createEvent() works with DeviceMotionEvent.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/detached-frame.html b/third_party/WebKit/LayoutTests/device_orientation/motion/detached-frame.html
index 88cfa6d..4267f56 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/detached-frame.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/detached-frame.html
@@ -3,58 +3,25 @@
 <body>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/device-orientation-helpers.js"></script>
 <script>
 'use strict';
 
-function assertTestRunner() {
-  assert_true(window.testRunner instanceof Object,
-    "This test can not be run without the window.testRunner.");
-}
-
-var mockAccelerationX = 1;
-var mockAccelerationY = 2;
-var mockAccelerationZ = 3;
-
-var mockAccelerationIncludingGravityX = 4;
-var mockAccelerationIncludingGravityY = 5;
-var mockAccelerationIncludingGravityZ = 6;
-
-var mockRotationRateAlpha = 7;
-var mockRotationRateBeta = 8;
-var mockRotationRateGamma = 9;
-
-var mockInterval = 10;
-
-function checkMotion(event) {
-  assert_equals(mockAccelerationX, event.acceleration.x);
-  assert_equals(mockAccelerationY, event.acceleration.y);
-  assert_equals(mockAccelerationZ, event.acceleration.z);
-
-  assert_equals(mockAccelerationIncludingGravityX, event.accelerationIncludingGravity.x);
-  assert_equals(mockAccelerationIncludingGravityY, event.accelerationIncludingGravity.y);
-  assert_equals(mockAccelerationIncludingGravityZ, event.accelerationIncludingGravity.z);
-
-  assert_equals(mockRotationRateAlpha, event.rotationRate.alpha);
-  assert_equals(mockRotationRateBeta, event.rotationRate.beta);
-  assert_equals(mockRotationRateGamma, event.rotationRate.gamma);
-
-  assert_equals(mockInterval, event.interval);
-}
-
 async_test(test => {
   assertTestRunner();
-  window.testRunner.setMockDeviceMotion(true, mockAccelerationX,
-      true, mockAccelerationY, true, mockAccelerationZ,
-      true, mockAccelerationIncludingGravityX,
-      true, mockAccelerationIncludingGravityY,
-      true, mockAccelerationIncludingGravityZ, true, mockRotationRateAlpha,
-      true, mockRotationRateBeta, true, mockRotationRateGamma, mockInterval);
+  var motionData = generateMotionData(1, 2, 3,
+                                      4, 5, 6,
+                                      7, 8, 9,
+                                      10);
+  setMockMotion(motionData);
   var childFrame = document.createElement('iframe');
   document.body.appendChild(childFrame);
   childFrame.contentWindow.addEventListener('devicemotion', () => {
     document.body.removeChild(childFrame);
     setTimeout(() => {
-      window.addEventListener('devicemotion', test.step_func_done(checkMotion));
+      window.addEventListener('devicemotion', test.step_func_done(event => {
+        checkMotion(event, motionData);
+      }));
     }, 300);
   });
 }, 'Tests adding a devicemotion event listener in an iframe, removing the iframe, and then adding a devicemotion event listener in the main frame.');
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/fire-last-event-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/fire-last-event-expected.txt
deleted file mode 100644
index 655ea4e..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/fire-last-event-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Tests to see if the last available event is fired.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS deviceMotionEvent.acceleration.x is mockEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is mockEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is mockEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is mockEvent.interval
-PASS deviceMotionEvent.acceleration.x is mockEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is mockEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is mockEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is mockEvent.interval
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/fire-last-event.html b/third_party/WebKit/LayoutTests/device_orientation/motion/fire-last-event.html
index 21586845..2f77c530 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/fire-last-event.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/fire-last-event.html
@@ -1,83 +1,36 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/device-orientation-helpers.js"></script>
 <script>
+'use strict';
 
-description('Tests to see if the last available event is fired.');
-
-var mockEvent;
-function setMockMotion(accelerationX, accelerationY, accelerationZ,
-                       accelerationIncludingGravityX, accelerationIncludingGravityY, accelerationIncludingGravityZ,
-                       rotationRateAlpha, rotationRateBeta, rotationRateGamma,
-                       interval) {
-
-    mockEvent = {accelerationX: accelerationX, accelerationY: accelerationY, accelerationZ: accelerationZ,
-                 accelerationIncludingGravityX: accelerationIncludingGravityX, accelerationIncludingGravityY: accelerationIncludingGravityY, accelerationIncludingGravityZ: accelerationIncludingGravityZ,
-                 rotationRateAlpha: rotationRateAlpha, rotationRateBeta: rotationRateBeta, rotationRateGamma: rotationRateGamma,
-                 interval: interval};
-
-    if (window.testRunner)
-        testRunner.setMockDeviceMotion(null != mockEvent.accelerationX, null == mockEvent.accelerationX ? 0 : mockEvent.accelerationX,
-                                       null != mockEvent.accelerationY, null == mockEvent.accelerationY ? 0 : mockEvent.accelerationY,
-                                       null != mockEvent.accelerationZ, null == mockEvent.accelerationZ ? 0 : mockEvent.accelerationZ,
-                                       null != mockEvent.accelerationIncludingGravityX, null == mockEvent.accelerationIncludingGravityX ? 0 : mockEvent.accelerationIncludingGravityX,
-                                       null != mockEvent.accelerationIncludingGravityY, null == mockEvent.accelerationIncludingGravityY ? 0 : mockEvent.accelerationIncludingGravityY,
-                                       null != mockEvent.accelerationIncludingGravityZ, null == mockEvent.accelerationIncludingGravityZ ? 0 : mockEvent.accelerationIncludingGravityZ,
-                                       null != mockEvent.rotationRateAlpha, null == mockEvent.rotationRateAlpha ? 0 : mockEvent.rotationRateAlpha,
-                                       null != mockEvent.rotationRateBeta, null == mockEvent.rotationRateBeta ? 0 : mockEvent.rotationRateBeta,
-                                       null != mockEvent.rotationRateGamma, null == mockEvent.rotationRateGamma ? 0 : mockEvent.rotationRateGamma,
-                                       interval);
-    else
-        debug('This test can not be run without the TestRunner');
-}
-
-
-var deviceMotionEvent;
-function checkMotion(event) {
-    deviceMotionEvent = event;
-    shouldBe('deviceMotionEvent.acceleration.x', 'mockEvent.accelerationX');
-    shouldBe('deviceMotionEvent.acceleration.y', 'mockEvent.accelerationY');
-    shouldBe('deviceMotionEvent.acceleration.z', 'mockEvent.accelerationZ');
-
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.x', 'mockEvent.accelerationIncludingGravityX');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.y', 'mockEvent.accelerationIncludingGravityY');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.z', 'mockEvent.accelerationIncludingGravityZ');
-
-    shouldBe('deviceMotionEvent.rotationRate.alpha', 'mockEvent.rotationRateAlpha');
-    shouldBe('deviceMotionEvent.rotationRate.beta', 'mockEvent.rotationRateBeta');
-    shouldBe('deviceMotionEvent.rotationRate.gamma', 'mockEvent.rotationRateGamma');
-
-    shouldBe('deviceMotionEvent.interval', 'mockEvent.interval');
-}
-
-
-function mainFrameListener(event) {
-    checkMotion(event);
+async_test(test => {
+  assertTestRunner();
+  var motionData1 = generateMotionData(1, 2, 3,
+                                       4, 5, 6,
+                                       7, 8, 9,
+                                       10);
+  var motionData2 = generateMotionData(0, 0, 0,
+                                       0, 0, 0,
+                                       0, 0, 0,
+                                       0);
+  setMockMotion(motionData1);
+  window.addEventListener('devicemotion', function mainFrameListener(event) {
+    test.step(() => {
+      checkMotion(event, motionData1);
+    });
     var childFrame = document.createElement('iframe');
     document.body.appendChild(childFrame);
     window.removeEventListener('devicemotion', mainFrameListener);
-    testRunner.setMockDeviceMotion(true, 0, true, 0, true, 0,
-                                   true, 0, true, 0, true, 0,
-                                   true, 0, true, 0, true, 0,
-                                   0);
-    childFrame.contentWindow.addEventListener('devicemotion', childFrameListener);
-}
-
-function childFrameListener(event) {
-    checkMotion(event);
-    finishJSTest();
-}
-
-setMockMotion(1, 2, 3,
-              4, 5, 6,
-              7, 8, 9,
-              10);
-
-window.addEventListener('devicemotion', mainFrameListener);
-
-window.jsTestIsAsync = true;
-
+    setMockMotion(motionData2);
+    childFrame.contentWindow.addEventListener('devicemotion', test.step_func_done(event => {
+      checkMotion(event, motionData1);
+    }));
+  });
+}, 'Tests to see if the last available event is fired.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/multiple-event-listeners-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/multiple-event-listeners-expected.txt
deleted file mode 100644
index 3b76381..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/multiple-event-listeners-expected.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-Tests using multiple event handlers for the Device Motion API.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS deviceMotionEvent.acceleration.x is expectedEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is expectedEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is expectedEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is expectedEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is expectedEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is expectedEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is expectedEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is expectedEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is expectedEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is expectedEvent.interval
-PASS deviceMotionEvent.acceleration.x is expectedEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is expectedEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is expectedEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is expectedEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is expectedEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is expectedEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is expectedEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is expectedEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is expectedEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is expectedEvent.interval
-PASS deviceMotionEvent.acceleration.x is expectedEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is expectedEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is expectedEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is expectedEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is expectedEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is expectedEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is expectedEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is expectedEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is expectedEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is expectedEvent.interval
-PASS deviceMotionEvent.acceleration.x is expectedEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is expectedEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is expectedEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is expectedEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is expectedEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is expectedEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is expectedEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is expectedEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is expectedEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is expectedEvent.interval
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/multiple-event-listeners.html b/third_party/WebKit/LayoutTests/device_orientation/motion/multiple-event-listeners.html
index ea405da..5d0d83b 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/multiple-event-listeners.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/multiple-event-listeners.html
@@ -1,112 +1,75 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/device-orientation-helpers.js"></script>
 <script>
+'use strict';
 
-description('Tests using multiple event handlers for the Device Motion API.');
+async_test(test => {
+  assertTestRunner();
+  var motionData1 = generateMotionData(1, 2, 3,
+                                       4, 5, 6,
+                                       7, 8, 9,
+                                       10);
+  var motionData2 = generateMotionData(11, 12, 13,
+                                       14, 15, 16,
+                                       17, 18, 19,
+                                       0);
+  var counter = 0;
 
-var mockEvent;
-var expectedEvent;
-function setMockMotion(accelerationX, accelerationY, accelerationZ,
-                       accelerationIncludingGravityX, accelerationIncludingGravityY, accelerationIncludingGravityZ,
-                       rotationRateAlpha, rotationRateBeta, rotationRateGamma,
-                       interval) {
-
-    mockEvent = {accelerationX: accelerationX, accelerationY: accelerationY, accelerationZ: accelerationZ,
-                 accelerationIncludingGravityX: accelerationIncludingGravityX, accelerationIncludingGravityY: accelerationIncludingGravityY, accelerationIncludingGravityZ: accelerationIncludingGravityZ,
-                 rotationRateAlpha: rotationRateAlpha, rotationRateBeta: rotationRateBeta, rotationRateGamma: rotationRateGamma,
-                 interval: interval};
-
-    if (window.testRunner)
-        testRunner.setMockDeviceMotion(true, mockEvent.accelerationX, true, mockEvent.accelerationY, true, mockEvent.accelerationZ,
-                                       true, mockEvent.accelerationIncludingGravityX, true, mockEvent.accelerationIncludingGravityY, true, mockEvent.accelerationIncludingGravityZ,
-                                       true, mockEvent.rotationRateAlpha, true, mockEvent.rotationRateBeta, true, mockEvent.rotationRateGamma,
-                                       interval);
-    else
-        debug('This test can not be run without the TestRunner');
-}
-
-var deviceMotionEvent;
-function checkMotion(event) {
-    deviceMotionEvent = event;
-    shouldBe('deviceMotionEvent.acceleration.x', 'expectedEvent.accelerationX');
-    shouldBe('deviceMotionEvent.acceleration.y', 'expectedEvent.accelerationY');
-    shouldBe('deviceMotionEvent.acceleration.z', 'expectedEvent.accelerationZ');
-
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.x', 'expectedEvent.accelerationIncludingGravityX');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.y', 'expectedEvent.accelerationIncludingGravityY');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.z', 'expectedEvent.accelerationIncludingGravityZ');
-
-    shouldBe('deviceMotionEvent.rotationRate.alpha', 'expectedEvent.rotationRateAlpha');
-    shouldBe('deviceMotionEvent.rotationRate.beta', 'expectedEvent.rotationRateBeta');
-    shouldBe('deviceMotionEvent.rotationRate.gamma', 'expectedEvent.rotationRateGamma');
-
-    shouldBe('deviceMotionEvent.interval', 'expectedEvent.interval');
-}
-
-var counter = 0;
-function firstListener(event) {
-    checkMotion(event);
-    counter++;
+  var firstListener = test.step_func(event => {
+    checkMotion(event, motionData1);
+    ++counter;
     proceedIfNecessary();
-}
+  });
 
-function secondListener(event) {
-    checkMotion(event);
-    counter++;
+  var secondListener = test.step_func(event => {
+    checkMotion(event, motionData1);
+    ++counter;
     proceedIfNecessary();
-}
+  });
 
-function proceedIfNecessary() {
+  function proceedIfNecessary() {
     if (counter == 2) {
-        setMockMotion(11, 12, 13,
-                      14, 15, 16,
-                      17, 18, 19,
-                      0);
-        // Note: this should not stop Device Motion updates,
-        // because there is still one listener active.
-        window.removeEventListener('devicemotion', secondListener);
-        setTimeout(function(){initThirdListener();}, 0);
+      setMockMotion(motionData2);
+      // Note: this should not stop Device Motion updates,
+      // because there is still one listener active.
+      window.removeEventListener('devicemotion', secondListener);
+      setTimeout(initThirdListener, 0);
     }
-}
+  }
 
-var childFrame;
-function initThirdListener() {
+  var childFrame;
+  function initThirdListener() {
     childFrame = document.createElement('iframe');
     document.body.appendChild(childFrame);
     childFrame.contentWindow.addEventListener('devicemotion', thirdListener);
-}
+  }
 
-function thirdListener(event) {
+  var thirdListener = test.step_func(event => {
     // Expect the cached event because Device Motion was already active
     // when third listener was added.
-    checkMotion(event);
+    checkMotion(event, motionData1);
     window.removeEventListener('devicemotion', firstListener);
     childFrame.contentWindow.removeEventListener('devicemotion', thirdListener);
-    setTimeout(function(){initFourthListener();}, 0);
-}
+    setTimeout(initFourthListener, 0);
+  });
 
-function initFourthListener() {
-    expectedEvent = mockEvent;
+  function initFourthListener() {
     window.addEventListener('devicemotion', fourthListener);
-}
+  }
 
-function fourthListener(event) {
-    checkMotion(event);
-    finishJSTest();
-}
+  var fourthListener = test.step_func(event => {
+    checkMotion(event, motionData2);
+    test.done();
+  });
 
-setMockMotion(1, 2, 3,
-              4, 5, 6,
-              7, 8, 9,
-              0);
-expectedEvent = mockEvent;
-window.addEventListener('devicemotion', firstListener);
-window.addEventListener('devicemotion', secondListener);
-
-window.jsTestIsAsync = true;
-
+  setMockMotion(motionData1);
+  window.addEventListener('devicemotion', firstListener);
+  window.addEventListener('devicemotion', secondListener);
+}, 'Tests using multiple event handlers for the Device Motion API.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/null-values-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/null-values-expected.txt
deleted file mode 100644
index 00acf33..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/null-values-expected.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-Tests using null values for some or all of the event properties.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS deviceMotionEvent.acceleration.x is mockEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is mockEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is mockEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is mockEvent.interval
-PASS deviceMotionEvent.acceleration.x is mockEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is mockEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is mockEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is mockEvent.interval
-PASS deviceMotionEvent.acceleration.x is mockEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is mockEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is mockEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is mockEvent.interval
-PASS deviceMotionEvent.acceleration.x is mockEvent.accelerationX
-PASS deviceMotionEvent.acceleration.y is mockEvent.accelerationY
-PASS deviceMotionEvent.acceleration.z is mockEvent.accelerationZ
-PASS deviceMotionEvent.accelerationIncludingGravity.x is mockEvent.accelerationIncludingGravityX
-PASS deviceMotionEvent.accelerationIncludingGravity.y is mockEvent.accelerationIncludingGravityY
-PASS deviceMotionEvent.accelerationIncludingGravity.z is mockEvent.accelerationIncludingGravityZ
-PASS deviceMotionEvent.rotationRate.alpha is mockEvent.rotationRateAlpha
-PASS deviceMotionEvent.rotationRate.beta is mockEvent.rotationRateBeta
-PASS deviceMotionEvent.rotationRate.gamma is mockEvent.rotationRateGamma
-PASS deviceMotionEvent.interval is mockEvent.interval
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/null-values.html b/third_party/WebKit/LayoutTests/device_orientation/motion/null-values.html
index 18c966b..e2e3bc8 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/null-values.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/null-values.html
@@ -1,109 +1,75 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/device-orientation-helpers.js"></script>
 <script>
-description('Tests using null values for some or all of the event properties.');
+'use strict';
 
-var mockEvent;
-function setMockMotion(accelerationX, accelerationY, accelerationZ,
-                       accelerationIncludingGravityX, accelerationIncludingGravityY, accelerationIncludingGravityZ,
-                       rotationRateAlpha, rotationRateBeta, rotationRateGamma,
-                       interval) {
+async_test(test => {
+  assertTestRunner();
+  var motionData1 = generateMotionData(null, null, null,
+                                       null, null, null,
+                                       null, null, null,
+                                       0);
 
-    mockEvent = {accelerationX: accelerationX, accelerationY: accelerationY, accelerationZ: accelerationZ,
-                 accelerationIncludingGravityX: accelerationIncludingGravityX, accelerationIncludingGravityY: accelerationIncludingGravityY, accelerationIncludingGravityZ: accelerationIncludingGravityZ,
-                 rotationRateAlpha: rotationRateAlpha, rotationRateBeta: rotationRateBeta, rotationRateGamma: rotationRateGamma,
-                 interval: interval};
+  var motionData2 = generateMotionData(1, 2, 3,
+                                       null, null, null,
+                                       null, null, null,
+                                       100);
 
-    if (window.testRunner)
-        testRunner.setMockDeviceMotion(null != mockEvent.accelerationX, null == mockEvent.accelerationX ? 0 : mockEvent.accelerationX,
-                                       null != mockEvent.accelerationY, null == mockEvent.accelerationY ? 0 : mockEvent.accelerationY,
-                                       null != mockEvent.accelerationZ, null == mockEvent.accelerationZ ? 0 : mockEvent.accelerationZ,
-                                       null != mockEvent.accelerationIncludingGravityX, null == mockEvent.accelerationIncludingGravityX ? 0 : mockEvent.accelerationIncludingGravityX,
-                                       null != mockEvent.accelerationIncludingGravityY, null == mockEvent.accelerationIncludingGravityY ? 0 : mockEvent.accelerationIncludingGravityY,
-                                       null != mockEvent.accelerationIncludingGravityZ, null == mockEvent.accelerationIncludingGravityZ ? 0 : mockEvent.accelerationIncludingGravityZ,
-                                       null != mockEvent.rotationRateAlpha, null == mockEvent.rotationRateAlpha ? 0 : mockEvent.rotationRateAlpha,
-                                       null != mockEvent.rotationRateBeta, null == mockEvent.rotationRateBeta ? 0 : mockEvent.rotationRateBeta,
-                                       null != mockEvent.rotationRateGamma, null == mockEvent.rotationRateGamma ? 0 : mockEvent.rotationRateGamma,
-                                       interval);
-    else
-        debug('This test can not be run without the TestRunner');
-}
+  var motionData3 = generateMotionData(null, null, null,
+                                       1, 2, 3,
+                                       null, null, null,
+                                       100);
 
+  var motionData4 = generateMotionData(null, null, null,
+                                       null, null, null,
+                                       1, 2, 3,
+                                       100);
 
-var deviceMotionEvent;
-function checkMotion(event) {
-    deviceMotionEvent = event;
-    shouldBe('deviceMotionEvent.acceleration.x', 'mockEvent.accelerationX');
-    shouldBe('deviceMotionEvent.acceleration.y', 'mockEvent.accelerationY');
-    shouldBe('deviceMotionEvent.acceleration.z', 'mockEvent.accelerationZ');
-
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.x', 'mockEvent.accelerationIncludingGravityX');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.y', 'mockEvent.accelerationIncludingGravityY');
-    shouldBe('deviceMotionEvent.accelerationIncludingGravity.z', 'mockEvent.accelerationIncludingGravityZ');
-
-    shouldBe('deviceMotionEvent.rotationRate.alpha', 'mockEvent.rotationRateAlpha');
-    shouldBe('deviceMotionEvent.rotationRate.beta', 'mockEvent.rotationRateBeta');
-    shouldBe('deviceMotionEvent.rotationRate.gamma', 'mockEvent.rotationRateGamma');
-
-    shouldBe('deviceMotionEvent.interval', 'mockEvent.interval');
-}
-
-function firstListener(event) {
-    checkMotion(event);
+  var firstListener = test.step_func(event => {
+    checkMotion(event, motionData1);
     window.removeEventListener('devicemotion', firstListener);
-    setTimeout(function(){initSecondListener();}, 0);
-}
+    setTimeout(initSecondListener, 0);
+  });
 
-function initSecondListener() {
-    setMockMotion(1, 2, 3,
-              null, null, null,
-              null, null, null,
-              100);
+  function initSecondListener() {
+    setMockMotion(motionData2);
     window.addEventListener('devicemotion', secondListener);
-}
+  }
 
-function secondListener(event) {
-    checkMotion(event);
+  var secondListener = test.step_func(event => {
+    checkMotion(event, motionData2);
     window.removeEventListener('devicemotion', secondListener);
-    setTimeout(function(){initThirdListener();}, 0);
-}
+    setTimeout(initThirdListener, 0);
+  });
 
-function initThirdListener() {
-    setMockMotion(null, null, null,
-                  1, 2, 3,
-                  null, null, null,
-                  100);
+  function initThirdListener() {
+    setMockMotion(motionData3);
     window.addEventListener('devicemotion', thirdListener);
-}
+  }
 
-function thirdListener(event) {
-    checkMotion(event);
+  var thirdListener = test.step_func(event => {
+    checkMotion(event, motionData3);
     window.removeEventListener('devicemotion', thirdListener);
-    setTimeout(function(){initFourthListener();}, 0);
-}
+    setTimeout(initFourthListener, 0);
+  });
 
-function initFourthListener() {
-    setMockMotion(null, null, null,
-                  null, null, null,
-                  1, 2, 3,
-                  100);
+  function initFourthListener() {
+    setMockMotion(motionData4);
     window.addEventListener('devicemotion', fourthListener);
-}
+  }
 
-function fourthListener(event) {
-    checkMotion(event);
-    finishJSTest();
-}
+  var fourthListener = test.step_func(event => {
+    checkMotion(event, motionData4);
+    test.done();
+  });
 
-setMockMotion(null, null, null,
-              null, null, null,
-              null, null, null,
-              0);
-window.addEventListener('devicemotion', firstListener);
-
-window.jsTestIsAsync = true;
+  setMockMotion(motionData1);
+  window.addEventListener('devicemotion', firstListener);
+}, 'Tests using null values for some or all of the event properties.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/optional-event-properties-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/optional-event-properties-expected.txt
deleted file mode 100644
index 858fada3..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/optional-event-properties-expected.txt
+++ /dev/null
@@ -1,114 +0,0 @@
-Tests the optional properties of DeviceMotionEvent. Each property should be null if not set, or set to null or undefined.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-event = document.createEvent('DeviceMotionEvent')
-PASS event.acceleration == null is true
-PASS event.accelerationIncludingGravity == null is true
-PASS event.rotationRate == null is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: 4, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: 8}, interval: 9})
-PASS event.acceleration.x == 0 is true
-PASS event.acceleration.y == 1 is true
-PASS event.acceleration.z == 2 is true
-PASS event.accelerationIncludingGravity.x == 3 is true
-PASS event.accelerationIncludingGravity.y == 4 is true
-PASS event.accelerationIncludingGravity.z == 5 is true
-PASS event.rotationRate.alpha == 6 is true
-PASS event.rotationRate.beta == 7 is true
-PASS event.rotationRate.gamma == 8 is true
-PASS event.interval == 9 is true
-PASS event = new DeviceMotionEvent('', {acceleration: objectThrowingException, accelerationIncludingGravity: {x: 3, z: 5}, rotationRate: {gamma: 8, beta: 7}, interval: 9}) threw exception Error: x getter exception.
-PASS event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: objectThrowingException, rotationRate: {gamma: 8, beta: 7}, interval: 9}) threw exception Error: x getter exception.
-PASS event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, z: 5}, rotationRate: objectThrowingException, interval: 9}) threw exception Error: alpha getter exception.
-PASS event = new DeviceMotionEvent('', {acceleration: {x: objectThrowingException, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: 4, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: 8}, interval: 9}) threw exception Error: valueOf threw exception.
-PASS event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: objectThrowingException, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: 8}, interval: 9}) threw exception Error: valueOf threw exception.
-PASS event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: 4, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: objectThrowingException}, interval: 9}) threw exception Error: valueOf threw exception.
-event = new DeviceMotionEvent('', {acceleration: {y: 1, x: 0}, accelerationIncludingGravity: {x: 3, z: 5}, rotationRate: {gamma: 8, beta: 7}, interval: 9})
-PASS event.acceleration.x == 0 is true
-PASS event.acceleration.y == 1 is true
-PASS event.acceleration.z == null is true
-PASS event.accelerationIncludingGravity.x == 3 is true
-PASS event.accelerationIncludingGravity.y == null is true
-PASS event.accelerationIncludingGravity.z == 5 is true
-PASS event.rotationRate.alpha == null is true
-PASS event.rotationRate.beta == 7 is true
-PASS event.rotationRate.gamma == 8 is true
-PASS event.interval == 9 is true
-event = new DeviceMotionEvent('')
-PASS event.acceleration == null is true
-PASS event.accelerationIncludingGravity == null is true
-PASS event.rotationRate == null is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: [], accelerationIncludingGravity: [], rotationRate: [], interval: []})
-PASS event.acceleration.x == null is true
-PASS event.acceleration.y == null is true
-PASS event.acceleration.z == null is true
-PASS event.accelerationIncludingGravity.x == null is true
-PASS event.accelerationIncludingGravity.y == null is true
-PASS event.accelerationIncludingGravity.z == null is true
-PASS event.rotationRate.alpha == null is true
-PASS event.rotationRate.beta == null is true
-PASS event.rotationRate.gamma == null is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: [], accelerationIncludingGravity: undefined, rotationRate: undefined, interval: undefined})
-PASS event.acceleration.x == null is true
-PASS event.acceleration.y == null is true
-PASS event.acceleration.z == null is true
-PASS event.accelerationIncludingGravity == null is true
-PASS event.rotationRate == null is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: null, accelerationIncludingGravity: null, rotationRate: null, interval: null})
-PASS event.acceleration == null is true
-PASS event.accelerationIncludingGravity == null is true
-PASS event.rotationRate == null is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: {x: null, y: null, z: null}, accelerationIncludingGravity: {x: null, y: null, z: null}, rotationRate: {alpha: null, beta: null, gamma: null}, interval: null})
-PASS event.acceleration.x == null is true
-PASS event.acceleration.y == null is true
-PASS event.acceleration.z == null is true
-PASS event.accelerationIncludingGravity.x == null is true
-PASS event.accelerationIncludingGravity.y == null is true
-PASS event.accelerationIncludingGravity.z == null is true
-PASS event.rotationRate.alpha == null is true
-PASS event.rotationRate.beta == null is true
-PASS event.rotationRate.gamma == null is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: {x: null, y: null, z: 1}, accelerationIncludingGravity: {x: null, y: null, z: 2}, rotationRate: {alpha: null, beta: null, gamma: 3}, interval: null})
-PASS event.acceleration.x == null is true
-PASS event.acceleration.y == null is true
-PASS event.acceleration.z == 1 is true
-PASS event.accelerationIncludingGravity.x == null is true
-PASS event.accelerationIncludingGravity.y == null is true
-PASS event.accelerationIncludingGravity.z == 2 is true
-PASS event.rotationRate.alpha == null is true
-PASS event.rotationRate.beta == null is true
-PASS event.rotationRate.gamma == 3 is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: {x: undefined, y: undefined, z: undefined}, accelerationIncludingGravity: {x: undefined, y: undefined, z: undefined}, rotationRate: {alpha: undefined, beta: undefined, gamma: undefined}, interval: undefined})
-PASS event.acceleration.x == null is true
-PASS event.acceleration.y == null is true
-PASS event.acceleration.z == null is true
-PASS event.accelerationIncludingGravity.x == null is true
-PASS event.accelerationIncludingGravity.y == null is true
-PASS event.accelerationIncludingGravity.z == null is true
-PASS event.rotationRate.alpha == null is true
-PASS event.rotationRate.beta == null is true
-PASS event.rotationRate.gamma == null is true
-PASS event.interval == 0 is true
-event = new DeviceMotionEvent('', {acceleration: {x: undefined, y: undefined, z: 1}, accelerationIncludingGravity: {x: undefined, y: undefined, z: 2}, rotationRate: {alpha: undefined, beta: undefined, gamma: 3}, interval: undefined})
-PASS event.acceleration.x == null is true
-PASS event.acceleration.y == null is true
-PASS event.acceleration.z == 1 is true
-PASS event.accelerationIncludingGravity.x == null is true
-PASS event.accelerationIncludingGravity.y == null is true
-PASS event.accelerationIncludingGravity.z == 2 is true
-PASS event.rotationRate.alpha == null is true
-PASS event.rotationRate.beta == null is true
-PASS event.rotationRate.gamma == 3 is true
-PASS event.interval == 0 is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/optional-event-properties.html b/third_party/WebKit/LayoutTests/device_orientation/motion/optional-event-properties.html
index be6b5c3..30ff4dd 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/optional-event-properties.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/optional-event-properties.html
@@ -1,9 +1,10 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-description("Tests the optional properties of DeviceMotionEvent. Each property should be null if not set, or set to null or undefined.");
+'use strict';
 
 function ObjectThrowingException() {};
 ObjectThrowingException.prototype.valueOf = function() { throw new Error('valueOf threw exception'); }
@@ -11,130 +12,242 @@
 ObjectThrowingException.prototype.__defineGetter__("alpha", function() { throw new Error('alpha getter exception'); });
 var objectThrowingException = new ObjectThrowingException();
 
-function testException(expression, expectedException)
-{
-    shouldThrow(expression, '(function() { return "' + expectedException + '"; })();');
-}
+test(test => {
+  event = document.createEvent('DeviceMotionEvent');
+  assert_equals(event.acceleration, null);
+  assert_equals(event.accelerationIncludingGravity, null);
+  assert_equals(event.rotationRate, null);
+  assert_equals(event.interval, 0);
+}, 'Tests creating a DeviceMotionEvent.');
 
-var event;
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2},
+                                     accelerationIncludingGravity: {x: 3, y: 4, z: 5},
+                                     rotationRate: {alpha: 6, beta: 7, gamma: 8},
+                                     interval: 9});
+  assert_equals(event.acceleration.x, 0);
+  assert_equals(event.acceleration.y, 1);
+  assert_equals(event.acceleration.z, 2);
+  assert_equals(event.accelerationIncludingGravity.x, 3);
+  assert_equals(event.accelerationIncludingGravity.y, 4);
+  assert_equals(event.accelerationIncludingGravity.z, 5);
+  assert_equals(event.rotationRate.alpha, 6);
+  assert_equals(event.rotationRate.beta, 7);
+  assert_equals(event.rotationRate.gamma, 8);
+  assert_equals(event.interval, 9);
+}, 'Tests no missing value.');
 
-evalAndLog("event = document.createEvent('DeviceMotionEvent')");
-shouldBeTrue("event.acceleration == null");
-shouldBeTrue("event.accelerationIncludingGravity == null");
-shouldBeTrue("event.rotationRate == null");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  try {
+    event = new DeviceMotionEvent('', {acceleration: objectThrowingException,
+                                       accelerationIncludingGravity: {x: 3, z: 5},
+                                       rotationRate: {gamma: 8, beta: 7},
+                                       interval: 9});
+    assert_unreached("Invalid acceleration, must throw an Error exception");
+  } catch (e) {
+    assert_equals(e.name, "Error");
+    assert_equals(e.message, "x getter exception");
+  }
+}, 'Tests invalid acceleration.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: 4, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: 8}, interval: 9})");
-shouldBeTrue("event.acceleration.x == 0");
-shouldBeTrue("event.acceleration.y == 1");
-shouldBeTrue("event.acceleration.z == 2");
-shouldBeTrue("event.accelerationIncludingGravity.x == 3");
-shouldBeTrue("event.accelerationIncludingGravity.y == 4");
-shouldBeTrue("event.accelerationIncludingGravity.z == 5");
-shouldBeTrue("event.rotationRate.alpha == 6");
-shouldBeTrue("event.rotationRate.beta == 7");
-shouldBeTrue("event.rotationRate.gamma == 8");
-shouldBeTrue("event.interval == 9");
+test(test => {
+  try {
+    event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2},
+                                       accelerationIncludingGravity: objectThrowingException,
+                                       rotationRate: {gamma: 8, beta: 7},
+                                       interval: 9});
+    assert_unreached("Invalid acelerationIncludingGravity, must throw an Error exception");
+  } catch (e) {
+    assert_equals(e.name, "Error");
+    assert_equals(e.message, "x getter exception");
+  }
+}, 'Tests invalid acelerationIncludingGravity.');
 
-testException("event = new DeviceMotionEvent('', {acceleration: objectThrowingException, accelerationIncludingGravity: {x: 3, z: 5}, rotationRate: {gamma: 8, beta: 7}, interval: 9})", "Error: x getter exception");
-testException("event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: objectThrowingException, rotationRate: {gamma: 8, beta: 7}, interval: 9})", "Error: x getter exception");
-testException("event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, z: 5}, rotationRate: objectThrowingException, interval: 9})", "Error: alpha getter exception");
+test(test => {
+  try {
+    event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2},
+                                       accelerationIncludingGravity: {x: 3, z: 5},
+                                       rotationRate: objectThrowingException,
+                                       interval: 9});
+    assert_unreached("Invalid rotationRate, must throw an Error exception");
+  } catch (e) {
+    assert_equals(e.name, "Error");
+    assert_equals(e.message, "alpha getter exception");
+  }
+}, 'Tests invalid rotationRate.');
 
-testException("event = new DeviceMotionEvent('', {acceleration: {x: objectThrowingException, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: 4, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: 8}, interval: 9})", "Error: valueOf threw exception");
-testException("event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: objectThrowingException, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: 8}, interval: 9})", "Error: valueOf threw exception");
-testException("event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2}, accelerationIncludingGravity: {x: 3, y: 4, z: 5}, rotationRate: {alpha: 6, beta: 7, gamma: objectThrowingException}, interval: 9})", "Error: valueOf threw exception");
+test(test => {
+  try {
+    event = new DeviceMotionEvent('', {acceleration: {x: objectThrowingException, y: 1, z: 2},
+                                       accelerationIncludingGravity: {x: 3, y: 4, z: 5},
+                                       rotationRate: {alpha: 6, beta: 7, gamma: 8},
+                                       interval: 9});
+    assert_unreached("Invalid acceleration.x, must throw an Error exception");
+  } catch (e) {
+    assert_equals(e.name, "Error");
+    assert_equals(e.message, "valueOf threw exception");
+  }
+}, 'Tests invalid acceleration.x.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: {y: 1, x: 0}, accelerationIncludingGravity: {x: 3, z: 5}, rotationRate: {gamma: 8, beta: 7}, interval: 9})");
-shouldBeTrue("event.acceleration.x == 0");
-shouldBeTrue("event.acceleration.y == 1");
-shouldBeTrue("event.acceleration.z == null");
-shouldBeTrue("event.accelerationIncludingGravity.x == 3");
-shouldBeTrue("event.accelerationIncludingGravity.y == null");
-shouldBeTrue("event.accelerationIncludingGravity.z == 5");
-shouldBeTrue("event.rotationRate.alpha == null");
-shouldBeTrue("event.rotationRate.beta == 7");
-shouldBeTrue("event.rotationRate.gamma == 8");
-shouldBeTrue("event.interval == 9");
+test(test => {
+  try {
+    event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2},
+                                       accelerationIncludingGravity: {x: 3, y: objectThrowingException, z: 5},
+                                       rotationRate: {alpha: 6, beta: 7, gamma: 8},
+                                       interval: 9});
+    assert_unreached("Invalid accelerationIncludingGravity.y, must throw an Error exception");
+  } catch (e) {
+    assert_equals(e.name, "Error");
+    assert_equals(e.message, "valueOf threw exception");
+  }
+}, 'Tests invalid accelerationIncludingGravity.y.');
 
-evalAndLog("event = new DeviceMotionEvent('')");
-shouldBeTrue("event.acceleration == null");
-shouldBeTrue("event.accelerationIncludingGravity == null");
-shouldBeTrue("event.rotationRate == null");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  try {
+    event = new DeviceMotionEvent('', {acceleration: {x: 0, y: 1, z: 2},
+                                       accelerationIncludingGravity: {x: 3, y: 4, z: 5},
+                                       rotationRate: {alpha: 6, beta: 7, gamma: objectThrowingException},
+                                       interval: 9});
+    assert_unreached("Invalid rotationRate.gamma, must throw an Error exception");
+  } catch (e) {
+    assert_equals(e.name, "Error");
+    assert_equals(e.message, "valueOf threw exception");
+  }
+}, 'Tests invalid rotationRate.gamma.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: [], accelerationIncludingGravity: [], rotationRate: [], interval: []})");
-shouldBeTrue("event.acceleration.x == null");
-shouldBeTrue("event.acceleration.y == null");
-shouldBeTrue("event.acceleration.z == null");
-shouldBeTrue("event.accelerationIncludingGravity.x == null");
-shouldBeTrue("event.accelerationIncludingGravity.y == null");
-shouldBeTrue("event.accelerationIncludingGravity.z == null");
-shouldBeTrue("event.rotationRate.alpha == null");
-shouldBeTrue("event.rotationRate.beta == null");
-shouldBeTrue("event.rotationRate.gamma == null");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: {y: 1, x: 0},
+                                     accelerationIncludingGravity: {x: 3, z: 5},
+                                     rotationRate: {gamma: 8, beta: 7},
+                                     interval: 9});
+  assert_equals(event.acceleration.x, 0);
+  assert_equals(event.acceleration.y, 1);
+  assert_equals(event.acceleration.z, null);
+  assert_equals(event.accelerationIncludingGravity.x, 3);
+  assert_equals(event.accelerationIncludingGravity.y, null);
+  assert_equals(event.accelerationIncludingGravity.z, 5);
+  assert_equals(event.rotationRate.alpha, null);
+  assert_equals(event.rotationRate.beta, 7);
+  assert_equals(event.rotationRate.gamma, 8);
+  assert_equals(event.interval, 9);
+}, 'Tests missing fields should be null.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: [], accelerationIncludingGravity: undefined, rotationRate: undefined, interval: undefined})");
-shouldBeTrue("event.acceleration.x == null");
-shouldBeTrue("event.acceleration.y == null");
-shouldBeTrue("event.acceleration.z == null");
-shouldBeTrue("event.accelerationIncludingGravity == null");
-shouldBeTrue("event.rotationRate == null");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  event = new DeviceMotionEvent('');
+  assert_equals(event.acceleration, null);
+  assert_equals(event.accelerationIncludingGravity, null);
+  assert_equals(event.rotationRate, null);
+  assert_equals(event.interval, 0);
+}, 'Tests DeviceMotionEvent default constructor.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: null, accelerationIncludingGravity: null, rotationRate: null, interval: null})");
-shouldBeTrue("event.acceleration == null");
-shouldBeTrue("event.accelerationIncludingGravity == null");
-shouldBeTrue("event.rotationRate == null");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: [],
+                                     accelerationIncludingGravity: [],
+                                     rotationRate: [],
+                                     interval: []});
+  assert_equals(event.acceleration.x, null);
+  assert_equals(event.acceleration.y, null);
+  assert_equals(event.acceleration.z, null);
+  assert_equals(event.accelerationIncludingGravity.x, null);
+  assert_equals(event.accelerationIncludingGravity.y, null);
+  assert_equals(event.accelerationIncludingGravity.z, null);
+  assert_equals(event.rotationRate.alpha, null);
+  assert_equals(event.rotationRate.beta, null);
+  assert_equals(event.rotationRate.gamma, null);
+  assert_equals(event.interval, 0);
+}, 'Tests all values are empty array.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: {x: null, y: null, z: null}, accelerationIncludingGravity: {x: null, y: null, z: null}, rotationRate: {alpha: null, beta: null, gamma: null}, interval: null})");
-shouldBeTrue("event.acceleration.x == null");
-shouldBeTrue("event.acceleration.y == null");
-shouldBeTrue("event.acceleration.z == null");
-shouldBeTrue("event.accelerationIncludingGravity.x == null");
-shouldBeTrue("event.accelerationIncludingGravity.y == null");
-shouldBeTrue("event.accelerationIncludingGravity.z == null");
-shouldBeTrue("event.rotationRate.alpha == null");
-shouldBeTrue("event.rotationRate.beta == null");
-shouldBeTrue("event.rotationRate.gamma == null");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: [],
+                                     accelerationIncludingGravity: undefined,
+                                     rotationRate: undefined,
+                                     interval: undefined});
+  assert_equals(event.acceleration.x, null);
+  assert_equals(event.acceleration.y, null);
+  assert_equals(event.acceleration.z, null);
+  assert_equals(event.accelerationIncludingGravity, null);
+  assert_equals(event.rotationRate, null);
+  assert_equals(event.interval, 0);
+}, 'Tests some values are empty array and some values are undefined.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: {x: null, y: null, z: 1}, accelerationIncludingGravity: {x: null, y: null, z: 2}, rotationRate: {alpha: null, beta: null, gamma: 3}, interval: null})");
-shouldBeTrue("event.acceleration.x == null");
-shouldBeTrue("event.acceleration.y == null");
-shouldBeTrue("event.acceleration.z == 1");
-shouldBeTrue("event.accelerationIncludingGravity.x == null");
-shouldBeTrue("event.accelerationIncludingGravity.y == null");
-shouldBeTrue("event.accelerationIncludingGravity.z == 2");
-shouldBeTrue("event.rotationRate.alpha == null");
-shouldBeTrue("event.rotationRate.beta == null");
-shouldBeTrue("event.rotationRate.gamma == 3");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: null,
+                                     accelerationIncludingGravity: null,
+                                     rotationRate: null,
+                                     interval: null});
+  assert_equals(event.acceleration, null);
+  assert_equals(event.accelerationIncludingGravity, null);
+  assert_equals(event.rotationRate, null);
+  assert_equals(event.interval, 0);
+}, "Tests all values are null.");
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: {x: undefined, y: undefined, z: undefined}, accelerationIncludingGravity: {x: undefined, y: undefined, z: undefined}, rotationRate: {alpha: undefined, beta: undefined, gamma: undefined}, interval: undefined})");
-shouldBeTrue("event.acceleration.x == null");
-shouldBeTrue("event.acceleration.y == null");
-shouldBeTrue("event.acceleration.z == null");
-shouldBeTrue("event.accelerationIncludingGravity.x == null");
-shouldBeTrue("event.accelerationIncludingGravity.y == null");
-shouldBeTrue("event.accelerationIncludingGravity.z == null");
-shouldBeTrue("event.rotationRate.alpha == null");
-shouldBeTrue("event.rotationRate.beta == null");
-shouldBeTrue("event.rotationRate.gamma == null");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: {x: null, y: null, z: null},
+                                     accelerationIncludingGravity: {x: null, y: null, z: null},
+                                     rotationRate: {alpha: null, beta: null, gamma: null},
+                                     interval: null});
+  assert_equals(event.acceleration.x, null);
+  assert_equals(event.acceleration.y, null);
+  assert_equals(event.acceleration.z, null);
+  assert_equals(event.accelerationIncludingGravity.x, null);
+  assert_equals(event.accelerationIncludingGravity.y, null);
+  assert_equals(event.accelerationIncludingGravity.z, null);
+  assert_equals(event.rotationRate.alpha, null);
+  assert_equals(event.rotationRate.beta, null);
+  assert_equals(event.rotationRate.gamma, null);
+  assert_equals(event.interval, 0);
+}, 'Tests all fields are null.');
 
-evalAndLog("event = new DeviceMotionEvent('', {acceleration: {x: undefined, y: undefined, z: 1}, accelerationIncludingGravity: {x: undefined, y: undefined, z: 2}, rotationRate: {alpha: undefined, beta: undefined, gamma: 3}, interval: undefined})");
-shouldBeTrue("event.acceleration.x == null");
-shouldBeTrue("event.acceleration.y == null");
-shouldBeTrue("event.acceleration.z == 1");
-shouldBeTrue("event.accelerationIncludingGravity.x == null");
-shouldBeTrue("event.accelerationIncludingGravity.y == null");
-shouldBeTrue("event.accelerationIncludingGravity.z == 2");
-shouldBeTrue("event.rotationRate.alpha == null");
-shouldBeTrue("event.rotationRate.beta == null");
-shouldBeTrue("event.rotationRate.gamma == 3");
-shouldBeTrue("event.interval == 0");
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: {x: null, y: null, z: 1},
+                                     accelerationIncludingGravity: {x: null, y: null, z: 2},
+                                     rotationRate: {alpha: null, beta: null, gamma: 3},
+                                     interval: null});
+  assert_equals(event.acceleration.x, null);
+  assert_equals(event.acceleration.y, null);
+  assert_equals(event.acceleration.z, 1);
+  assert_equals(event.accelerationIncludingGravity.x, null);
+  assert_equals(event.accelerationIncludingGravity.y, null);
+  assert_equals(event.accelerationIncludingGravity.z, 2);
+  assert_equals(event.rotationRate.alpha, null);
+  assert_equals(event.rotationRate.beta, null);
+  assert_equals(event.rotationRate.gamma, 3);
+  assert_equals(event.interval, 0);
+}, 'Tests some fields are null.');
+
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: {x: undefined, y: undefined, z: undefined},
+                                     accelerationIncludingGravity: {x: undefined, y: undefined, z: undefined},
+                                     rotationRate: {alpha: undefined, beta: undefined, gamma: undefined},
+                                     interval: undefined});
+  assert_equals(event.acceleration.x, null);
+  assert_equals(event.acceleration.y, null);
+  assert_equals(event.acceleration.z, null);
+  assert_equals(event.accelerationIncludingGravity.x, null);
+  assert_equals(event.accelerationIncludingGravity.y, null);
+  assert_equals(event.accelerationIncludingGravity.z, null);
+  assert_equals(event.rotationRate.alpha, null);
+  assert_equals(event.rotationRate.beta, null);
+  assert_equals(event.rotationRate.gamma, null);
+  assert_equals(event.interval, 0);
+}, 'Tests all fields are undefined.');
+
+test(test => {
+  event = new DeviceMotionEvent('', {acceleration: {x: undefined, y: undefined, z: 1},
+                                     accelerationIncludingGravity: {x: undefined, y: undefined, z: 2},
+                                     rotationRate: {alpha: undefined, beta: undefined, gamma: 3},
+                                     interval: undefined});
+  assert_equals(event.acceleration.x, null);
+  assert_equals(event.acceleration.y, null);
+  assert_equals(event.acceleration.z, 1);
+  assert_equals(event.accelerationIncludingGravity.x, null);
+  assert_equals(event.accelerationIncludingGravity.y, null);
+  assert_equals(event.accelerationIncludingGravity.z, 2);
+  assert_equals(event.rotationRate.alpha, null);
+  assert_equals(event.rotationRate.beta, null);
+  assert_equals(event.rotationRate.gamma, 3);
+  assert_equals(event.interval, 0);
+}, 'Tests some fields are undefined.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/page-visibility-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/page-visibility-expected.txt
deleted file mode 100644
index 854c7b81..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/page-visibility-expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-Tests to check that devicemotion events are not fired when the page is not visible.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-* Page is visible
-PASS Received a devicemotion event
-* Page is hidden
-PASS Did not receive a devicemotion event
-* Page is visible
-PASS Received a devicemotion event
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/page-visibility.html b/third_party/WebKit/LayoutTests/device_orientation/motion/page-visibility.html
index 65e663a7..b187700 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/page-visibility.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/page-visibility.html
@@ -1,58 +1,48 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/device-orientation-helpers.js"></script>
 <script>
+'use strict';
 
-description('Tests to check that devicemotion events are not fired when the page is not visible.');
-window.jsTestIsAsync = true;
+async_test(test => {
+  assertTestRunner();
 
-function succeedAndFinish()
-{
-    testPassed("Received a devicemotion event");
-    finishJSTest();
-}
+  var motionData = generateMotionData(0, 0, 0,
+                                      0, 0, 0,
+                                      0, 0, 0,
+                                      0);
+  var succeedAndFinish = test.step_func(() => {
+    test.done();
+  });
 
-function testWithPageVisible()
-{
-    testPassed("Did not receive a devicemotion event");
+  function testWithPageVisible() {
     window.removeEventListener('devicemotion', failAndFinish);
-    if (window.testRunner)
-        testRunner.setPageVisibility("visible");
-    debug("* Page is visible");
+    testRunner.setPageVisibility("visible");
     window.addEventListener('devicemotion', succeedAndFinish);
-}
+  }
 
-function failAndFinish()
-{
-    testFailed('Should not have received a devicemotion event while the page was hidden');
-    finishJSTest();
-}
+  var failAndFinish = test.step_func(() => {
+    assert_unreached("Should not have received a devicemotion event while the page was hidden");
+    test.done();
+  });
 
-function testWithPageHidden()
-{
-    testPassed("Received a devicemotion event");
+  function testWithPageHidden() {
     window.removeEventListener('devicemotion', deviceMotionListener);
-    if (window.testRunner)
-        testRunner.setPageVisibility("hidden");
-    debug("* Page is hidden");
+    testRunner.setPageVisibility("hidden");
     window.addEventListener('devicemotion', failAndFinish);
-
     setTimeout(testWithPageVisible, 100);
-}
+  }
 
-function deviceMotionListener(event) {
+  var deviceMotionListener = test.step_func(() => {
     setTimeout(testWithPageHidden, 0);
-}
+  });
 
-if (window.testRunner)
-    testRunner.setMockDeviceMotion(true, 0, true, 0, true, 0,
-                                   true, 0, true, 0, true, 0,
-                                   true, 0, true, 0, true, 0,
-                                   0);
-
-debug("* Page is visible");
-window.addEventListener('devicemotion', deviceMotionListener);
+  setMockMotion(motionData);
+  window.addEventListener('devicemotion', deviceMotionListener);
+}, 'Tests to check that devicemotion events are not fired when the page is not visible.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/window-property-expected.txt b/third_party/WebKit/LayoutTests/device_orientation/motion/window-property-expected.txt
deleted file mode 100644
index a891785..0000000
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/window-property-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Tests that the window.DeviceMotionEvent and window.ondevicemotion properties are present.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-FAIL typeof window.DeviceMotionEvent == 'object' should be true. Was false.
-FAIL typeof window.DeviceMotionEvent == 'function' should be false. Was true.
-FAIL hasDeviceMotionEventProperty() should be true. Was false.
-PASS 'DeviceMotionEvent' in window is true
-PASS window.hasOwnProperty('DeviceMotionEvent') is true
-PASS typeof window.ondevicemotion == 'object' is true
-PASS hasOnDeviceMotionProperty() is true
-PASS 'ondevicemotion' in window is true
-PASS window.hasOwnProperty('ondevicemotion') is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/device_orientation/motion/window-property.html b/third_party/WebKit/LayoutTests/device_orientation/motion/window-property.html
index cd308cb..7e66b379 100644
--- a/third_party/WebKit/LayoutTests/device_orientation/motion/window-property.html
+++ b/third_party/WebKit/LayoutTests/device_orientation/motion/window-property.html
@@ -1,38 +1,40 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-description("Tests that the window.DeviceMotionEvent and window.ondevicemotion properties are present.");
+'use strict';
 
 function hasDeviceMotionEventProperty()
 {
-    for (var property in window) {
-        if (property == "DeviceMotionEvent")
-            return true;
-    }
-    return false;
+  for (var property in window) {
+    if (property == "DeviceMotionEvent")
+      return true;
+  }
+  return false;
 }
 
-shouldBeTrue("typeof window.DeviceMotionEvent == 'object'");
-shouldBeFalse("typeof window.DeviceMotionEvent == 'function'");
-shouldBeTrue("hasDeviceMotionEventProperty()");
-shouldBeTrue("'DeviceMotionEvent' in window");
-shouldBeTrue("window.hasOwnProperty('DeviceMotionEvent')");
-
 function hasOnDeviceMotionProperty()
 {
-    for (var property in window) {
-        if (property == "ondevicemotion")
-            return true;
-    }
-    return false;
+  for (var property in window) {
+    if (property == "ondevicemotion")
+      return true;
+  }
+  return false;
 }
 
-shouldBeTrue("typeof window.ondevicemotion == 'object'");
-shouldBeTrue("hasOnDeviceMotionProperty()");
-shouldBeTrue("'ondevicemotion' in window");
-shouldBeTrue("window.hasOwnProperty('ondevicemotion')");
+test(test => {
+  assert_equals(typeof window.DeviceMotionEvent, 'function');
+  assert_false(hasDeviceMotionEventProperty());
+  assert_true('DeviceMotionEvent' in window);
+  assert_true(window.hasOwnProperty('DeviceMotionEvent'));
+
+  assert_equals(typeof window.ondevicemotion, 'object');
+  assert_true(hasOnDeviceMotionProperty());
+  assert_true('ondevicemotion' in window);
+  assert_true(window.hasOwnProperty('ondevicemotion'));
+}, 'Tests that the window.DeviceMotionEvent and window.ondevicemotion properties are present.');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/device_orientation/resources/device-orientation-helpers.js b/third_party/WebKit/LayoutTests/device_orientation/resources/device-orientation-helpers.js
new file mode 100644
index 0000000..7c432c8e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/device_orientation/resources/device-orientation-helpers.js
@@ -0,0 +1,63 @@
+'use strict';
+
+function assertTestRunner() {
+  assert_true(window.testRunner instanceof Object,
+    "This test can not be run without the window.testRunner.");
+}
+
+function generateMotionData(accelerationX, accelerationY, accelerationZ,
+                            accelerationIncludingGravityX,
+                            accelerationIncludingGravityY,
+                            accelerationIncludingGravityZ,
+                            rotationRateAlpha, rotationRateBeta, rotationRateGamma,
+                            interval) {
+  var motionData = {accelerationX: accelerationX,
+                    accelerationY: accelerationY,
+                    accelerationZ: accelerationZ,
+                    accelerationIncludingGravityX: accelerationIncludingGravityX,
+                    accelerationIncludingGravityY: accelerationIncludingGravityY,
+                    accelerationIncludingGravityZ: accelerationIncludingGravityZ,
+                    rotationRateAlpha: rotationRateAlpha,
+                    rotationRateBeta: rotationRateBeta,
+                    rotationRateGamma: rotationRateGamma,
+                    interval: interval};
+  return motionData;
+}
+
+function setMockMotion(motionData) {
+  testRunner.setMockDeviceMotion(null != motionData.accelerationX,
+      null == motionData.accelerationX ? 0 : motionData.accelerationX,
+      null != motionData.accelerationY,
+      null == motionData.accelerationY ? 0 : motionData.accelerationY,
+      null != motionData.accelerationZ,
+      null == motionData.accelerationZ ? 0 : motionData.accelerationZ,
+      null != motionData.accelerationIncludingGravityX,
+      null == motionData.accelerationIncludingGravityX ? 0 : motionData.accelerationIncludingGravityX,
+      null != motionData.accelerationIncludingGravityY,
+      null == motionData.accelerationIncludingGravityY ? 0 : motionData.accelerationIncludingGravityY,
+      null != motionData.accelerationIncludingGravityZ,
+      null == motionData.accelerationIncludingGravityZ ? 0 : motionData.accelerationIncludingGravityZ,
+      null != motionData.rotationRateAlpha,
+      null == motionData.rotationRateAlpha ? 0 : motionData.rotationRateAlpha,
+      null != motionData.rotationRateBeta,
+      null == motionData.rotationRateBeta ? 0 : motionData.rotationRateBeta,
+      null != motionData.rotationRateGamma,
+      null == motionData.rotationRateGamma ? 0 : motionData.rotationRateGamma,
+      motionData.interval);
+}
+
+function checkMotion(event, expectedMotionData) {
+  assert_equals(event.acceleration.x, expectedMotionData.accelerationX, "acceleration.x");
+  assert_equals(event.acceleration.y, expectedMotionData.accelerationY, "acceleration.y");
+  assert_equals(event.acceleration.z, expectedMotionData.accelerationZ, "acceleration.z");
+
+  assert_equals(event.accelerationIncludingGravity.x, expectedMotionData.accelerationIncludingGravityX, "accelerationIncludingGravity.x");
+  assert_equals(event.accelerationIncludingGravity.y, expectedMotionData.accelerationIncludingGravityY, "accelerationIncludingGravity.y");
+  assert_equals(event.accelerationIncludingGravity.z, expectedMotionData.accelerationIncludingGravityZ, "accelerationIncludingGravity.z");
+
+  assert_equals(event.rotationRate.alpha, expectedMotionData.rotationRateAlpha, "rotationRate.alpha");
+  assert_equals(event.rotationRate.beta, expectedMotionData.rotationRateBeta, "rotationRate.beta");
+  assert_equals(event.rotationRate.gamma, expectedMotionData.rotationRateGamma, "rotationRate.gamma");
+
+  assert_equals(event.interval, expectedMotionData.interval, "interval");
+}
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/switch-multiple-list-items-crash-expected.txt b/third_party/WebKit/LayoutTests/editing/execCommand/switch-multiple-list-items-crash-expected.txt
deleted file mode 100644
index 22741bb..0000000
--- a/third_party/WebKit/LayoutTests/editing/execCommand/switch-multiple-list-items-crash-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This test ensures WebKit does not crash when switching the type of a list with multiple list items.
-PASS
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/switch-multiple-list-items-crash.html b/third_party/WebKit/LayoutTests/editing/execCommand/switch-multiple-list-items-crash.html
index c879d81..08b9cc06 100644
--- a/third_party/WebKit/LayoutTests/editing/execCommand/switch-multiple-list-items-crash.html
+++ b/third_party/WebKit/LayoutTests/editing/execCommand/switch-multiple-list-items-crash.html
@@ -1,19 +1,32 @@
-<html><head><script>
-
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-function go() {
-    document.execCommand("selectall");
-    document.designMode="on";
-    document.execCommand("InsertLineBreak");
-    document.execCommand("insertimage");
-    document.execCommand("InsertOrderedList");
-    document.execCommand("inserthtml", false, "z");
-    document.execCommand("InsertHorizontalRule");
-    document.execCommand("selectall");
-    document.execCommand("createlink", false, "z");
-    document.execCommand("insertunorderedlist");
-    document.body.innerHTML = 'This test ensures WebKit does not crash when switching the type of a list with multiple list items.<br>PASS';
-}
-</script></head><body onload="go();"></body></html>
+<!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
+<script>
+test(() => assert_selection(
+  [
+  '<div contenteditable>',
+    '<a href="z">^<br></a>',
+    '<ol>',
+      '<li>',
+        '<a href="Z"><img>z</a>',
+        '<hr>',
+      '|</li>',
+    '</ol>',
+  '</div>'
+  ],
+  'insertunorderedlist',
+  [
+  '<div contenteditable>',
+    '<ul>',
+      '<li>',
+        '<font color="#0000ee"><u>^<br></u></font>',
+      '</li>',
+      '<li>',
+        '<a href="Z"><img>z</a><hr>|',
+      '</li>',
+    '</ul>',
+  '</div>'
+  ]),
+  "This InsertOrderedList switches the type of a list with multiple list items");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 4c77e87..5e43b5f 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -151,6 +151,480 @@
      {}
     ]
    ],
+   "core-aam/alert-manual.html": [
+    [
+     "/core-aam/alert-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/alertdialog-manual.html": [
+    [
+     "/core-aam/alertdialog-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/application-manual.html": [
+    [
+     "/core-aam/application-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/article-manual.html": [
+    [
+     "/core-aam/article-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/banner_new-manual.html": [
+    [
+     "/core-aam/banner_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/button_with_aria-haspopup__dialog__new-manual.html": [
+    [
+     "/core-aam/button_with_aria-haspopup__dialog__new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/button_with_aria-haspopup__true__new-manual.html": [
+    [
+     "/core-aam/button_with_aria-haspopup__true__new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual.html": [
+    [
+     "/core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/button_with_defined_value_for_aria-pressed-manual.html": [
+    [
+     "/core-aam/button_with_defined_value_for_aria-pressed-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/cell_new-manual.html": [
+    [
+     "/core-aam/cell_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/checkbox-manual.html": [
+    [
+     "/core-aam/checkbox-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/columnheader-manual.html": [
+    [
+     "/core-aam/columnheader-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/combobox-manual.html": [
+    [
+     "/core-aam/combobox-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/complementary_new-manual.html": [
+    [
+     "/core-aam/complementary_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/contentinfo_new-manual.html": [
+    [
+     "/core-aam/contentinfo_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/definition-manual.html": [
+    [
+     "/core-aam/definition-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/dialog-manual.html": [
+    [
+     "/core-aam/dialog-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/directory-manual.html": [
+    [
+     "/core-aam/directory-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/document-manual.html": [
+    [
+     "/core-aam/document-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/feed_new-manual.html": [
+    [
+     "/core-aam/feed_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/figure_new-manual.html": [
+    [
+     "/core-aam/figure_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/form_new-manual.html": [
+    [
+     "/core-aam/form_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/grid-manual.html": [
+    [
+     "/core-aam/grid-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/gridcell-manual.html": [
+    [
+     "/core-aam/gridcell-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/group-manual.html": [
+    [
+     "/core-aam/group-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/heading-manual.html": [
+    [
+     "/core-aam/heading-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/img-manual.html": [
+    [
+     "/core-aam/img-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/link-manual.html": [
+    [
+     "/core-aam/link-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/list-manual.html": [
+    [
+     "/core-aam/list-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/listbox_not_owned_by_or_child_of_combobox-manual.html": [
+    [
+     "/core-aam/listbox_not_owned_by_or_child_of_combobox-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/listbox_owned_by_or_child_of_combobox-manual.html": [
+    [
+     "/core-aam/listbox_owned_by_or_child_of_combobox-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/listitem-manual.html": [
+    [
+     "/core-aam/listitem-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/log-manual.html": [
+    [
+     "/core-aam/log-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/main_new-manual.html": [
+    [
+     "/core-aam/main_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/marquee-manual.html": [
+    [
+     "/core-aam/marquee-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/math-manual.html": [
+    [
+     "/core-aam/math-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/menu-manual.html": [
+    [
+     "/core-aam/menu-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/menubar-manual.html": [
+    [
+     "/core-aam/menubar-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/menuitem_not_owned_by_or_child_of_group-manual.html": [
+    [
+     "/core-aam/menuitem_not_owned_by_or_child_of_group-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/menuitem_owned_by_or_child_of_group-manual.html": [
+    [
+     "/core-aam/menuitem_owned_by_or_child_of_group-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/menuitemcheckbox-manual.html": [
+    [
+     "/core-aam/menuitemcheckbox-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/menuitemradio-manual.html": [
+    [
+     "/core-aam/menuitemradio-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/navigation_new-manual.html": [
+    [
+     "/core-aam/navigation_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/none_new-manual.html": [
+    [
+     "/core-aam/none_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/note-manual.html": [
+    [
+     "/core-aam/note-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/option_inside_combobox-manual.html": [
+    [
+     "/core-aam/option_inside_combobox-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/option_not_inside_combobox-manual.html": [
+    [
+     "/core-aam/option_not_inside_combobox-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/presentation-manual.html": [
+    [
+     "/core-aam/presentation-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/progressbar-manual.html": [
+    [
+     "/core-aam/progressbar-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/radio-manual.html": [
+    [
+     "/core-aam/radio-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/radiogroup-manual.html": [
+    [
+     "/core-aam/radiogroup-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/region_with_an_accessible_name_new-manual.html": [
+    [
+     "/core-aam/region_with_an_accessible_name_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/region_without_an_accessible_name_new-manual.html": [
+    [
+     "/core-aam/region_without_an_accessible_name_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/row_inside_treegrid-manual.html": [
+    [
+     "/core-aam/row_inside_treegrid-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/row_not_inside_treegrid-manual.html": [
+    [
+     "/core-aam/row_not_inside_treegrid-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/rowgroup-manual.html": [
+    [
+     "/core-aam/rowgroup-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/rowheader-manual.html": [
+    [
+     "/core-aam/rowheader-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/scrollbar-manual.html": [
+    [
+     "/core-aam/scrollbar-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/search_new-manual.html": [
+    [
+     "/core-aam/search_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/searchbox_new-manual.html": [
+    [
+     "/core-aam/searchbox_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/separator_focusable_new-manual.html": [
+    [
+     "/core-aam/separator_focusable_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/separator_non-focusable-manual.html": [
+    [
+     "/core-aam/separator_non-focusable-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/slider-manual.html": [
+    [
+     "/core-aam/slider-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/spinbutton-manual.html": [
+    [
+     "/core-aam/spinbutton-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/status-manual.html": [
+    [
+     "/core-aam/status-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/switch_new-manual.html": [
+    [
+     "/core-aam/switch_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/tab-manual.html": [
+    [
+     "/core-aam/tab-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/table_new-manual.html": [
+    [
+     "/core-aam/table_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/tablist-manual.html": [
+    [
+     "/core-aam/tablist-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/tabpanel-manual.html": [
+    [
+     "/core-aam/tabpanel-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/term_new-manual.html": [
+    [
+     "/core-aam/term_new-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/textbox_when_aria-multiline_is_false-manual.html": [
+    [
+     "/core-aam/textbox_when_aria-multiline_is_false-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/textbox_when_aria-multiline_is_true-manual.html": [
+    [
+     "/core-aam/textbox_when_aria-multiline_is_true-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/timer-manual.html": [
+    [
+     "/core-aam/timer-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/toolbar-manual.html": [
+    [
+     "/core-aam/toolbar-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/tooltip-manual.html": [
+    [
+     "/core-aam/tooltip-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/tree-manual.html": [
+    [
+     "/core-aam/tree-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/treegrid-manual.html": [
+    [
+     "/core-aam/treegrid-manual.html",
+     {}
+    ]
+   ],
+   "core-aam/treeitem-manual.html": [
+    [
+     "/core-aam/treeitem-manual.html",
+     {}
+    ]
+   ],
    "css/CSS2/floats-clear/floating-replaced-height-008.xht": [
     [
      "/css/CSS2/floats-clear/floating-replaced-height-008.xht",
@@ -3283,6 +3757,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-canvas-element/2d.scaled-manual.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.scaled-manual.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_allow_top_navigation_by_user_activation-manual.html": [
     [
      "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_allow_top_navigation_by_user_activation-manual.html",
@@ -62213,6 +62693,42 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html": [
+    [
+     "/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html",
+     [
+      [
+       "/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-embed-element/embed-represent-nothing-03.html": [
+    [
+     "/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-03.html",
+     [
+      [
+       "/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html": [
+    [
+     "/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html",
+     [
+      [
+       "/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/iframe-with-base.html": [
     [
      "/html/semantics/embedded-content/the-iframe-element/iframe-with-base.html",
@@ -62273,6 +62789,42 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-video-element/video_dynamic_poster_absolute.htm": [
+    [
+     "/html/semantics/embedded-content/the-video-element/video_dynamic_poster_absolute.htm",
+     [
+      [
+       "/html/semantics/embedded-content/the-video-element/video_dynamic_poster-ref.htm",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-video-element/video_dynamic_poster_relative.htm": [
+    [
+     "/html/semantics/embedded-content/the-video-element/video_dynamic_poster_relative.htm",
+     [
+      [
+       "/html/semantics/embedded-content/the-video-element/video_dynamic_poster-ref.htm",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-video-element/video_initially_paused.html": [
+    [
+     "/html/semantics/embedded-content/the-video-element/video_initially_paused.html",
+     [
+      [
+       "/html/semantics/embedded-content/the-video-element/video_initially_paused-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/semantics/forms/the-input-element/image01.html": [
     [
      "/html/semantics/forms/the-input-element/image01.html",
@@ -69005,6 +69557,11 @@
      {}
     ]
    ],
+   "XMLHttpRequest/resources/access-control-preflight-request-header-sorted.py": [
+    [
+     {}
+    ]
+   ],
    "XMLHttpRequest/resources/access-control-preflight-request-invalid-status.py": [
     [
      {}
@@ -70505,26 +71062,6 @@
      {}
     ]
    ],
-   "content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html.sub.headers": [
-    [
-     {}
-    ]
-   ],
-   "content-security-policy/blink-contrib/object-src-applet-archive.sub.html.sub.headers": [
-    [
-     {}
-    ]
-   ],
-   "content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html.sub.headers": [
-    [
-     {}
-    ]
-   ],
-   "content-security-policy/blink-contrib/object-src-applet-code.sub.html.sub.headers": [
-    [
-     {}
-    ]
-   ],
    "content-security-policy/blink-contrib/object-src-no-url-allowed.sub.html.sub.headers": [
     [
      {}
@@ -71730,6 +72267,406 @@
      {}
     ]
    ],
+   "core-aam/README.md": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/alert-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/alertdialog-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/application-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/article-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/banner_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/button_with_aria-haspopup__dialog__new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/button_with_aria-haspopup__true__new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/button_with_defined_value_for_aria-pressed-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/cell_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/checkbox-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/columnheader-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/combobox-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/complementary_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/contentinfo_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/definition-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/dialog-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/directory-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/document-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/feed_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/figure_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/form_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/grid-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/gridcell-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/group-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/heading-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/img-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/link-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/list-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/listbox_not_owned_by_or_child_of_combobox-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/listbox_owned_by_or_child_of_combobox-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/listitem-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/log-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/main_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/marquee-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/math-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/menu-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/menubar-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/menuitem_not_owned_by_or_child_of_group-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/menuitem_owned_by_or_child_of_group-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/menuitemcheckbox-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/menuitemradio-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/navigation_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/none_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/note-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/option_inside_combobox-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/option_not_inside_combobox-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/presentation-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/progressbar-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/radio-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/radiogroup-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/region_with_an_accessible_name_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/region_without_an_accessible_name_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/row_inside_treegrid-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/row_not_inside_treegrid-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/rowgroup-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/rowheader-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/scrollbar-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/search_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/searchbox_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/separator_focusable_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/separator_non-focusable-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/slider-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/spinbutton-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/status-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/switch_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/tab-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/table_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/tablist-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/tabpanel-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/term_new-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/textbox_when_aria-multiline_is_false-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/textbox_when_aria-multiline_is_true-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/timer-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/toolbar-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/tooltip-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/tree-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/treegrid-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "core-aam/treeitem-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "cors/OWNERS": [
     [
      {}
@@ -100850,16 +101787,6 @@
      {}
     ]
    ],
-   "html/dom/documents/dom-tree-accessors/nameditem-03-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "html/dom/documents/dom-tree-accessors/nameditem-08-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/dom/documents/loading-xml-documents/.gitkeep": [
     [
      {}
@@ -101600,6 +102527,11 @@
      {}
     ]
    ],
+   "html/dom/historical-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/dom/interactions-with-xpath-and-xslt/.gitkeep": [
     [
      {}
@@ -107385,11 +108317,26 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/event_pause_noautoplay-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_play_noautoplay-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/src-expected.txt": [
     [
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/onenter-expected.txt": [
     [
      {}
@@ -107520,6 +108467,36 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/networkState_during_progress-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/paused_true_during_pause-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/resources/track.de.vtt": [
     [
      {}
@@ -107545,11 +108522,21 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/track-data-url-expected.txt": [
     [
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/resources/should-load.html": [
     [
      {}
@@ -107585,6 +108572,241 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-canvas-element/2d.scaled.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/contains.json": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/imagedata-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.colour.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.different.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.path.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.same.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.reset.cross-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.reset.redirect-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.default.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.get.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.removed.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.set.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.style.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.png": [
+    [
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.png": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-embed-element/.gitkeep": [
     [
      {}
@@ -107750,6 +108972,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-img-element/current-pixel-density/basic-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/document-base-url-ref.html": [
     [
      {}
@@ -107760,6 +108987,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-img-element/environment-changes/viewport-change-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/image-1.jpg": [
     [
      {}
@@ -107830,6 +109062,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-object-element/object-fallback-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-object-element/object-in-object-fallback-2-expected.txt": [
     [
      {}
@@ -108420,11 +109657,6 @@
      {}
     ]
    ],
-   "html/semantics/interactive-elements/the-dialog-element/dialog-close-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/interactive-elements/the-dialog-element/dialog-showModal-expected.txt": [
     [
      {}
@@ -110325,16 +111557,6 @@
      {}
     ]
    ],
-   "html/webappapis/scripting/processing-model-2/compile-error-in-setInterval-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "html/webappapis/scripting/processing-model-2/compile-error-in-setTimeout-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/webappapis/scripting/processing-model-2/compile-error-same-origin-with-hash-expected.txt": [
     [
      {}
@@ -110365,16 +111587,6 @@
      {}
     ]
    ],
-   "html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/webappapis/scripting/processing-model-2/runtime-error-same-origin-with-hash-expected.txt": [
     [
      {}
@@ -117995,6 +119207,31 @@
      {}
     ]
    ],
+   "streams/readable-byte-streams/brand-checks-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/brand-checks.dedicatedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/brand-checks.js": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/brand-checks.serviceworker.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/brand-checks.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/readable-byte-streams/general-expected.txt": [
     [
      {}
@@ -120430,11 +121667,6 @@
      {}
     ]
    ],
-   "webvtt/parsing/file-parsing/signature-invalid-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "webvtt/parsing/file-parsing/support/arrows.test": [
     [
      {}
@@ -130937,6 +132169,12 @@
      {}
     ]
    ],
+   "XMLHttpRequest/access-control-preflight-async-method-denied.htm": [
+    [
+     "/XMLHttpRequest/access-control-preflight-async-method-denied.htm",
+     {}
+    ]
+   ],
    "XMLHttpRequest/access-control-preflight-credential-async.htm": [
     [
      "/XMLHttpRequest/access-control-preflight-credential-async.htm",
@@ -130967,6 +132205,12 @@
      {}
     ]
    ],
+   "XMLHttpRequest/access-control-preflight-request-header-sorted.htm": [
+    [
+     "/XMLHttpRequest/access-control-preflight-request-header-sorted.htm",
+     {}
+    ]
+   ],
    "XMLHttpRequest/access-control-preflight-request-invalid-status-301.htm": [
     [
      "/XMLHttpRequest/access-control-preflight-request-invalid-status-301.htm",
@@ -130985,6 +132229,12 @@
      {}
     ]
    ],
+   "XMLHttpRequest/access-control-preflight-sync-header-denied.htm": [
+    [
+     "/XMLHttpRequest/access-control-preflight-sync-header-denied.htm",
+     {}
+    ]
+   ],
    "XMLHttpRequest/allow-lists-starting-with-comma.htm": [
     [
      "/XMLHttpRequest/allow-lists-starting-with-comma.htm",
@@ -133113,30 +134363,6 @@
      {}
     ]
    ],
-   "content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html": [
-    [
-     "/content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html",
-     {}
-    ]
-   ],
-   "content-security-policy/blink-contrib/object-src-applet-archive.sub.html": [
-    [
-     "/content-security-policy/blink-contrib/object-src-applet-archive.sub.html",
-     {}
-    ]
-   ],
-   "content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html": [
-    [
-     "/content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html",
-     {}
-    ]
-   ],
-   "content-security-policy/blink-contrib/object-src-applet-code.sub.html": [
-    [
-     "/content-security-policy/blink-contrib/object-src-applet-code.sub.html",
-     {}
-    ]
-   ],
    "content-security-policy/blink-contrib/object-src-no-url-allowed.sub.html": [
     [
      "/content-security-policy/blink-contrib/object-src-no-url-allowed.sub.html",
@@ -135921,6 +137147,12 @@
      {}
     ]
    ],
+   "css/css-grid-1/grid-definition/grid-shorthand-001.html": [
+    [
+     "/css/css-grid-1/grid-definition/grid-shorthand-001.html",
+     {}
+    ]
+   ],
    "css/css-grid-1/grid-definition/grid-support-flexible-lengths-001.html": [
     [
      "/css/css-grid-1/grid-definition/grid-support-flexible-lengths-001.html",
@@ -147017,6 +148249,12 @@
      {}
     ]
    ],
+   "html/dom/historical.html": [
+    [
+     "/html/dom/historical.html",
+     {}
+    ]
+   ],
    "html/dom/interfaces.html": [
     [
      "/html/dom/interfaces.html",
@@ -147841,12 +149079,170 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/audio_loop_base.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/audio_loop_base.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/audio_volume_check.html": [
     [
      "/html/semantics/embedded-content/media-elements/audio_volume_check.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/error-codes/error.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/error-codes/error.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_canplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_canplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_canplay_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_canplay_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_canplaythrough.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_canplaythrough.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_canplaythrough_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_canplaythrough_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_loadeddata.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_loadeddata.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_loadedmetadata.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_loadedmetadata.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_loadstart.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_loadstart.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_loadstart_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_loadstart_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_order_canplay_canplaythrough.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_order_canplay_canplaythrough.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_order_canplay_playing.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_order_canplay_playing.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_order_loadstart_progress.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_order_loadstart_progress.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_pause.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_pause.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_pause_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_pause_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_play.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_play.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_play_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_play_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_playing.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_playing.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_playing_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_playing_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_progress.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_progress.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_progress_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_progress_noautoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_timeupdate.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_timeupdate.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/event_timeupdate_noautoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/event_timeupdate_noautoplay.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/event_volumechange.html": [
     [
      "/html/semantics/embedded-content/media-elements/event_volumechange.html",
@@ -147913,6 +149309,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/interfaces/TextTrack/addCue.html": [
     [
      "/html/semantics/embedded-content/media-elements/interfaces/TextTrack/addCue.html",
@@ -148069,6 +149471,18 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/loading-the-media-resource/autoplay-overrides-preload.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/loading-the-media-resource/autoplay-overrides-preload.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/loading-the-media-resource/load-removes-queued-error-event.html": [
     [
      "/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-removes-queued-error-event.html",
@@ -148291,24 +149705,78 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/networkState_during_loadstart.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/networkState_during_loadstart.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/networkState_during_progress.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/networkState_during_progress.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/networkState_initial.html": [
     [
      "/html/semantics/embedded-content/media-elements/networkState_initial.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/duration.html": [
     [
      "/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/duration.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/paused_false_during_play.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/paused_false_during_play.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/paused_true_during_pause.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/paused_true_during_pause.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html": [
     [
      "/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/playing-the-media-resource/playbackRate.html": [
     [
      "/html/semantics/embedded-content/media-elements/playing-the-media-resource/playbackRate.html",
@@ -148327,12 +149795,66 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/ready-states/autoplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/ready-states/autoplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/readyState_during_canplay.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/readyState_during_canplay.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/readyState_during_canplaythrough.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/readyState_during_canplaythrough.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/readyState_during_playing.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/readyState_during_playing.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/readyState_initial.html": [
     [
      "/html/semantics/embedded-content/media-elements/readyState_initial.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm": [
+    [
+     "/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm": [
+    [
+     "/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html": [
     [
      "/html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html",
@@ -148351,18 +149873,44 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/track-data-url.html": [
     [
      "/html/semantics/embedded-content/media-elements/track/track-element/track-data-url.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/user-interface/muted.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/user-interface/muted.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/video_008.htm": [
     [
      "/html/semantics/embedded-content/media-elements/video_008.htm",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/video_loop_base.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/video_loop_base.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/video_volume_check.html": [
     [
      "/html/semantics/embedded-content/media-elements/video_volume_check.html",
@@ -148411,6 +149959,732 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-canvas-element/2d.canvas.readonly.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.canvas.readonly.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.canvas.reference.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.canvas.reference.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.getcontext.exists.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.getcontext.exists.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.getcontext.extraargs.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.getcontext.extraargs.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.getcontext.shared.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.getcontext.shared.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.getcontext.unique.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.getcontext.unique.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.type.exists.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.type.exists.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.type.extend.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.type.extend.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.type.prototype.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.type.prototype.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/2d.type.replace.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/2d.type.replace.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/context.arguments.missing.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/context.arguments.missing.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/context.casesensitive.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/context.casesensitive.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/context.emptystring.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/context.emptystring.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/context.unrecognised.badname.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badname.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/context.unrecognised.badsuffix.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badsuffix.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/context.unrecognised.nullsuffix.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/context.unrecognised.nullsuffix.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/context.unrecognised.unicode.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/context.unrecognised.unicode.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/fallback.basic.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/fallback.basic.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/fallback.multiple.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/fallback.multiple.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/fallback.nested.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/fallback.nested.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/historical.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/historical.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/imagedata.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/imagedata.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.colour.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.colour.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.clip.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.clip.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.different.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.different.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.gradient.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.gradient.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.path.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.path.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.pattern.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.pattern.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.same.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.same.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/initial.reset.transform.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/initial.reset.transform.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.dataURI.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.dataURI.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.drawImage.image.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.drawImage.image.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.create.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.create.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.create.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.create.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.cross.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.cross.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.reset.cross.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.reset.cross.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/security.reset.redirect.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/security.reset.redirect.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.default.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.default.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.idl.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.idl.set.zero.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.set.zero.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.hex.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.hex.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.zero.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.zero.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidlzero.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidlzero.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.removed.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.removed.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.hex.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.hex.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.zero.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.zero.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/size.attributes.style.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/size.attributes.style.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toBlob.jpeg.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toBlob.jpeg.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toBlob.null.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toBlob.null.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toBlob.png.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toBlob.png.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.1.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.1.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.2.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.2.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.3.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.3.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.bogustype.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.bogustype.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.default.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.default.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.notnumber.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.notnumber.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.outsiderange.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.outsiderange.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.jpg.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.jpg.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.ascii.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.ascii.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.unicode.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.unicode.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.nocontext.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.nocontext.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.png.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.png.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.unrecognised.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.unrecognised.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.zeroheight.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.zeroheight.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.zerosize.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.zerosize.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/toDataURL.zerowidth.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/toDataURL.zerowidth.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/type.delete.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/type.delete.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/type.exists.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/type.exists.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/type.extend.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/type.extend.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/type.name.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/type.name.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/type.prototype.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/type.prototype.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-canvas-element/type.replace.html": [
+    [
+     "/html/semantics/embedded-content/the-canvas-element/type.replace.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-embed-element/embed-dimension.html": [
+    [
+     "/html/semantics/embedded-content/the-embed-element/embed-dimension.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-embed-element/embed-document.html": [
     [
      "/html/semantics/embedded-content/the-embed-element/embed-document.html",
@@ -148585,6 +150859,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html": [
+    [
+     "/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/current-pixel-density/error.html": [
     [
      "/html/semantics/embedded-content/the-img-element/current-pixel-density/error.html",
@@ -148633,6 +150913,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html": [
+    [
+     "/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/img.complete.html": [
     [
      "/html/semantics/embedded-content/the-img-element/img.complete.html",
@@ -148663,6 +150949,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-img-element/relevant-mutations.html": [
+    [
+     "/html/semantics/embedded-content/the-img-element/relevant-mutations.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute.html": [
     [
      "/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute.html",
@@ -148725,6 +151017,18 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-object-element/object-events.html": [
+    [
+     "/html/semantics/embedded-content/the-object-element/object-events.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/the-object-element/object-fallback.html": [
+    [
+     "/html/semantics/embedded-content/the-object-element/object-fallback.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-object-element/object-handler.html": [
     [
      "/html/semantics/embedded-content/the-object-element/object-handler.html",
@@ -164709,6 +167013,12 @@
      {}
     ]
    ],
+   "payment-request/payment-request-shippingAddress-attribute.https.html": [
+    [
+     "/payment-request/payment-request-shippingAddress-attribute.https.html",
+     {}
+    ]
+   ],
    "payment-request/payment-request-shippingType-attribute.https.html": [
     [
      "/payment-request/payment-request-shippingType-attribute.https.html",
@@ -175913,6 +178223,30 @@
      {}
     ]
    ],
+   "streams/readable-byte-streams/brand-checks.dedicatedworker.html": [
+    [
+     "/streams/readable-byte-streams/brand-checks.dedicatedworker.html",
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/brand-checks.html": [
+    [
+     "/streams/readable-byte-streams/brand-checks.html",
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/brand-checks.serviceworker.https.html": [
+    [
+     "/streams/readable-byte-streams/brand-checks.serviceworker.https.html",
+     {}
+    ]
+   ],
+   "streams/readable-byte-streams/brand-checks.sharedworker.html": [
+    [
+     "/streams/readable-byte-streams/brand-checks.sharedworker.html",
+     {}
+    ]
+   ],
    "streams/readable-byte-streams/general.dedicatedworker.html": [
     [
      "/streams/readable-byte-streams/general.dedicatedworker.html",
@@ -193542,6 +195876,10 @@
    "f69a2fdd41df78f29187bfa848e88c5c39b60736",
    "testharness"
   ],
+  "XMLHttpRequest/access-control-preflight-async-method-denied.htm": [
+   "29bb39b957742d739bb0d54464b48a53533206fe",
+   "testharness"
+  ],
   "XMLHttpRequest/access-control-preflight-credential-async.htm": [
    "ae93b44faf45f95927a1ee82052a414273333e61",
    "testharness"
@@ -193562,6 +195900,10 @@
    "1f3beb7047a0f4828d44f67664a977469af75263",
    "testharness"
   ],
+  "XMLHttpRequest/access-control-preflight-request-header-sorted.htm": [
+   "45f904c2322ee7b14cc78075f99243bbad7ecd96",
+   "testharness"
+  ],
   "XMLHttpRequest/access-control-preflight-request-invalid-status-301.htm": [
    "e59e2de75149869531b056b53501b92302fdee04",
    "testharness"
@@ -193574,6 +195916,10 @@
    "a59b9c8f77991992faade11e955061078b9d9623",
    "testharness"
   ],
+  "XMLHttpRequest/access-control-preflight-sync-header-denied.htm": [
+   "98e89f8ddccbba846b6f21f1d77b6a64554bcb52",
+   "testharness"
+  ],
   "XMLHttpRequest/allow-lists-starting-with-comma.htm": [
    "34a8d82f397f35902c73d9ced2f3cf900d04ae53",
    "testharness"
@@ -194026,6 +196372,10 @@
    "3f39f2f6bdda8c167df09525b8d23d04c16b2462",
    "support"
   ],
+  "XMLHttpRequest/resources/access-control-preflight-request-header-sorted.py": [
+   "357dbf2f01ab59c8689af632c1116d2053f3829d",
+   "support"
+  ],
   "XMLHttpRequest/resources/access-control-preflight-request-invalid-status.py": [
    "c572b1e3d79f66df0a40766e6e4c3cc785458d0e",
    "support"
@@ -196402,38 +198752,6 @@
    "368845671fc996d39fd6f85c113a26cdaa98ee3e",
    "support"
   ],
-  "content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html": [
-   "7f81f0fe6a5ed984e6084250672e598a2fe2c707",
-   "testharness"
-  ],
-  "content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html.sub.headers": [
-   "37429d7e5523b4fa092f319e0348abf62f1fe95e",
-   "support"
-  ],
-  "content-security-policy/blink-contrib/object-src-applet-archive.sub.html": [
-   "9d07979a968cea9958c237e465b3562fac0d6e65",
-   "testharness"
-  ],
-  "content-security-policy/blink-contrib/object-src-applet-archive.sub.html.sub.headers": [
-   "0e9b0159e148542c330eeb1c9501911e2e0473c0",
-   "support"
-  ],
-  "content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html": [
-   "5b0ef3d19498af074fbd2ca00b6af16774b1b4cc",
-   "testharness"
-  ],
-  "content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html.sub.headers": [
-   "eac4a0d1aecb5475bb88b223deec64209f98b25c",
-   "support"
-  ],
-  "content-security-policy/blink-contrib/object-src-applet-code.sub.html": [
-   "5827478d16c8bf8f473daae756eaeabaafdee879",
-   "testharness"
-  ],
-  "content-security-policy/blink-contrib/object-src-applet-code.sub.html.sub.headers": [
-   "8d1f3d53e9702d62946969231a45c79f26e6e287",
-   "support"
-  ],
   "content-security-policy/blink-contrib/object-src-no-url-allowed.sub.html": [
    "e4cd8d8e7a3150626eea1d6ca7beed13feb6a76c",
    "testharness"
@@ -198330,6 +200648,642 @@
    "31461ac108fe717b074a41e14c12d9b83c064f85",
    "testharness"
   ],
+  "core-aam/README.md": [
+   "a910a51a7869305635992eb784b0ddfe70d8f8ae",
+   "support"
+  ],
+  "core-aam/alert-manual-expected.txt": [
+   "6d520939a448bccdbeea133744b7a41924aa495d",
+   "support"
+  ],
+  "core-aam/alert-manual.html": [
+   "02d8baf1f695c5dfce45d67df71027949a5211b6",
+   "manual"
+  ],
+  "core-aam/alertdialog-manual-expected.txt": [
+   "b6114905a27b4b5cbf17921dfdf948e23bca375e",
+   "support"
+  ],
+  "core-aam/alertdialog-manual.html": [
+   "96fbf83d26ad1aa3a6f2904a280ab6c88b8cef59",
+   "manual"
+  ],
+  "core-aam/application-manual-expected.txt": [
+   "eb5358399204c9b431024876dea360d5b4cb3da2",
+   "support"
+  ],
+  "core-aam/application-manual.html": [
+   "cd247440cbabed171a2261632417bac42a26576b",
+   "manual"
+  ],
+  "core-aam/article-manual-expected.txt": [
+   "9f3852fea4e6d841ecfc1382c98273043595c2a6",
+   "support"
+  ],
+  "core-aam/article-manual.html": [
+   "16a599b1d4933b9ce17c083cea764aeef8fc6fff",
+   "manual"
+  ],
+  "core-aam/banner_new-manual-expected.txt": [
+   "1189be6850a263be825d8bda7e9bc222c132044f",
+   "support"
+  ],
+  "core-aam/banner_new-manual.html": [
+   "ee344b6e341649e5024e521c1cdc85f3668f8bf0",
+   "manual"
+  ],
+  "core-aam/button_with_aria-haspopup__dialog__new-manual-expected.txt": [
+   "964a67179d673f143d77bf79a3324b12156f9679",
+   "support"
+  ],
+  "core-aam/button_with_aria-haspopup__dialog__new-manual.html": [
+   "3b5d7256859e2422887aba591f5d01b27ef9c033",
+   "manual"
+  ],
+  "core-aam/button_with_aria-haspopup__true__new-manual-expected.txt": [
+   "cd45fc81ce7404ca104aeb6ac8ed6b04817f940b",
+   "support"
+  ],
+  "core-aam/button_with_aria-haspopup__true__new-manual.html": [
+   "7bd98bc98a69f8fae54c467d8092ef291e2505fe",
+   "manual"
+  ],
+  "core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual-expected.txt": [
+   "198ad97d432bd43e5dd1bed1eb37a3d527a4be0b",
+   "support"
+  ],
+  "core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual.html": [
+   "b816704abd4606ef6f51534e6c596326fe8ac4c3",
+   "manual"
+  ],
+  "core-aam/button_with_defined_value_for_aria-pressed-manual-expected.txt": [
+   "a23d50c8edc38f64ede46c7ddfac80c7ebb0fc16",
+   "support"
+  ],
+  "core-aam/button_with_defined_value_for_aria-pressed-manual.html": [
+   "e1f4e451c4390f123a4f3792a47d708a73dec908",
+   "manual"
+  ],
+  "core-aam/cell_new-manual-expected.txt": [
+   "a728e69a860987423633b15899d5267eff1d703c",
+   "support"
+  ],
+  "core-aam/cell_new-manual.html": [
+   "2da920ba8c111b9de22a8e4e430c38bda3606d9e",
+   "manual"
+  ],
+  "core-aam/checkbox-manual-expected.txt": [
+   "02c7a7467172f464ccb39bb917ea203b947115d8",
+   "support"
+  ],
+  "core-aam/checkbox-manual.html": [
+   "0e4d9205cf13d442d90646efc05770740399d42d",
+   "manual"
+  ],
+  "core-aam/columnheader-manual-expected.txt": [
+   "f5d97b6182ef1f662a76b1d6b21fb189d4854eb6",
+   "support"
+  ],
+  "core-aam/columnheader-manual.html": [
+   "0324c63751491117f58b90c6b39603140d1ac8f3",
+   "manual"
+  ],
+  "core-aam/combobox-manual-expected.txt": [
+   "449d0ef48589d6a7f5dbedcbb70577f2951e2b28",
+   "support"
+  ],
+  "core-aam/combobox-manual.html": [
+   "395f3359d35f954b6c8b53f5a1f6933413f96a17",
+   "manual"
+  ],
+  "core-aam/complementary_new-manual-expected.txt": [
+   "20b0a50b291ff32492fd93e1ab8a793154bc3e95",
+   "support"
+  ],
+  "core-aam/complementary_new-manual.html": [
+   "2577834a5c668a7117ad27065f6d472f57160cc5",
+   "manual"
+  ],
+  "core-aam/contentinfo_new-manual-expected.txt": [
+   "11a914c72db8eca01e2d8f3cd0ebbf9a4441f33a",
+   "support"
+  ],
+  "core-aam/contentinfo_new-manual.html": [
+   "75bb6f8ce69766100ff1ebf4f49d93c2be9f1f58",
+   "manual"
+  ],
+  "core-aam/definition-manual-expected.txt": [
+   "dd2afb95b6e558bb1702696b1b71ade61e638ba4",
+   "support"
+  ],
+  "core-aam/definition-manual.html": [
+   "bfe049bc485d0ea535505edec4d504475764368e",
+   "manual"
+  ],
+  "core-aam/dialog-manual-expected.txt": [
+   "7af02438b0c41ca3f78128565847df834c160a5a",
+   "support"
+  ],
+  "core-aam/dialog-manual.html": [
+   "125d0da9c5100366aab9121e26b0052c1b0377cf",
+   "manual"
+  ],
+  "core-aam/directory-manual-expected.txt": [
+   "0003b00b5e284c06541d6176bd7756adb7eccd9e",
+   "support"
+  ],
+  "core-aam/directory-manual.html": [
+   "0b4aa5e7e97e09512a46c73034e12e5461fc2bcd",
+   "manual"
+  ],
+  "core-aam/document-manual-expected.txt": [
+   "d8440d9111ffbcd602f3e937b479316eede4d930",
+   "support"
+  ],
+  "core-aam/document-manual.html": [
+   "c04b82cc3523d267f02e5692869099289bf708fb",
+   "manual"
+  ],
+  "core-aam/feed_new-manual-expected.txt": [
+   "232f055fbad0d495d6c5671fe852940b8ef4531b",
+   "support"
+  ],
+  "core-aam/feed_new-manual.html": [
+   "42603640c24cd7453a2bcd07f231a112c18ed8f7",
+   "manual"
+  ],
+  "core-aam/figure_new-manual-expected.txt": [
+   "165d95ad3b14f2af36a0d1cbb528d1fae1104769",
+   "support"
+  ],
+  "core-aam/figure_new-manual.html": [
+   "99aa4e80240eca0cb471d34c618ddace7eb39a3f",
+   "manual"
+  ],
+  "core-aam/form_new-manual-expected.txt": [
+   "fde48a0a4c632b2984b19230307ebe2189479b0a",
+   "support"
+  ],
+  "core-aam/form_new-manual.html": [
+   "15db01d459850b748206a63c182b1af7249dbfec",
+   "manual"
+  ],
+  "core-aam/grid-manual-expected.txt": [
+   "99f06ee1f1f85748f52ccac71aebb0ce99a64cea",
+   "support"
+  ],
+  "core-aam/grid-manual.html": [
+   "a387f2d5757eb820da2010bd9d1dfb5c343fe8f7",
+   "manual"
+  ],
+  "core-aam/gridcell-manual-expected.txt": [
+   "5f7a8d3e6b5fbe46f3176159d1366d4dd5f245ec",
+   "support"
+  ],
+  "core-aam/gridcell-manual.html": [
+   "c993c85b760b7dc7d9511088b4af7e1e1bd27ebf",
+   "manual"
+  ],
+  "core-aam/group-manual-expected.txt": [
+   "2197943596811bac315a2929a9bfe040c1e95eff",
+   "support"
+  ],
+  "core-aam/group-manual.html": [
+   "6700d8ee8c38c23da67d4610f263c07123329c3f",
+   "manual"
+  ],
+  "core-aam/heading-manual-expected.txt": [
+   "4bea38d64e602770bdde9fdc42bbf4b8aceac87b",
+   "support"
+  ],
+  "core-aam/heading-manual.html": [
+   "66293d0ddea32f0560509e403928699a1eb24646",
+   "manual"
+  ],
+  "core-aam/img-manual-expected.txt": [
+   "078f0608d209d01806755c52bcedb9b4877e1911",
+   "support"
+  ],
+  "core-aam/img-manual.html": [
+   "e2c779dfa16fda427ddfd394206d4d9e16ecc324",
+   "manual"
+  ],
+  "core-aam/link-manual-expected.txt": [
+   "817d5fb2fd3b0c5a56019687aac29df460e5fdf1",
+   "support"
+  ],
+  "core-aam/link-manual.html": [
+   "1cbea4cfbfe4ba255017a54f99f533bfa8c14e8f",
+   "manual"
+  ],
+  "core-aam/list-manual-expected.txt": [
+   "016987f35cb271fc3d6820c53554ba0cfb70610c",
+   "support"
+  ],
+  "core-aam/list-manual.html": [
+   "f38a581d6b7ef73f163f8729d0996857874fc3a8",
+   "manual"
+  ],
+  "core-aam/listbox_not_owned_by_or_child_of_combobox-manual-expected.txt": [
+   "bf3ffcb363190708cfec299f6c47420c1869d474",
+   "support"
+  ],
+  "core-aam/listbox_not_owned_by_or_child_of_combobox-manual.html": [
+   "1fcfd5fbcf600a9bf73745b6dbde16e602b0ceb5",
+   "manual"
+  ],
+  "core-aam/listbox_owned_by_or_child_of_combobox-manual-expected.txt": [
+   "89f7456936cf0d14e71aa2b485bf1ffcbb4f681f",
+   "support"
+  ],
+  "core-aam/listbox_owned_by_or_child_of_combobox-manual.html": [
+   "850825d4aaf2942d799b5a6655709b5b0e698bc8",
+   "manual"
+  ],
+  "core-aam/listitem-manual-expected.txt": [
+   "16c12d41f9565e29f7dc2b4eec7a2124357cb29b",
+   "support"
+  ],
+  "core-aam/listitem-manual.html": [
+   "16159e510c16bcf7cd147b8cd4c786e9bdf8d99d",
+   "manual"
+  ],
+  "core-aam/log-manual-expected.txt": [
+   "d1e8cc36961ef7e6b80b94a0b7463523ae604b56",
+   "support"
+  ],
+  "core-aam/log-manual.html": [
+   "a3ee519dbbe4451de6f1f298754bcaf26dcdc458",
+   "manual"
+  ],
+  "core-aam/main_new-manual-expected.txt": [
+   "d6db22501384ba0fb2280abbcd8dc2b2e2da6be0",
+   "support"
+  ],
+  "core-aam/main_new-manual.html": [
+   "9beef2a7a07bc774af0ad0a90f43607f889963d7",
+   "manual"
+  ],
+  "core-aam/marquee-manual-expected.txt": [
+   "2e9247fcfc794604a449f8eae32d787dea486f6d",
+   "support"
+  ],
+  "core-aam/marquee-manual.html": [
+   "4134b2e32c2ffa2d7f246dddfe25b88d5033eda9",
+   "manual"
+  ],
+  "core-aam/math-manual-expected.txt": [
+   "4b5aece2358f76882ef5323e334d46287900a52f",
+   "support"
+  ],
+  "core-aam/math-manual.html": [
+   "575f46d8c14a3085eeb873f3f61be4174e413236",
+   "manual"
+  ],
+  "core-aam/menu-manual-expected.txt": [
+   "6d118fc134b9249042f5a0ee6623932ab31b384b",
+   "support"
+  ],
+  "core-aam/menu-manual.html": [
+   "9e6272984fb83a8772f24afa9d27a9c526cc2046",
+   "manual"
+  ],
+  "core-aam/menubar-manual-expected.txt": [
+   "a24ec34fb8f9d383a09ea4e25e6caaed894005e9",
+   "support"
+  ],
+  "core-aam/menubar-manual.html": [
+   "c3d772f2dbde70d9d881d6b0f0f322a4583ce708",
+   "manual"
+  ],
+  "core-aam/menuitem_not_owned_by_or_child_of_group-manual-expected.txt": [
+   "2359b0bd2ecbeb045990a022cd4742042973bc0a",
+   "support"
+  ],
+  "core-aam/menuitem_not_owned_by_or_child_of_group-manual.html": [
+   "55e4d49ad9639d47ac82fa7889227a425a2868e3",
+   "manual"
+  ],
+  "core-aam/menuitem_owned_by_or_child_of_group-manual-expected.txt": [
+   "136f301467ddc7069f1666bec6be8bfa89d0c570",
+   "support"
+  ],
+  "core-aam/menuitem_owned_by_or_child_of_group-manual.html": [
+   "92bcf8240fb355fabe168762c4efcdd9efbaa006",
+   "manual"
+  ],
+  "core-aam/menuitemcheckbox-manual-expected.txt": [
+   "dd746171952a42945b0c2a2faa207721fde25498",
+   "support"
+  ],
+  "core-aam/menuitemcheckbox-manual.html": [
+   "226dda30c2c3368d2f3c95089901c3148fac9f27",
+   "manual"
+  ],
+  "core-aam/menuitemradio-manual-expected.txt": [
+   "c8ecdb1224cdc5a94b363d8427f77d1f9169c856",
+   "support"
+  ],
+  "core-aam/menuitemradio-manual.html": [
+   "defae7d3d9f9748f7d7ce2ce50962b256b55ddc0",
+   "manual"
+  ],
+  "core-aam/navigation_new-manual-expected.txt": [
+   "d87e12b69f89b692b236a534f4b5e726520dfcdb",
+   "support"
+  ],
+  "core-aam/navigation_new-manual.html": [
+   "f231b6953f9007557d588100d319b00d425a324b",
+   "manual"
+  ],
+  "core-aam/none_new-manual-expected.txt": [
+   "4dec5c88237826dd6ba55f4e7ee3a20b82323aaf",
+   "support"
+  ],
+  "core-aam/none_new-manual.html": [
+   "4a4adf886deeddd6984fd6b1f6013863c1052087",
+   "manual"
+  ],
+  "core-aam/note-manual-expected.txt": [
+   "e954c4255be404cfa3df2f7f62114a4677f4e6ff",
+   "support"
+  ],
+  "core-aam/note-manual.html": [
+   "60d596499a7cb3c37dee3cde25b21349f042bc2a",
+   "manual"
+  ],
+  "core-aam/option_inside_combobox-manual-expected.txt": [
+   "6262fbce8c5963b11dd03b3814a549a634ef22d4",
+   "support"
+  ],
+  "core-aam/option_inside_combobox-manual.html": [
+   "2158857762050cf13bef68c34cc267678c42ce37",
+   "manual"
+  ],
+  "core-aam/option_not_inside_combobox-manual-expected.txt": [
+   "154b6964e6cc9e81ccaed176bbd36dee3a1b06ac",
+   "support"
+  ],
+  "core-aam/option_not_inside_combobox-manual.html": [
+   "169dfc20493c4b1520490a47de099d59bdf540cb",
+   "manual"
+  ],
+  "core-aam/presentation-manual-expected.txt": [
+   "1c29c8b36c79b66c6635d4c4f61e5dd575e90afa",
+   "support"
+  ],
+  "core-aam/presentation-manual.html": [
+   "28969de0d6e28fabecccd699bce82479cb653a32",
+   "manual"
+  ],
+  "core-aam/progressbar-manual-expected.txt": [
+   "5c03dd446dc47331dc9ccf1e6e652efafbbb1f28",
+   "support"
+  ],
+  "core-aam/progressbar-manual.html": [
+   "b24273979fffbce0627c16525f614470085cb4dd",
+   "manual"
+  ],
+  "core-aam/radio-manual-expected.txt": [
+   "194b230930671fe08d5dda5b31994d9daf8388f8",
+   "support"
+  ],
+  "core-aam/radio-manual.html": [
+   "9ef5980d95ff6c59100ee1a8d0eb5ef7312a556e",
+   "manual"
+  ],
+  "core-aam/radiogroup-manual-expected.txt": [
+   "22fb0c156656ea0169ad03d3ad064dce757c48b9",
+   "support"
+  ],
+  "core-aam/radiogroup-manual.html": [
+   "9378d3936f880fd0efb62da47ad7ced426b62e34",
+   "manual"
+  ],
+  "core-aam/region_with_an_accessible_name_new-manual-expected.txt": [
+   "5962641bc177f3fa6ec371650fee7ff53fc6e1c3",
+   "support"
+  ],
+  "core-aam/region_with_an_accessible_name_new-manual.html": [
+   "4b1b9eacbdedd38a98f46020463065dd2dc61c3a",
+   "manual"
+  ],
+  "core-aam/region_without_an_accessible_name_new-manual-expected.txt": [
+   "04f605db145b69602e02025bc4796e071b48df11",
+   "support"
+  ],
+  "core-aam/region_without_an_accessible_name_new-manual.html": [
+   "1f11016d7976992072c3331d2db7dc416f9e0a0d",
+   "manual"
+  ],
+  "core-aam/row_inside_treegrid-manual-expected.txt": [
+   "c02ee9c0ee1c7ab470acc8395818553346f3f3ea",
+   "support"
+  ],
+  "core-aam/row_inside_treegrid-manual.html": [
+   "6c821c87776723303fe893b34bb38d6a223ba72d",
+   "manual"
+  ],
+  "core-aam/row_not_inside_treegrid-manual-expected.txt": [
+   "c9489eb2f684945efda6717ff256d1230cf41eb6",
+   "support"
+  ],
+  "core-aam/row_not_inside_treegrid-manual.html": [
+   "d4be6e2b01bdafa14dcae66e9a9f58b3ee27e405",
+   "manual"
+  ],
+  "core-aam/rowgroup-manual-expected.txt": [
+   "64218f06836b07a4fd4cde6f224d7013b105d63b",
+   "support"
+  ],
+  "core-aam/rowgroup-manual.html": [
+   "52c2e1e2b03ff6193d818cda71f4008e55d023f3",
+   "manual"
+  ],
+  "core-aam/rowheader-manual-expected.txt": [
+   "7470cff674a0ad4f820c0a2efd4aa9d882a57c18",
+   "support"
+  ],
+  "core-aam/rowheader-manual.html": [
+   "127bee90f419edb40e7874acc16388c4e200415a",
+   "manual"
+  ],
+  "core-aam/scrollbar-manual-expected.txt": [
+   "8635b07216ec6eecb42fc6896adfd613503f30bf",
+   "support"
+  ],
+  "core-aam/scrollbar-manual.html": [
+   "5c64840620d953f3aa4ee37d88924359210f76f6",
+   "manual"
+  ],
+  "core-aam/search_new-manual-expected.txt": [
+   "c41f9179c62814f42829de3fa447993705c1bceb",
+   "support"
+  ],
+  "core-aam/search_new-manual.html": [
+   "49ffcb0924057e8f520689a7e000db4f4a840ef4",
+   "manual"
+  ],
+  "core-aam/searchbox_new-manual-expected.txt": [
+   "e51f6856d9122807849fad0adfa32930687d98f6",
+   "support"
+  ],
+  "core-aam/searchbox_new-manual.html": [
+   "536b133c905d306dac8d345cb92554dc2d5b1a68",
+   "manual"
+  ],
+  "core-aam/separator_focusable_new-manual-expected.txt": [
+   "c3dd0beddcf18e2e138aa359febb76c9716dfad4",
+   "support"
+  ],
+  "core-aam/separator_focusable_new-manual.html": [
+   "757691240cc56cf59d8700657b778d82b139ed02",
+   "manual"
+  ],
+  "core-aam/separator_non-focusable-manual-expected.txt": [
+   "2937f5db8b8b48d1cb2e537c42234c87175b0b10",
+   "support"
+  ],
+  "core-aam/separator_non-focusable-manual.html": [
+   "a84d13a23f69d94bc9421b18196049dac215a009",
+   "manual"
+  ],
+  "core-aam/slider-manual-expected.txt": [
+   "6610f53421bb35962fe062f826b90ce0dc3e2ed9",
+   "support"
+  ],
+  "core-aam/slider-manual.html": [
+   "73a9990075ae9204899d4c7daaa851a954f6bed5",
+   "manual"
+  ],
+  "core-aam/spinbutton-manual-expected.txt": [
+   "728658277ca5c425adf12c590853da4816359fed",
+   "support"
+  ],
+  "core-aam/spinbutton-manual.html": [
+   "301d7ab36f4b9fe485d63b0db26a9a9094737f14",
+   "manual"
+  ],
+  "core-aam/status-manual-expected.txt": [
+   "0b2bfb88e4dd83e4f6d6f360932fcd0421ea7d6a",
+   "support"
+  ],
+  "core-aam/status-manual.html": [
+   "aab7d2154d9650541267979e4d5cb99df232a8ff",
+   "manual"
+  ],
+  "core-aam/switch_new-manual-expected.txt": [
+   "41a5529f1fdb443e2c7253ead62be675b6f9df0c",
+   "support"
+  ],
+  "core-aam/switch_new-manual.html": [
+   "5754cd31372954a5d4af14ce269d96b9d781ed5d",
+   "manual"
+  ],
+  "core-aam/tab-manual-expected.txt": [
+   "999eab4eecc929b08912c7f1bdd90157cd1a0fb2",
+   "support"
+  ],
+  "core-aam/tab-manual.html": [
+   "f89e46491ccbecf387bd57187833e730dd40fb7f",
+   "manual"
+  ],
+  "core-aam/table_new-manual-expected.txt": [
+   "45136cc9c2c63cb88de9829e090d8aa8c9aa6b3e",
+   "support"
+  ],
+  "core-aam/table_new-manual.html": [
+   "9befdb0b1a9caf842b3470da75a42033f352aebc",
+   "manual"
+  ],
+  "core-aam/tablist-manual-expected.txt": [
+   "013a9e94cb6ab2dee64e5beffcb91d415e54df5a",
+   "support"
+  ],
+  "core-aam/tablist-manual.html": [
+   "7bc2605f5c27789d696ea8bbbcabd08d2f65bb5c",
+   "manual"
+  ],
+  "core-aam/tabpanel-manual-expected.txt": [
+   "5645d838f0f7e8dabb6667bff0abea597750a8a6",
+   "support"
+  ],
+  "core-aam/tabpanel-manual.html": [
+   "a3cc6f18f39cd374b1ec0cb561b24468c19bd153",
+   "manual"
+  ],
+  "core-aam/term_new-manual-expected.txt": [
+   "a9d79ef7ee940411615a4c692045428c5153e3b3",
+   "support"
+  ],
+  "core-aam/term_new-manual.html": [
+   "86472c985ac1954a0239507306e6cc22343190de",
+   "manual"
+  ],
+  "core-aam/textbox_when_aria-multiline_is_false-manual-expected.txt": [
+   "978524e3a20d18c8b60acc49c1a9d1d9eaba1fa1",
+   "support"
+  ],
+  "core-aam/textbox_when_aria-multiline_is_false-manual.html": [
+   "66decde98dc0a5d9533be5f8c1de0d53bb9fb15d",
+   "manual"
+  ],
+  "core-aam/textbox_when_aria-multiline_is_true-manual-expected.txt": [
+   "f8f7168db9776b6ff12ef9f54d2568ea2e71fa59",
+   "support"
+  ],
+  "core-aam/textbox_when_aria-multiline_is_true-manual.html": [
+   "c14adf428092d0bd425928bd24a63b49ef8e6c51",
+   "manual"
+  ],
+  "core-aam/timer-manual-expected.txt": [
+   "a067ce4a7ab9a109549fc6fd84aa8440de63b92f",
+   "support"
+  ],
+  "core-aam/timer-manual.html": [
+   "ba19dc032e8642c395c84dc7724c15d8c8fd90e5",
+   "manual"
+  ],
+  "core-aam/toolbar-manual-expected.txt": [
+   "9cbb71dce09b07fbf0e3468b484c92e8a9fef92f",
+   "support"
+  ],
+  "core-aam/toolbar-manual.html": [
+   "8d9efb8c016ea162a26cfe5412cce42c893b81e8",
+   "manual"
+  ],
+  "core-aam/tooltip-manual-expected.txt": [
+   "439ac4faf2a1b96fe24da2f19edb5aa62acbfdd9",
+   "support"
+  ],
+  "core-aam/tooltip-manual.html": [
+   "6b998648736d762ab9f953af5110c41d55f6ed89",
+   "manual"
+  ],
+  "core-aam/tree-manual-expected.txt": [
+   "301068457805f0283ecccde25f79bb82c38b721e",
+   "support"
+  ],
+  "core-aam/tree-manual.html": [
+   "75ea426f9284062895acb8f9fdece77fa5da65dc",
+   "manual"
+  ],
+  "core-aam/treegrid-manual-expected.txt": [
+   "78d8734758435fd5074ef302c1f8f4f42a5ea94e",
+   "support"
+  ],
+  "core-aam/treegrid-manual.html": [
+   "78f6e81ed43630de9b093a321ab6a9cd34071a9c",
+   "manual"
+  ],
+  "core-aam/treeitem-manual-expected.txt": [
+   "143b4e7fe8f2bd3b511d2d2790130f9f07072a1a",
+   "support"
+  ],
+  "core-aam/treeitem-manual.html": [
+   "c57bf44ba5df7ca32afda36134fbeff9fc8dd2ec",
+   "manual"
+  ],
   "cors/304.htm": [
    "644c902be2861bed6dfa48ed12a12b08c6d9a2f5",
    "testharness"
@@ -223138,6 +226092,10 @@
    "e30c5d9b04eaf45a511b8df22a2c9719a03ecd92",
    "reftest"
   ],
+  "css/css-grid-1/grid-definition/grid-shorthand-001.html": [
+   "31ef1f583e9d09e4d719a0ca5cb5531e8ce08b36",
+   "testharness"
+  ],
   "css/css-grid-1/grid-definition/grid-support-flexible-lengths-001.html": [
    "f03efa4af7f9eb9decd60bfe44c7a3166947ba32",
    "testharness"
@@ -244471,11 +247429,11 @@
    "testharness"
   ],
   "dom/nodes/Node-cloneNode-expected.txt": [
-   "f46df5a70942a521fcc8a9da2483830ec68941a5",
+   "bb0e06c33d3bbd9153e73d7c1edbbe93e5c14bce",
    "support"
   ],
   "dom/nodes/Node-cloneNode.html": [
-   "f2f37f4ad272aef9f5ee46f8b44a668ff394d6c8",
+   "d4ab5a700e36fa6b8c26ffc6703d2a9020b5336e",
    "testharness"
   ],
   "dom/nodes/Node-compareDocumentPosition.html": [
@@ -251443,11 +254401,11 @@
    "support"
   ],
   "html/browsers/the-window-object/named-access-on-the-window-object/named-objects-expected.txt": [
-   "7a225dc2d15426da6e73d02dde0545c05acd984d",
+   "4e32463c271e2fb8080f9ca30c46ce09076bb0f8",
    "support"
   ],
   "html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html": [
-   "b4aed70f7618d5d5e29350f19b4c1d45c045f9cb",
+   "37377d2ed04e32f8c2ada3143fa0d2d8f70c0ad6",
    "testharness"
   ],
   "html/browsers/the-window-object/named-access-on-the-window-object/test.html": [
@@ -252090,12 +255048,8 @@
    "f5112d9d4111e61a4b87d6806f22e75ea85cb8af",
    "testharness"
   ],
-  "html/dom/documents/dom-tree-accessors/nameditem-03-expected.txt": [
-   "a56be8099ef0df8e9cb5678f460f300304b3733a",
-   "support"
-  ],
   "html/dom/documents/dom-tree-accessors/nameditem-03.html": [
-   "6692f5b790960145e7a94b25227682237cbb4862",
+   "0887edcb756daa6447497510ea7c8a3967ae8c2f",
    "testharness"
   ],
   "html/dom/documents/dom-tree-accessors/nameditem-04.html": [
@@ -252114,12 +255068,8 @@
    "f9eddafeddf7f4e7ca99b080f98e3e379b5434d0",
    "testharness"
   ],
-  "html/dom/documents/dom-tree-accessors/nameditem-08-expected.txt": [
-   "e6b3e5b0c07c42ea9a2489fb57c1b9c0d6f49cec",
-   "support"
-  ],
   "html/dom/documents/dom-tree-accessors/nameditem-08.html": [
-   "5ae6d9718f6568cf9c42a7ebdf2cbae767c68852",
+   "ffb7fbed3b9e0f2a73907358234136d5a62b6943",
    "testharness"
   ],
   "html/dom/documents/loading-xml-documents/.gitkeep": [
@@ -253606,20 +256556,28 @@
    "a4f99553c0cdf1c1efab08c85b9e3211b42d5412",
    "support"
   ],
+  "html/dom/historical-expected.txt": [
+   "810ed84324e124a97eeede13ca2ef7e0950c3f8f",
+   "support"
+  ],
+  "html/dom/historical.html": [
+   "75fd4e5379337af2ebcb3cd7d62dbf3d726c4036",
+   "testharness"
+  ],
   "html/dom/interactions-with-xpath-and-xslt/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
   "html/dom/interfaces-expected.txt": [
-   "e9c860e94f0af2d7e515ac3774ee981d928fc3e0",
+   "ba03da572c92941a19a1ff5b132f10c21267b0a8",
    "support"
   ],
   "html/dom/interfaces.html": [
-   "4c0db96824033d94b98123954254930fb742d7e3",
+   "54e9b9fdae41f484fbd84ebdb03514c147d216bf",
    "testharness"
   ],
   "html/dom/interfaces.worker-expected.txt": [
-   "e27b2571218899a677f86af0c41478b5c446ed90",
+   "decb9e90eb1a324cb0b066e065674debbdf0a693",
    "support"
   ],
   "html/dom/interfaces.worker.js": [
@@ -259250,6 +262208,10 @@
    "9dacdb9cf50ff61b0b7d31cba1304bfddc2b9a58",
    "manual"
   ],
+  "html/semantics/embedded-content/media-elements/audio_loop_base.html": [
+   "7b60d16acf933da11aa65988bf2dfada68c3b853",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html": [
    "38a1bdd2f5d5da661e43482e9050b6b708837863",
    "manual"
@@ -259274,6 +262236,114 @@
    "c4e395b396f7f8d9aac3e687d34c2df47dde5589",
    "support"
   ],
+  "html/semantics/embedded-content/media-elements/error-codes/error.html": [
+   "b13ed034ef354031000614c7f11a20d8fc17653a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_canplay.html": [
+   "e68b3bfc3a4fb897b1435fc1d7ba4596c2efbfbe",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_canplay_noautoplay.html": [
+   "49202003dc7204d997b4dcee3a99ae9b9c77399f",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_canplaythrough.html": [
+   "7f6e61d2498bb60077c50a2036430a2bf7a7ec9f",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_canplaythrough_noautoplay.html": [
+   "04dba01a3d3da718a2ea3e65078d41fbfec982be",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_loadeddata.html": [
+   "c1457d29ad55ea9e6d723e9d9d144f199f614a79",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html": [
+   "7765806a9035b1c94929eb913a68668b6268d900",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_loadedmetadata.html": [
+   "a0fa9cca891fcdf066409b225daff6d09bf53601",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html": [
+   "247eae45d09620d37ee0714475ab9677b8061b6e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_loadstart.html": [
+   "3d23314e29d44667ca09aabd4769e1c4f3b4c9bf",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_loadstart_noautoplay.html": [
+   "46ebae07f296a394fd005609e150087b00665e51",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_order_canplay_canplaythrough.html": [
+   "70e74de8fe3eab2c775489364faa1eab832ef14d",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_order_canplay_playing.html": [
+   "f9a6c488442573dfc0d06acd1f6944d8cb2d585e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html": [
+   "1f9a9ee27d7cedb3c7f128276770334780afb523",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_order_loadstart_progress.html": [
+   "013746f8434b90d53724e7cd924f8b430cdc52b3",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_pause.html": [
+   "d1d4945f75e8febfd1ed29947700da38d9adcda4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_pause_noautoplay-expected.txt": [
+   "dc1384623c574b051f8d0777a5d6c7337aa49a35",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/event_pause_noautoplay.html": [
+   "2e30c02fd6cd54ce23531a61c28405e76815d92f",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_play.html": [
+   "5ab77070444e804dbecad5260dd71ddaa4dba1cb",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_play_noautoplay-expected.txt": [
+   "c8b0eb0a04d2d54757380ab7bdf60108db691a41",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/event_play_noautoplay.html": [
+   "5d4442f1a9c94c0a141bd04bd15862e903d3c386",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_playing.html": [
+   "3cef57701c8c8591046bce55713beb0c007e775f",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_playing_noautoplay.html": [
+   "3cd57a7a9a2b46cb6b2662f77633be17f00d2f79",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_progress.html": [
+   "8297355a38ca40dbdb9021f6d28001c7515b7ee4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_progress_noautoplay.html": [
+   "7274516f1fa0685e1f919ccb38cd4601a24aa7a4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_timeupdate.html": [
+   "de8142e31455d9f1efa8cd44183263cf9f5e3b57",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/event_timeupdate_noautoplay.html": [
+   "5156765c6bc0e4ce9f6d8ca55e48f5871046f7f4",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/event_volumechange.html": [
    "b942ea11dee1f0bafacf246c73decb436090899d",
    "testharness"
@@ -259322,6 +262392,14 @@
    "d720c62464330b12e0a3f54d39ef5f078324116c",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues-expected.txt": [
+   "159c98a10ef724036ca56e183e590a6184de9a9a",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues.html": [
+   "e294dbd7b5c21fb61e0796097e1ba9f9c054dee5",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/interfaces/TextTrack/addCue.html": [
    "d8494280b25a6cfa93a57587c21c077084cb0be4",
    "testharness"
@@ -259438,6 +262516,14 @@
    "10f5ac8421e6ab23d623141f66fd48c5a9d1f2d6",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/loading-the-media-resource/autoplay-overrides-preload.html": [
+   "ffd2e043a1c07338b597366876b4ca0d79d75e16",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html": [
+   "ad2401f93e135e6c9d618870bb07d92cfd0d8dcc",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/loading-the-media-resource/load-removes-queued-error-event-expected.txt": [
    "ec4d925002e83fa32dfb829991ee31edaaad9000",
    "support"
@@ -259682,18 +262768,78 @@
    "3ea30a20d18f5c8839ccfaa183627702db38ed4b",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/networkState_during_loadstart.html": [
+   "d86a87c7d1a43a6f51d9a7d929684ddecb83fd25",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/networkState_during_progress-expected.txt": [
+   "880301efece208f9302598a6f5986e11f91bc325",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/networkState_during_progress.html": [
+   "e934a38666b8d9fe9c02650b32672ca388bfd03b",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/networkState_initial.html": [
    "b1dc1caf309baa5ec8e7cf2e256fbe0a3e453b03",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html": [
+   "fa1d49b7f98272d53e1b7bb2c7795085097c104a",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/duration.html": [
    "97eebd347a273120c3b8acb22a89ad7e274b60f0",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/paused_false_during_play.html": [
+   "ff28f3466bf3f0b6df316b774dd4ac28950dbcb7",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/paused_true_during_pause-expected.txt": [
+   "b5a4957e609a96638e035004a41a83ad55d1199f",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/paused_true_during_pause.html": [
+   "8abac7d28126bac761a5ca2b4cf4ea5550896fa9",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document-expected.txt": [
+   "e3430bbd395e023a98364b6ef233280a3d6afa32",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html": [
+   "aaa705291eba72ed3d9d3836f0de8d19720604de",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document-expected.txt": [
+   "9777f19d8798d2e83adbe2fd90989ce90ba45aca",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document.html": [
+   "09dc023213aeaf3e871ee70fafc6fa1e083010bc",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-expected.txt": [
+   "1c2d70c47033813cc407b361d39b3aa1debff82d",
+   "support"
+  ],
   "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html": [
    "79b2b6cf21717300b1d109fdc8aaa867038a4dbb",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html": [
+   "23e98284f003acebd9ea8cd6fe6d72aced95c108",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document-expected.txt": [
+   "620d3689770ca48901e87411eb438f195bec8476",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html": [
+   "0f49782d9d8d9267eb288cdc2599f2ff0a84dfa1",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/playing-the-media-resource/playbackRate.html": [
    "f529d9f469607cd8975dd2df4d0636a8ceb739e7",
    "testharness"
@@ -259706,10 +262852,46 @@
    "ff9cdde226ae066001108c2237345a5fe3a0b3a4",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/ready-states/autoplay.html": [
+   "6ca8c7a50317c932254cf8254c7638d61f8bb00a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/readyState_during_canplay.html": [
+   "7e3844240c9f1ffcde0e0cff68ca747e2ee4bd01",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/readyState_during_canplaythrough.html": [
+   "93d9bd7ab6dc10b762ba51d50612421adae3da36",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html": [
+   "05eff7f919c9c471f4116d046eb83de3a11cb890",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html": [
+   "648caf3811d8b1e07f9bfcc5f53b4be5b048f0d4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/readyState_during_playing.html": [
+   "081d656eb789fa49e09fe0e5936eb10658321aa4",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/readyState_initial.html": [
    "8897e5c41a0cd6e5b8496f05ed2dff8be7929e85",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html": [
+   "acd2bc1f7e9e368da10e9ea790ae608a8bad4e17",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm": [
+   "ba37092d24cbc787f2cdbc75e4cc2d46d371fde7",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm": [
+   "0c1329ed621ee3151d6b324ba2a3d4be5a95e4b0",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html": [
    "9032286bc0f4fb4221858847200e0f40874c68a7",
    "testharness"
@@ -259742,6 +262924,18 @@
    "9e5b2fa642544c20e04d542d9a8f701d1fa2d165",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html": [
+   "f7576ff332cac04a4e2b663b6fdd40aef154b6b5",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order-expected.txt": [
+   "2bb2fdf21fd4ec2c82315e6dcf1759f6f84e37c4",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html": [
+   "eeab6b02e728aea21878cf72664929766be057b7",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/track/track-element/track-data-url-expected.txt": [
    "83170156f9c401d4a2e34df8eb590d16487699a1",
    "support"
@@ -259750,6 +262944,14 @@
    "e9c8849350512b1247543939ee0e529947e47c2d",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt": [
+   "d993351bfab44488bce7ef0a9f3d6f351f191dfc",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/user-interface/muted.html": [
+   "74deefbbc4b8f96ff4856db1c32c6428183cc040",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/video_008.htm": [
    "087f17d5f7a75ac1990ef7ecb413fc4eaf312be5",
    "testharness"
@@ -259758,6 +262960,10 @@
    "9c0b04737cb4aa758d017d3f17dd0e71e6e4adcb",
    "manual"
   ],
+  "html/semantics/embedded-content/media-elements/video_loop_base.html": [
+   "d84abb0277613a9f38037c7dcec197fab5e8bdd9",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html": [
    "8cacab3375c6e43e59a733319268fdd1f7a5a3ce",
    "manual"
@@ -259842,10 +263048,686 @@
    "a74faddb16266717024b3a4efa21be7f4d00a85e",
    "support"
   ],
+  "html/semantics/embedded-content/the-canvas-element/2d.canvas.readonly.html": [
+   "877d238083fe2547543298613244cd51f6f071f2",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.canvas.reference.html": [
+   "168ab67c480aa80d99a2d6de7e69d47fed4c23b2",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.getcontext.exists.html": [
+   "7116376a6f5e6db863fdb0e4b975d06a7eb7e4a0",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.getcontext.extraargs.html": [
+   "742d99217ab55a83f639842102debd2f7b25f62c",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.getcontext.shared.html": [
+   "e0c2b0d46114dfeb85ab8eaa81b704d00bb23523",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.getcontext.unique.html": [
+   "2d8502310c97626f196422ae5b5cb4060c9d73cc",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.scaled-manual.html": [
+   "d757db9cf1308d4f9802743e0064953b5546d0be",
+   "manual"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.scaled.png": [
+   "324dcff206f4eced02b164d22c0ea86115f681f9",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.type.exists.html": [
+   "1cdab378022ca526b1f77fa66e8773026a99b422",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.type.extend.html": [
+   "04d192b24ee7443e4ff67d642eeb25b39d8c0e24",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.type.prototype.html": [
+   "443476ad33a4a0e82e47a799d6ed74399c54f138",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/2d.type.replace.html": [
+   "e8f238ba662aed30f87d0acb28578e053acd8bc6",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/contains.json": [
+   "535b2978af25a4cc2e1341d26f675711db8cae8c",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/context.arguments.missing.html": [
+   "9bc55c03d9f80947c642a6699bec246e76a70547",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/context.casesensitive.html": [
+   "b3c974a1fcc98d66a1f55d00e4a2298100055f48",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/context.emptystring.html": [
+   "113490b4f515a14cfe186d84e81745f739e81f31",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/context.unrecognised.badname.html": [
+   "9a85e7b30146a65d54e84b35e197033acb3d1419",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/context.unrecognised.badsuffix.html": [
+   "fd179471c03baf98e4ab4ed4b3404d4184ec259e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/context.unrecognised.nullsuffix.html": [
+   "2f03d887c3fb3c9502070b53bb3469907f9cc484",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/context.unrecognised.unicode.html": [
+   "ce5c07b2c99f88ac0ac0508e8d5a74e0785a5c6c",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/fallback.basic.html": [
+   "ef1c94aef3c9fff5d6f5394e74703098dc46f855",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/fallback.multiple.html": [
+   "91dc96caa75d304d6bff938feb526b6b71b03a33",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/fallback.nested.html": [
+   "3fc3a0d7a8b6b19764109a1ee7b662f560fb2f8e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/historical.html": [
+   "38b6f3c5707b360427854b82054d86f5364dc0b8",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/imagedata-expected.txt": [
+   "5a33efa3e6913ca1a91fab19baaf8731783a6e39",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/imagedata.html": [
+   "e685ab0d76bdd1b60a5d6f1e2126ea1a89db97d1",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.colour.html": [
+   "22ddb77f5a18a19edc409d36532120f852bfbc57",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.colour.png": [
+   "6b549fa40955b0232d58c857ee9506a255009838",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html": [
+   "fc9ec219694a04fbd5db7382e72cacd8039c88a3",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.clip.html": [
+   "b96a905e24b53ea36c94133180880a1755a64fe4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.different.html": [
+   "e43dd640a501bf34ea0bf5710a53e07e2f4db349",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.different.png": [
+   "5e139d676e811aa5e2755fef30efbd9f62f38835",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.gradient.html": [
+   "a6520e1fb405126f2d6bfd5e6131222f6de2323e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.path.html": [
+   "7b1376f4fda5d75cb2f42beed29d0c4dbf89dd60",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.path.png": [
+   "6b549fa40955b0232d58c857ee9506a255009838",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.pattern.html": [
+   "c004dc29065fd9914f61780a6b04a5ba1e55cde5",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.same.html": [
+   "49bc14fc4edf6a0bdccd8f7cdaf3586cb5607e92",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.same.png": [
+   "6b549fa40955b0232d58c857ee9506a255009838",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/initial.reset.transform.html": [
+   "711d929f6c280c1bf04b4c3485f163c600c19e1b",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.dataURI.html": [
+   "4a8ff94a4be33132d36c1e23bcf3123dc332c396",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.cross.html": [
+   "c74e8ac5a19e8eba7a225dde2fdee84f88e3c00e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.redirect.html": [
+   "51494c44452d5d0830dda02b8e60baea0e51d49f",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.drawImage.image.cross.html": [
+   "2941763c01f9cdf660ec746f51cde40b268300fe",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.drawImage.image.redirect.html": [
+   "5cc004d27ac599e0f542aec575233aacd19f6526",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.cross.html": [
+   "6f4230968c1d5f12b3157e969f6ecdcd1d5a923c",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.redirect.html": [
+   "538c30f0de6c2c1952853576d00fd1fc19bd0dde",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.cross.html": [
+   "526e41303f134c9cb0e862a4876dec2e363a1320",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.redirect.html": [
+   "a8fb8cdd1387bc67eeec3687334b303f92f91a4d",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.cross.html": [
+   "536556689e037e136d0bd3d08dacdf087ffdf609",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.redirect.html": [
+   "d90f3b399affa6d795b4f7f38643dae6ba1ea3a7",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.create.cross.html": [
+   "f5d020386b0d6707b20b585912cf4a98fd86986a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.create.redirect.html": [
+   "1d4e6e8090169ed602ba7bb71f811562cdf0a528",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.cross.cross.html": [
+   "1bb8f33901b78142c66e3e1b989b395101488457",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.cross.redirect.html": [
+   "4bf890d4778b37977b7280e42f5c004a877a18a6",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html": [
+   "8630fe5572973ec38bea623acc35ecb79e9f5e76",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.redirect.html": [
+   "05ea5c77fefdae06cb964cc2f6cfef9582418737",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.cross.html": [
+   "65390fb4f54f6359c2c6ca1e58a1423485beb689",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.redirect.html": [
+   "d7c4bac59fb35405582c7a008f0e71c20805da86",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.reset.cross-expected.txt": [
+   "5bb2752bd82fa78b479f74694c4a5d4724c58b91",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.reset.cross.html": [
+   "1b844c83c588d722d3b0ef3247d76aaacddfbe9a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.reset.redirect-expected.txt": [
+   "5bb2752bd82fa78b479f74694c4a5d4724c58b91",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/security.reset.redirect.html": [
+   "93e50cbaf157c2639f62662801dc1df4b983bde9",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.default.html": [
+   "17bd0074fb31a7f28d1f0ef995320a765f5795d4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.default.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.get.png": [
+   "3dc9815df30cd1bfbfda3f751c914b7906287a62",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.idl.html": [
+   "85efb09e8dd48374b88a3ad2be36d2d660e5bf95",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.idl.set.zero.html": [
+   "1a1a96038df6da9a186a2d34ed3cbc74251cf323",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.html": [
+   "4370b8fb87a5bcc7e398430675966e082b8900a6",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.html": [
+   "47ea2c0a879e70a24ebbf2ea9c6cfec63a7a35e1",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.html": [
+   "fc4c8a978091d1b1d27b6f51a5888242d8c3d73b",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.html": [
+   "bb4487ba4947e5aafad122c112f37c33043cfb47",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.hex.html": [
+   "4561d5e16d02f4140b6be9f535040ad8ef23341a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.html": [
+   "f95b48b8eb5fff20c28cd26cdb97693de9c149f2",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.html": [
+   "a9c150adb3fd76c6d0b5fa5497fb40b7dc3c38a5",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.html": [
+   "e8755e0f4e2be6d163d5296ba4e93750a76bbc8a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.html": [
+   "583473a6fd55676e81764ea081b425f0369e93f9",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.html": [
+   "ff3dca9acdea00bd62a097dab838ba979c3c3287",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.html": [
+   "e245cbdd25e514669dc38522db97cba1f220eb9a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.html": [
+   "982763f573a79745f4eb2ff3668270392ffc1aa2",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.html": [
+   "841613b14f7c2823e14eca5d3da90f4512a26c72",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html": [
+   "70f6750f7fcee9b8f4e91560411b670d9d5401e4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.parse.zero.html": [
+   "fc399d15b920ad2aeabdfb155f659a4813e3e817",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.html": [
+   "3553d955ad0642846b19850f38b19a31ca32c640",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.png": [
+   "3dc9815df30cd1bfbfda3f751c914b7906287a62",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.html": [
+   "8db5726b0dd8b2dd787ead9d9ff6edf549234a78",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.png": [
+   "3dc9815df30cd1bfbfda3f751c914b7906287a62",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidlzero.html": [
+   "a351e12cc92ebd8358b76bf3f1ccd53020308111",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.removed.html": [
+   "5f9f095b4a1d05de4e29036216c245c550dd2139",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.removed.png": [
+   "cb5d7d41d893842110d18b9cd5b12f7b91c7db1f",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.set.png": [
+   "3dc9815df30cd1bfbfda3f751c914b7906287a62",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.html": [
+   "f4f5ec2ca384eebd440cd278d435addc64f72c87",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.html": [
+   "304fca1217343fa51686a4681a9db4c59622d101",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.html": [
+   "84c79b174b778064c08891e24ac8e4440fc5e0c4",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.html": [
+   "9cb1c34c15b4da10a0bafe0a7f90d9cdb520dbec",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.hex.html": [
+   "ac55c206e66cd17a3177f816e779dfcc9dbda4d1",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.html": [
+   "e061e43837d166087998c7b706611f91ecbac216",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.html": [
+   "aaa95dc8b65a41e667b3c34b68cedd709b6039cf",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.html": [
+   "6c17e8d9ec2cd5d605b9c7b45e78bd13c3ba3357",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.html": [
+   "8b7372b235de4bd3ba12c08ffd78ba8332843b45",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.png": [
+   "983edae0371889ea6388a2ff38e2ea2178099275",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.html": [
+   "3361f36e895e8a89ebf1f90aa90840593da0cb08",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.html": [
+   "9d4b9f94ccbe8cc990b163bc65e65691961495b0",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.html": [
+   "804e2b98b85a3cc12b34ae3002a8bc39133fb2af",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.html": [
+   "9e0cfdf719ec61ab394e86701a0c5807ee9c548d",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.html": [
+   "61d8273233d229e41b1bde68e45ca723f876e9bc",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.png": [
+   "bcdbeae6ef68a9f10bac6d7f02fcf51e8cbabaae",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.zero.html": [
+   "00dae14fc4d1bcfef4cbeff819f150c1a85b04ca",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.style.html": [
+   "4568e6c0760e0cacd17fa7f952e9854692285464",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/size.attributes.style.png": [
+   "6b549fa40955b0232d58c857ee9506a255009838",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toBlob.jpeg.html": [
+   "6ac7096aa4c4db6206e212a6e229419d1f35bf2e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toBlob.null.html": [
+   "932034c2b0172b26a800aebaa5eb3a19e2034c93",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toBlob.png.html": [
+   "cb8667e2238b2e5b8bb703436e1dc766ba8600ae",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.1.html": [
+   "ba9b65715c0aaab297daae21aa0fd4e70c07c99e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.2.html": [
+   "d59ea56a6f56bf29a8db7336f78b3e2c5c5364d8",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.3.html": [
+   "64e72bfa867ffdc22592b021f3bec9ff9e57a38c",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.bogustype.html": [
+   "e3cfe22f9bc3d388193a63297c8c760623c990f9",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.default.html": [
+   "415132601879e01d7c8786930b91bfa4349642a6",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.html": [
+   "019931886576bc20a7f5ba90a541f45425a55d61",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.png": [
+   "679bf15817a292bc701d2cb4c803de22d237d5b8",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.html": [
+   "4ce4852c2164933d21d46b23c64cd3cac658c164",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.png": [
+   "846d5a7f3e0f57edf9eb44f270ada6d195410cfe",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.html": [
+   "1d98a76db469637bbbaf8d82fa250566e54427a0",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.png": [
+   "b0487c056dd6dafd1d1bfa530cb7cf8c58ca8b2d",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.notnumber.html": [
+   "3b7ae3a387d5822785aa84fa7d48fff7b66d2e31",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.outsiderange.html": [
+   "d1f0b376bca4da5bb89e5d641c81b06e1d57fa14",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.jpg.html": [
+   "b918850eed2137d1a352ade0f1b112f67836502d",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.ascii.html": [
+   "732d5e60d769197f0e1ef7dd0d63e9952dc3becf",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.unicode.html": [
+   "9d979a9c23bb2b82756f10e1715dc26b25c8f150",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.nocontext.html": [
+   "84f878a6a44511e97b36fb579514dc5214a088c7",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.html": [
+   "e259d37625dc27fc4098e511256c592870e1fcca",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.png": [
+   "ed0d67d23e601762bdc3852c72145db298fda6f1",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.png.html": [
+   "a9967fe45349dec5064aef96e2b7ae44beb2634a",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.html": [
+   "d235c02cc677fe7bdf80b963fb7ec5b7bd6f97f3",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.png": [
+   "846d5a7f3e0f57edf9eb44f270ada6d195410cfe",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.unrecognised.html": [
+   "649ac0f9c9bd0263bfd0f6c6d83251fb780c128c",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.zeroheight.html": [
+   "8d33cf61c8b30a57a3954a186d3e7f33094d604e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.zerosize.html": [
+   "1734921bd72e3c5a1466004771f2a33a9e98b762",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/toDataURL.zerowidth.html": [
+   "4f725b9fa38f32651015c151c5db7c729d12b0d1",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/type.delete.html": [
+   "aeb8324293a033064b9e07af9e47e4564412e3f2",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/type.exists.html": [
+   "54d41655c47beb666be3e80cb0c92f2aaa497d63",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/type.extend.html": [
+   "62ae77f87e51726e00406149de2dec1dca9b7acd",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/type.name.html": [
+   "bab1d6f57ac79f404bc8d7b696194bd6081056e0",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/type.prototype.html": [
+   "b688ea8ca3e95f4a3cfd92a9ac0f5230b8975be3",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-canvas-element/type.replace.html": [
+   "c8784361857ba83afbe1be4bca4ed5e654307c2f",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-embed-element/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
+  "html/semantics/embedded-content/the-embed-element/embed-dimension.html": [
+   "6f8443aada05e8ab3cbb81d81d7053a81fe0dcfe",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-embed-element/embed-document.html": [
    "e6611c20a50884639a51010836bb2b1bdfb9cab8",
    "testharness"
@@ -259878,6 +263760,18 @@
    "2b595a45498791fc4737ea3095bb5ee89cbc3d8f",
    "reftest"
   ],
+  "html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html": [
+   "e69808a70a4b97dbc42bcac676d247acd7e29c69",
+   "reftest"
+  ],
+  "html/semantics/embedded-content/the-embed-element/embed-represent-nothing-03.html": [
+   "96a9be3a5efd744375ccd2e7c59aaf50e3ef7eee",
+   "reftest"
+  ],
+  "html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html": [
+   "f73ab93480c64cb7801d9cfe320264c48f30bfb8",
+   "reftest"
+  ],
   "html/semantics/embedded-content/the-embed-element/embed-represent-nothing-ref.html": [
    "bdcd35bc3b9f80ec0c25c34a7977b97a06ffab88",
    "support"
@@ -260102,6 +263996,14 @@
    "74de4312124b394cb2d6442810af6938cb7360c3",
    "support"
   ],
+  "html/semantics/embedded-content/the-img-element/current-pixel-density/basic-expected.txt": [
+   "a86a7826e5f11f607c00aa17a3a8a2fd08530765",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html": [
+   "b652ca562a6b01922ab1be34823d32ed0f5753ba",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-img-element/current-pixel-density/error.html": [
    "ca607612e24b5354ab806a717315bc313b924751",
    "testharness"
@@ -260146,6 +264048,14 @@
    "49749bac2a0e3ec6b3d8ac1c5dd4f1a3514ddfdd",
    "support"
   ],
+  "html/semantics/embedded-content/the-img-element/environment-changes/viewport-change-expected.txt": [
+   "49c4dfa53617dbf099400c5a1c82d52659a9bb54",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html": [
+   "7b09a85519ce0adb3718224451e385cf65375833",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-img-element/image-1.jpg": [
    "d8582432681a89eb24e4b42b304d63c8f2a70988",
    "support"
@@ -260194,6 +264104,10 @@
    "3752b0f4f5b31ca0bf55b99a400dd8cd7a12b8a7",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-img-element/relevant-mutations.html": [
+   "3b4171a783f97facca39bcc342df253597876412",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-img-element/resources/cat.jpg": [
    "d8bdb2208a32d2200afb173368c38826fede8476",
    "support"
@@ -260266,6 +264180,18 @@
    "d851a8ef7bf0dc9a2e64841db8c9002877cb3b50",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-object-element/object-events.html": [
+   "fcced7c858d527f7c0d4e792c683c21a68c2711b",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/the-object-element/object-fallback-expected.txt": [
+   "9cf4e6b222d5fbfb02e6271ee58356614e6adc0d",
+   "support"
+  ],
+  "html/semantics/embedded-content/the-object-element/object-fallback.html": [
+   "7bb46b36376a1afd004cf0537bdedd975088b2f2",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-object-element/object-handler.html": [
    "bf051d12a045698b2f9c3870ad4236f65bb85f51",
    "testharness"
@@ -260338,10 +264264,22 @@
    "8e29bdb76812e95400bf4b300b83418a1be368c8",
    "support"
   ],
+  "html/semantics/embedded-content/the-video-element/video_dynamic_poster_absolute.htm": [
+   "2e727c0a5e52dbd4bf20fe27285191a47ffec90d",
+   "reftest"
+  ],
+  "html/semantics/embedded-content/the-video-element/video_dynamic_poster_relative.htm": [
+   "b08d39d482ae807d2e33a91ded031c4fe4295e7c",
+   "reftest"
+  ],
   "html/semantics/embedded-content/the-video-element/video_initially_paused-ref.html": [
    "001abcd1f7997d63ea27ab99c25df6b20d7d1dde",
    "support"
   ],
+  "html/semantics/embedded-content/the-video-element/video_initially_paused.html": [
+   "90165d45b8b1670f0374ba2c8185327ece678458",
+   "reftest"
+  ],
   "html/semantics/forms/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
@@ -261550,10 +265488,6 @@
    "340924bc329569ce605ce228619d95f09f335ec5",
    "support"
   ],
-  "html/semantics/interactive-elements/the-dialog-element/dialog-close-expected.txt": [
-   "b1370af773ade2ac9d1e9176df4492521163613b",
-   "support"
-  ],
   "html/semantics/interactive-elements/the-dialog-element/dialog-close.html": [
    "94ed2b8f019e1b65c47c5f971503496bb4765048",
    "testharness"
@@ -261563,11 +265497,11 @@
    "testharness"
   ],
   "html/semantics/interactive-elements/the-dialog-element/dialog-showModal-expected.txt": [
-   "ac1d3a84925e392a8dff6e98c67a6de643440ef6",
+   "2de9fc78a570af675094cbb1781b1b03e4e3dd45",
    "support"
   ],
   "html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html": [
-   "10dd870ad796a59bef26d18917bf91374f475f93",
+   "c00ac5b6d038b45b1a7cfbef94a4527757fa74e6",
    "testharness"
   ],
   "html/semantics/interactive-elements/the-menu-element/.gitkeep": [
@@ -261583,7 +265517,7 @@
    "testharness"
   ],
   "html/semantics/interfaces-expected.txt": [
-   "4cfbe28a689d14da8f2e5f5d6bfeaf54724f1363",
+   "ef9cf530a16e355064cd78fc6edb0394ed31079f",
    "support"
   ],
   "html/semantics/interfaces.html": [
@@ -261591,7 +265525,7 @@
    "testharness"
   ],
   "html/semantics/interfaces.js": [
-   "b63c7402601bbf801f65dff9bef38797cdaf9eae",
+   "a9ac58b56b1a0f69f4e47365cb0ada55f31958e3",
    "support"
   ],
   "html/semantics/links/.gitkeep": [
@@ -264570,18 +268504,10 @@
    "7781dc14881c5377c0df772ab1271fe552493811",
    "testharness"
   ],
-  "html/webappapis/scripting/processing-model-2/compile-error-in-setInterval-expected.txt": [
-   "e643a631bf8a2d5a5bcb7ff4321329fd03f18137",
-   "support"
-  ],
   "html/webappapis/scripting/processing-model-2/compile-error-in-setInterval.html": [
    "ef844547e22243e00605fe61dae98fc4799849b1",
    "testharness"
   ],
-  "html/webappapis/scripting/processing-model-2/compile-error-in-setTimeout-expected.txt": [
-   "e20c3c6bba81ebed8f66889134edb21295b65107",
-   "support"
-  ],
   "html/webappapis/scripting/processing-model-2/compile-error-in-setTimeout.html": [
    "a76b8a140592153305d33c6cebe987754d6d42d3",
    "testharness"
@@ -264662,18 +268588,10 @@
    "2a36ca312c6b086b84efc832ad79c43ea7d11087",
    "testharness"
   ],
-  "html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval-expected.txt": [
-   "e5b6c61f4c19cbb813d5533c9a21b092e11cda99",
-   "support"
-  ],
   "html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval.html": [
    "7e8952fe584c9f7e8e04777d2d4946d54eb6f288",
    "testharness"
   ],
-  "html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout-expected.txt": [
-   "81240d5c320ccb80709e3812d612b008d64d4b2e",
-   "support"
-  ],
   "html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout.html": [
    "51840a7f6f72e730c7d7410bdbe80e9c9d9eb6fe",
    "testharness"
@@ -274891,23 +278809,27 @@
    "testharness"
   ],
   "payment-request/payment-request-id-attribute.https.html": [
-   "0c732487dba598c8ac72a349841ed2cae265a3a9",
+   "9a8a1ffc3cd7ba3c29380c4a9962bd17f35087c3",
    "testharness"
   ],
   "payment-request/payment-request-onshippingaddresschange-attribute.https.html": [
-   "c716788baf4b5e74c5bd5adbbd9f95d9ca98ce12",
+   "c9e3679232a83abe6a9eefcb28e3387d2c7810e5",
    "testharness"
   ],
   "payment-request/payment-request-onshippingoptionchange-attribute.https.html": [
-   "fc4772725ab7cab838d0d7bb97d0febeef8d093c",
+   "9488e832b86b582310b0f46a68f9cf420b473e98",
    "testharness"
   ],
   "payment-request/payment-request-response-id.html": [
    "8feda1d3b4c071014d4c8c7898598c7d23086216",
    "support"
   ],
+  "payment-request/payment-request-shippingAddress-attribute.https.html": [
+   "ce33b78031644cb508c6fe148c21c37128b422c0",
+   "testharness"
+  ],
   "payment-request/payment-request-shippingType-attribute.https.html": [
-   "b6c449dfe568dea727a18e10428e1b8e0186f8d4",
+   "27ecc7e10e50bf2df07f84a15972c3b913ebf32f",
    "testharness"
   ],
   "payment-request/payment-request-show-method.https.html": [
@@ -274931,7 +278853,7 @@
    "manual"
   ],
   "payment-request/payment-response/helpers.js": [
-   "d0824649acba162d9cc221f1b333cae915bc7828",
+   "86384f708f1067b3687d697a30652d1baa189739",
    "support"
   ],
   "payment-request/payment-response/methodName-attribute-manual.https.html": [
@@ -275023,7 +278945,7 @@
    "testharness"
   ],
   "performance-timeline/po-observe.html": [
-   "0076397128975660e1f66f8d23e6b6945d2a804e",
+   "2486507d5925b6429899ddf4db386990d7ae560f",
    "testharness"
   ],
   "performance-timeline/po-resource.html": [
@@ -287034,6 +290956,42 @@
    "005490d4fc62797e432b03c33c349d9136815625",
    "testharness"
   ],
+  "streams/readable-byte-streams/brand-checks-expected.txt": [
+   "1c2c756dfa3115edba4aefe869d44a4fcf563b8b",
+   "support"
+  ],
+  "streams/readable-byte-streams/brand-checks.dedicatedworker-expected.txt": [
+   "1c2c756dfa3115edba4aefe869d44a4fcf563b8b",
+   "support"
+  ],
+  "streams/readable-byte-streams/brand-checks.dedicatedworker.html": [
+   "b0f32b03a352ef7ac1940eda90414a5f65980194",
+   "testharness"
+  ],
+  "streams/readable-byte-streams/brand-checks.html": [
+   "317e5c5cc2eedcc6902e8cc44567ea59e7f173ac",
+   "testharness"
+  ],
+  "streams/readable-byte-streams/brand-checks.js": [
+   "15d95be48677eae31eece31a54d2d63fdf64c1bc",
+   "support"
+  ],
+  "streams/readable-byte-streams/brand-checks.serviceworker.https-expected.txt": [
+   "f4cccc39e7ef0c72201320573818469679e801f9",
+   "support"
+  ],
+  "streams/readable-byte-streams/brand-checks.serviceworker.https.html": [
+   "c8279e28f5cd80d454d884154ae883a8c965705f",
+   "testharness"
+  ],
+  "streams/readable-byte-streams/brand-checks.sharedworker-expected.txt": [
+   "1c2c756dfa3115edba4aefe869d44a4fcf563b8b",
+   "support"
+  ],
+  "streams/readable-byte-streams/brand-checks.sharedworker.html": [
+   "6f3911baf77e26af2d7e7d7472caae4df6d5a27e",
+   "testharness"
+  ],
   "streams/readable-byte-streams/general-expected.txt": [
    "73f76f622b4b6b4aff498525f1732e7d675c90b3",
    "support"
@@ -287351,7 +291309,7 @@
    "support"
   ],
   "streams/resources/test-utils.js": [
-   "a9f47ed7902a34cdd1ad34e422cd63b7bad58ee7",
+   "a05a620307acb1e7cadba523b8a3c6d2de7e1748",
    "support"
   ],
   "streams/writable-streams/aborting.dedicatedworker.html": [
@@ -288955,7 +292913,7 @@
    "testharness"
   ],
   "web-animations/interfaces/Animation/idlharness-expected.txt": [
-   "cd4f03a0410aa5262f93f0436e584dcc4f0201f1",
+   "3f853b935fc1b4891e9e1bce7c713dd204bd5ed2",
    "support"
   ],
   "web-animations/interfaces/Animation/idlharness.html": [
@@ -292039,7 +295997,7 @@
    "support"
   ],
   "webvr/idlharness.html": [
-   "236974fe82ab29908e849d25c5ce748f5c0509c3",
+   "ef6ad8bff43a6423b9b3e7deb8017a8b3fa0c112",
    "testharness"
   ],
   "webvr/webvr-disabled-by-feature-policy.https.sub.html": [
@@ -292290,10 +296248,6 @@
    "2ada07a44f030a55290a87e0a8ad46f1b9eb3f60",
    "support"
   ],
-  "webvtt/parsing/file-parsing/signature-invalid-expected.txt": [
-   "2272ccabb9cbd1f24e3be3025e636665ad22466b",
-   "support"
-  ],
   "webvtt/parsing/file-parsing/signature-invalid.html": [
    "a01ea6851e5ad1a1ef79d561fcfeafd09b6c1555",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-async-method-denied.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-async-method-denied.htm
new file mode 100644
index 0000000..eb36110f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-async-method-denied.htm
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Async request denied at preflight because of non-CORS-safelisted method</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="/common/utils.js"></script>
+  </head>
+  <body>
+    <script type="text/javascript">
+    const uuid = token();
+    const url = get_host_info().HTTP_REMOTE_ORIGIN +
+          "/XMLHttpRequest/resources/access-control-preflight-denied.py?token=" + uuid;
+
+    async_test((test) => {
+      let xhr = new XMLHttpRequest;
+      xhr.open("GET", url + "&command=reset", false);
+      xhr.send();
+
+      xhr = new XMLHttpRequest;
+      xhr.open("DELETE", url + "&command=method", true);
+
+      xhr.onload = test.unreached_func(
+          "Cross-domain access with non-CORS-safelisted method allowed without throwing exception");
+
+      xhr.onerror = test.step_func_done(() => {
+        xhr = new XMLHttpRequest;
+        xhr.open("GET", url + "&command=complete", false);
+        xhr.send();
+        assert_equals(xhr.responseText, "Request successfully blocked.");
+      });
+
+      xhr.send();
+    }, "Async request denied at preflight");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-sync-header-denied.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-sync-header-denied.htm
new file mode 100644
index 0000000..422c625e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-sync-header-denied.htm
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Sync request denied at preflight because of non-CORS-safelisted header</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="/common/utils.js"></script>
+  </head>
+  <body>
+    <script type="text/javascript">
+const uuid = token();
+const url = get_host_info().HTTP_REMOTE_ORIGIN +
+    "/XMLHttpRequest/resources/access-control-preflight-denied.py?token=" + uuid;
+
+test(() => {
+  let xhr = new XMLHttpRequest;
+  xhr.open("GET", url + "&command=reset", false);
+  xhr.send();
+
+  xhr = new XMLHttpRequest;
+  xhr.open("GET", url + "&command=header", false);
+  xhr.setRequestHeader("x-test", "foo");
+
+  try {
+    xhr.send();
+  } catch(e) {
+    xhr = new XMLHttpRequest;
+    xhr.open("GET", url + "&command=complete", false);
+    xhr.send();
+    assert_equals(xhr.responseText, "Request successfully blocked.");
+    return;
+  }
+
+  assert_unreached("Cross-domain access with custom header allowed without throwing exception");
+}, "Sync request denied at preflight");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html
deleted file mode 100644
index d770278..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-    <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.-->
-    <title>object-src-applet-archive-codebase</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src='../support/logTest.sub.js?logs=["PASS"]'></script>
-    <script src="../support/alertAssert.sub.js?alerts=[]"></script>
-    <!-- enforcing policy:
-object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self';
--->
-
-</head>
-
-<body>
-    <script>
-        var len = navigator.mimeTypes.length;
-        var allTypes = "";
-        var appletMimeType = "application/x-java-applet";
-        for (var i = 0; i < len; i++) {
-            allTypes += navigator.mimeTypes[i].type + ';';
-        }
-        if (allTypes.indexOf(appletMimeType) == -1) {
-            t_log.set_status(t_log.NOTRUN, "No Java Plugin, cannot run test.");
-            t_log.phase = t_log.phases.HAS_RESULT;
-            t_log.done();
-        } else {
-            var s = document.createElement('script');
-            s.src = "../support/checkReport.sub.js?reportExists=true&amp;reportField=violated-directive&amp;reportValue=object-src%20&apos;none&apos;";
-            document.body.appendChild(s);
-        }
-
-    </script>
-    This test passes if there is a CSP violation saying the plugin was blocked.
-    <applet code="TestThingie" archive="archive.jar" codebase="/plugins/codebase/" id="appletObject" onload="log('FAIL')" onerror="log('PASS')"></applet>
-    <div id="log"></div>
-</body>
-
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html.sub.headers
deleted file mode 100644
index 0b71a188..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive-codebase.sub.html.sub.headers
+++ /dev/null
@@ -1,6 +0,0 @@
-Expires: Mon, 26 Jul 1997 05:00:00 GMT
-Cache-Control: no-store, no-cache, must-revalidate
-Cache-Control: post-check=0, pre-check=0, false
-Pragma: no-cache
-Set-Cookie: object-src-applet-archive-codebase={{$id:uuid()}}; Path=/content-security-policy/blink-contrib
-Content-Security-Policy: object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self'; report-uri /content-security-policy/support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive.sub.html
deleted file mode 100644
index 69c71986..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive.sub.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-    <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.-->
-    <title>object-src-applet-archive</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src='../support/logTest.sub.js?logs=["PASS"]'></script>
-    <script src="../support/alertAssert.sub.js?alerts=[]"></script>
-    <!-- enforcing policy:
-object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self';
--->
-
-</head>
-
-<body>
-    <script>
-        var len = navigator.mimeTypes.length;
-        var allTypes = "";
-        var appletMimeType = "application/x-java-applet";
-        for (var i = 0; i < len; i++) {
-            allTypes += navigator.mimeTypes[i].type + ';';
-        }
-        if (allTypes.indexOf(appletMimeType) == -1) {
-            t_log.set_status(t_log.NOTRUN, "No Java Plugin, cannot run test.");
-            t_log.phase = t_log.phases.HAS_RESULT;
-            t_log.done();
-        } else {
-            var s = document.createElement('script');
-            s.src = "../support/checkReport.sub.js?reportExists=true&amp;reportField=violated-directive&amp;reportValue=object-src%20&apos;none&apos;";
-            document.body.appendChild(s);
-        }
-
-    </script>
-    This test passes if there is a CSP violation saying the plugin was blocked.
-    <applet code="TestThingie" archive="/plugins/archive.jar" id="appletObject" onload="log('FAIL')" onerror="log('PASS')"></applet>
-    <div id="log"></div>
-</body>
-
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive.sub.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive.sub.html.sub.headers
deleted file mode 100644
index 4bd5ec14..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-archive.sub.html.sub.headers
+++ /dev/null
@@ -1,6 +0,0 @@
-Expires: Mon, 26 Jul 1997 05:00:00 GMT
-Cache-Control: no-store, no-cache, must-revalidate
-Cache-Control: post-check=0, pre-check=0, false
-Pragma: no-cache
-Set-Cookie: object-src-applet-archive={{$id:uuid()}}; Path=/content-security-policy/blink-contrib
-Content-Security-Policy: object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self'; report-uri /content-security-policy/support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html
deleted file mode 100644
index 6121dad..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-    <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.-->
-    <title>object-src-applet-archive-code-codebase</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src='../support/logTest.sub.js?logs=["PASS"]'></script>
-    <script src="../support/alertAssert.sub.js?alerts=[]"></script>
-    <!-- enforcing policy:
-object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self';
--->
-
-</head>
-
-<body>
-    <script>
-        var len = navigator.mimeTypes.length;
-        var allTypes = "";
-        var appletMimeType = "application/x-java-applet";
-        for (var i = 0; i < len; i++) {
-            allTypes += navigator.mimeTypes[i].type + ';';
-        }
-        if (allTypes.indexOf(appletMimeType) == -1) {
-            t_log.set_status(t_log.NOTRUN, "No Java Plugin, cannot run test.");
-            t_log.phase = t_log.phases.HAS_RESULT;
-            t_log.done();
-        } else {
-            var s = document.createElement('script');
-            s.src = "../support/checkReport.sub.js?reportExists=true&amp;reportField=violated-directive&amp;reportValue=object-src%20&apos;none&apos;";
-            document.body.appendChild(s);
-        }
-
-    </script>
-    This test passes if there is a CSP violation saying the plugin was blocked.
-    <applet code="code.class" codebase="/plugins/codebase/"></applet>
-    <div id="log"></div>
-</body>
-
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html.sub.headers
deleted file mode 100644
index 1ced1a8..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code-codebase.sub.html.sub.headers
+++ /dev/null
@@ -1,6 +0,0 @@
-Expires: Mon, 26 Jul 1997 05:00:00 GMT
-Cache-Control: no-store, no-cache, must-revalidate
-Cache-Control: post-check=0, pre-check=0, false
-Pragma: no-cache
-Set-Cookie: object-src-applet-code-codebase={{$id:uuid()}}; Path=/content-security-policy/blink-contrib
-Content-Security-Policy: object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self'; report-uri /content-security-policy/support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code.sub.html
deleted file mode 100644
index af598bfd..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code.sub.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-    <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.-->
-    <title>object-src-applet-code</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src='../support/logTest.sub.js?logs=["PASS"]'></script>
-    <script src="../support/alertAssert.sub.js?alerts=[]"></script>
-    <!-- enforcing policy:
-object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self';
--->
-
-</head>
-
-<body>
-    <script>
-        var len = navigator.mimeTypes.length;
-        var allTypes = "";
-        var appletMimeType = "application/x-java-applet";
-        for (var i = 0; i < len; i++) {
-            allTypes += navigator.mimeTypes[i].type + ';';
-        }
-        if (allTypes.indexOf(appletMimeType) == -1) {
-            t_log.set_status(t_log.NOTRUN, "No Java Plugin, cannot run test.");
-            t_log.phase = t_log.phases.HAS_RESULT;
-            t_log.done();
-        } else {
-            var s = document.createElement('script');
-            s.src = "../support/checkReport.sub.js?reportExists=true&amp;reportField=violated-directive&amp;reportValue=object-src%20&apos;none&apos;";
-            document.body.appendChild(s);
-        }
-
-    </script>
-    This test passes if there is a CSP violation saying the plugin was blocked.
-    <applet code="/plugins/code.class"></applet>
-    <div id="log"></div>
-</body>
-
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code.sub.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code.sub.html.sub.headers
deleted file mode 100644
index 44bd725..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/blink-contrib/object-src-applet-code.sub.html.sub.headers
+++ /dev/null
@@ -1,6 +0,0 @@
-Expires: Mon, 26 Jul 1997 05:00:00 GMT
-Cache-Control: no-store, no-cache, must-revalidate
-Cache-Control: post-check=0, pre-check=0, false
-Pragma: no-cache
-Set-Cookie: object-src-applet-code={{$id:uuid()}}; Path=/content-security-policy/blink-contrib
-Content-Security-Policy: object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self'; report-uri /content-security-policy/support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/README.md b/third_party/WebKit/LayoutTests/external/wpt/core-aam/README.md
new file mode 100644
index 0000000..8728628
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/README.md
@@ -0,0 +1,59 @@
+core-aam: Tests for the Core Accessibility API Mappings Recommendation
+======================================================================
+
+The [Core Accessibility API Mappings Recommendation](https://www.w3.org/TR/core-aam-1.1/)
+describes how user agents should expose semantics of web content languages to accessibility
+APIs. This helps users with disabilities to obtain and interact with information using
+assistive technologies. Documenting these mappings promotes interoperable exposure of roles,
+states, properties, and events implemented by accessibility APIs and helps to ensure that
+this information appears in a manner consistent with author intent.
+
+The purpose of these tests is to help ensure that user agents support the requirements of
+the Recommendation.
+
+The general approach for this testing is to enable both manual and automated testing, with
+a preference for automation.
+
+
+Running Tests
+-------------
+
+In order to run these tests in an automated fashion, you will need to have a special
+Assistive Technology Test Adapter (ATTA) for the platform under test. We will provide
+a list of these for popular platforms here as they are made available.
+
+The ATTA will monitor the window under test via the platforms Accessibility Layer,
+forwarding information about the Accessibility Tree to the running test so that it
+can evaluate support for the various features under test.
+
+The workflow for running these tests is something like:
+
+1. Start up the ATTA for the platform under test.
+2. Start up the test driver window, select the core-aam tests to be run,
+   and click "Start"
+3. A window pops up that shows a test, the description of which tells the
+   tester what is being tested. In an automated test, the test will proceed
+   without user intervention. In a manual test, some user input or verification
+   may be required.
+4. The test runs. Success or failure is determined and reported to the test
+   driver window, which then cycles to the next test in the sequence.
+5. Repeat steps 2-4 until done.
+6. Download the JSON format report of test results, which can then be visually
+   inspected, reported on using various tools, or passed on to W3C for evaluation
+   and collection in the Implementation Report via github.
+
+**Remember that while these tests are written to help exercise implementations,
+their other (important) purpose is to increase confidence that there are
+interoperable implementations.** So, implementers are the audience, but these
+tests are not meant to be a comprehensive collection of tests for a client that
+might implement the Recommendation.
+
+
+Capturing and Reporting Results
+-------------------------------
+
+As tests are run against implementations, if the results of testing are
+submitted to [test-results](https://github.com/w3c/test-results/) then they will
+be automatically included in documents generated by
+[wptreport](https://www.github.com/w3c/wptreport). The same tool can be used
+locally to view reports about recorded results.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/alert-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alert-manual-expected.txt
new file mode 100644
index 0000000..4d15886
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alert-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL alert Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/alert-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alert-manual.html
new file mode 100644
index 0000000..a02f18c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alert-manual.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+  <head>
+    <title>alert</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_ALERT"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationAlert"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "alert"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_ALERT"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "alert"
+               ],
+               [
+                  "property",
+                  "LiveSetting",
+                  "is",
+                  "Assertive (2)"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "alert"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for alert.</p>
+    <div role='alert' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/alertdialog-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alertdialog-manual-expected.txt
new file mode 100644
index 0000000..2f25b38
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alertdialog-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL alertdialog Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/alertdialog-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alertdialog-manual.html
new file mode 100644
index 0000000..970ff07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/alertdialog-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>alertdialog</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_DIALOG"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationAlertDialog"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "web alert dialog"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_DIALOG"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Pane"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "alertdialog"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for alertdialog.</p>
+    <div role='alertdialog' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/application-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/application-manual-expected.txt
new file mode 100644
index 0000000..37301839
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/application-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL application Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/application-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/application-manual.html
new file mode 100644
index 0000000..a34e39e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/application-manual.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<html>
+  <head>
+    <title>application</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_EMBEDDED"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXWebApplication"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "web application"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_APPLICATION"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Pane"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "application"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "application"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for application.</p>
+    <div role='application' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/article-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/article-manual-expected.txt
new file mode 100644
index 0000000..1ee61ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/article-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL article Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/article-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/article-manual.html
new file mode 100644
index 0000000..d2775c6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/article-manual.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<html>
+  <head>
+    <title>article</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_ARTICLE"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:article"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXDocumentArticle"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "article"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_READONLY"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:article"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_DOCUMENT"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "article"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "article"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for article.</p>
+    <div role='article' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/banner_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/banner_new-manual-expected.txt
new file mode 100644
index 0000000..c42f993
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/banner_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL banner NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/banner_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/banner_new-manual.html
new file mode 100644
index 0000000..e096324c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/banner_new-manual.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<html>
+  <head>
+    <title>banner NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:banner"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXLandmarkBanner"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "banner"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:banner"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "banner"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Custom"
+               ],
+               [
+                  "property",
+                  "LocalizedLandmarkType",
+                  "is",
+                  "banner"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "banner NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for banner NEW.</p>
+    <div role='banner' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__dialog__new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__dialog__new-manual-expected.txt
new file mode 100644
index 0000000..affb2c65
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__dialog__new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL button with aria-haspopup="dialog" NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__dialog__new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__dialog__new-manual.html
new file mode 100644
index 0000000..b8e44e92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__dialog__new-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>button with aria-haspopup="dialog" NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PUSH_BUTTON"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXPopUpButton"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "pop up button"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_BUTTONMENU"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Button"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "button with aria-haspopup=\"dialog\" NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for button with aria-haspopup="dialog" NEW.</p>
+    <div role='button' id='test' aria-haspopup='dialog'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__true__new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__true__new-manual-expected.txt
new file mode 100644
index 0000000..99f150a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__true__new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL button with aria-haspopup="true" NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__true__new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__true__new-manual.html
new file mode 100644
index 0000000..45b3d670
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_aria-haspopup__true__new-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>button with aria-haspopup="true" NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PUSH_BUTTON"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXPopUpButton"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "pop up button"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_BUTTONMENU"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Button"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "button with aria-haspopup=\"true\" NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for button with aria-haspopup="true" NEW.</p>
+    <div role='button' id='test' aria-haspopup='true'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual-expected.txt
new file mode 100644
index 0000000..464c4043
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL button with default values for aria-pressed and aria-haspopup Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual.html
new file mode 100644
index 0000000..af670fcd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_default_values_for_aria-pressed_and_aria-haspopup-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>button with default values for aria-pressed and aria-haspopup</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PUSH_BUTTON"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXButton"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "button"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_PUSHBUTTON"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Button"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "button with default values for aria-pressed and aria-haspopup"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for button with default values for aria-pressed and aria-haspopup.</p>
+    <div role='button' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_defined_value_for_aria-pressed-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_defined_value_for_aria-pressed-manual-expected.txt
new file mode 100644
index 0000000..c3d5bad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_defined_value_for_aria-pressed-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL button with defined value for aria-pressed Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_defined_value_for_aria-pressed-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_defined_value_for_aria-pressed-manual.html
new file mode 100644
index 0000000..81c4ef1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/button_with_defined_value_for_aria-pressed-manual.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html>
+  <head>
+    <title>button with defined value for aria-pressed</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TOGGLE_BUTTON"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXCheckBox"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXToggle"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "toggle button"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_TOGGLE_BUTTON"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_PUSHBUTTON"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Button"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "button with defined value for aria-pressed"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for button with defined value for aria-pressed.</p>
+    <div role='button' id='test' aria-pressed='true'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/cell_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/cell_new-manual-expected.txt
new file mode 100644
index 0000000..751dca2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/cell_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL cell NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/cell_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/cell_new-manual.html
new file mode 100644
index 0000000..b5df0b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/cell_new-manual.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<html>
+  <head>
+    <title>cell NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TABLE_CELL"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "TableCell"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXCell"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "cell"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleTableCell"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_CELL"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "DataItem"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "cell"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "TableItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "cell NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for cell NEW.</p>
+    <div role='table'>
+    <div role='row'>
+      <div role='cell' id='test'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/checkbox-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/checkbox-manual-expected.txt
new file mode 100644
index 0000000..b48561f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/checkbox-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL checkbox Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/checkbox-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/checkbox-manual.html
new file mode 100644
index 0000000..2bdde316
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/checkbox-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>checkbox</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_CHECK_BOX"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXCheckBox"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "checkbox"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_CHECKBUTTON"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Checkbox"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "checkbox"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for checkbox.</p>
+    <div role='checkbox' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/columnheader-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/columnheader-manual-expected.txt
new file mode 100644
index 0000000..c02aa92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/columnheader-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL columnheader Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/columnheader-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/columnheader-manual.html
new file mode 100644
index 0000000..e6cbd46
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/columnheader-manual.html
@@ -0,0 +1,101 @@
+<!doctype html>
+<html>
+  <head>
+    <title>columnheader</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_COLUMN_HEADER"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "TableCell"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXCell"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "cell"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleTableCell"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_COLUMNHEADER"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "HeaderItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "columnheader"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for columnheader.</p>
+    <div role='grid'>
+    <div role='row'>
+      <div role='columnheader' id='test'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/combobox-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/combobox-manual-expected.txt
new file mode 100644
index 0000000..85cf3908
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/combobox-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL combobox Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/combobox-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/combobox-manual.html
new file mode 100644
index 0000000..7f7033b8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/combobox-manual.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<html>
+  <head>
+    <title>combobox</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_COMBO_BOX"
+               ],
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_EXPANDABLE"
+               ],
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_HAS_POPUP"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXComboBox"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "combo box"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_HASPOPUP"
+               ],
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_COLLAPSED"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_COMBOBOX"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Combobox"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "combobox"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for combobox.</p>
+    <div role='combobox' aria-expanded='false' id='test'>
+    <div role='textbox'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/complementary_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/complementary_new-manual-expected.txt
new file mode 100644
index 0000000..7ab4a10
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/complementary_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL complementary NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/complementary_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/complementary_new-manual.html
new file mode 100644
index 0000000..7f03810
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/complementary_new-manual.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<html>
+  <head>
+    <title>complementary NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:complementary"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXLandmarkComplementary"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "complementary"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:complementary"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "complementary"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Custom"
+               ],
+               [
+                  "property",
+                  "LocalizedLandmarkType",
+                  "is",
+                  "complementary"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "complementary NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for complementary NEW.</p>
+    <div role='complementary' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/contentinfo_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/contentinfo_new-manual-expected.txt
new file mode 100644
index 0000000..d17346e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/contentinfo_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL contentinfo NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/contentinfo_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/contentinfo_new-manual.html
new file mode 100644
index 0000000..2e12dc7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/contentinfo_new-manual.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<html>
+  <head>
+    <title>contentinfo NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:contentinfo"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXLandmarkContentInfo"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "content information"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:contentinfo"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "content information"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Custom"
+               ],
+               [
+                  "property",
+                  "LocalizedLandmarkType",
+                  "is",
+                  "content information"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "contentinfo NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for contentinfo NEW.</p>
+    <div role='contentinfo' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/definition-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/definition-manual-expected.txt
new file mode 100644
index 0000000..b265283
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/definition-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL definition Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/definition-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/definition-manual.html
new file mode 100644
index 0000000..81b782d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/definition-manual.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+  <head>
+    <title>definition</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_DESCRIPTION_VALUE"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:definition"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXDefinition"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "definition"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:definition"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "definition"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "definition"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for definition.</p>
+    <div role='definition' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/dialog-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/dialog-manual-expected.txt
new file mode 100644
index 0000000..f7afb8a8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/dialog-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL dialog Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/dialog-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/dialog-manual.html
new file mode 100644
index 0000000..9d94b23
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/dialog-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>dialog</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_DIALOG"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationDialog"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "web dialog"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_DIALOG"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Pane"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "dialog"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for dialog.</p>
+    <div role='dialog' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/directory-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/directory-manual-expected.txt
new file mode 100644
index 0000000..da75a89
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/directory-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL directory Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/directory-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/directory-manual.html
new file mode 100644
index 0000000..5e1a9d0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/directory-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>directory</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LIST"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXList"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXContentList"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "content list"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LIST"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "List"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "directory"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for directory.</p>
+    <div role='directory' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/document-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/document-manual-expected.txt
new file mode 100644
index 0000000..c1676ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/document-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL document Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/document-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/document-manual.html
new file mode 100644
index 0000000..04ffad6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/document-manual.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html>
+  <head>
+    <title>document</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_DOCUMENT_FRAME"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXDocument"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "document"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_READONLY"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_DOCUMENT"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Document"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "document"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for document.</p>
+    <div role='document' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/feed_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/feed_new-manual-expected.txt
new file mode 100644
index 0000000..a76e4f95
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/feed_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL feed NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/feed_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/feed_new-manual.html
new file mode 100644
index 0000000..9ef7cc5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/feed_new-manual.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+  <head>
+    <title>feed NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PANEL"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:feed"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationGroup"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "feed"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:feed"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_GROUPING"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "feed"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "feed NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for feed NEW.</p>
+    <div role='feed' id='test'>
+    <div role='article'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/figure_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/figure_new-manual-expected.txt
new file mode 100644
index 0000000..c88ba46
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/figure_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL figure NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/figure_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/figure_new-manual.html
new file mode 100644
index 0000000..a77e4e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/figure_new-manual.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+  <head>
+    <title>figure NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PANEL"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:figure"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "figure"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:figure"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_GROUPING"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "figure"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "figure NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for figure NEW.</p>
+    <div role='figure' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/form_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/form_new-manual-expected.txt
new file mode 100644
index 0000000..7e0c857
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/form_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL form NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/form_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/form_new-manual.html
new file mode 100644
index 0000000..8745bcf8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/form_new-manual.html
@@ -0,0 +1,107 @@
+<!doctype html>
+<html>
+  <head>
+    <title>form NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:form"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "group"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_FORM"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:form"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "form"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Form"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "form NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for form NEW.</p>
+    <div role='form' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/grid-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/grid-manual-expected.txt
new file mode 100644
index 0000000..8dc19350
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/grid-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL grid Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/grid-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/grid-manual.html
new file mode 100644
index 0000000..ff460bdc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/grid-manual.html
@@ -0,0 +1,164 @@
+<!doctype html>
+<html>
+  <head>
+    <title>grid</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TABLE"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:grid"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Table"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXTable"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "table"
+               ],
+               [
+                  "property",
+                  "AXColumnHeaderUIElements",
+                  "is",
+                  "[colheader1, colheader2]"
+               ],
+               [
+                  "property",
+                  "AXHeader",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXRowHeaderUIElements",
+                  "is",
+                  "[rowheader1, rowheader2]"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:grid"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleTable2"
+               ],
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_TABLE"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "DataGrid"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Selection"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "grid"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for grid.</p>
+    <div role='grid' id='test'>
+    <div role='row' id='headerrow'>
+      <div role='columnheader' id='colheader1'>content</div>
+      <div role='columnheader' id='colheader2'>content</div>
+    </div>
+    <div role='row'>
+      <div role='rowheader' id='rowheader1'>content</div>
+      <div role='gridcell'>content</div>
+    </div>
+    <div role='row'>
+      <div role='rowheader' id='rowheader2'>content</div>
+      <div role='gridcell'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/gridcell-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/gridcell-manual-expected.txt
new file mode 100644
index 0000000..f3bcd2b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/gridcell-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL gridcell Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/gridcell-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/gridcell-manual.html
new file mode 100644
index 0000000..04567986
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/gridcell-manual.html
@@ -0,0 +1,119 @@
+<!doctype html>
+<html>
+  <head>
+    <title>gridcell</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TABLE_CELL"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "TableCell"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXCell"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "cell"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleTableCell"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_CELL"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "DataItem"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "gridcell"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "SelectionItem"
+               ],
+               [
+                  "property",
+                  "SelectionItem.SelectionContainer",
+                  "is",
+                  "the containing grid"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "gridcell"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for gridcell.</p>
+    <div role='grid'>
+    <div role='row'>
+      <div role='gridcell' id='test'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/group-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/group-manual-expected.txt
new file mode 100644
index 0000000..1cee461
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/group-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL group Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/group-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/group-manual.html
new file mode 100644
index 0000000..72e4d3de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/group-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>group</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PANEL"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationGroup"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "group"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_GROUPING"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "group"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for group.</p>
+    <div role='group' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/heading-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/heading-manual-expected.txt
new file mode 100644
index 0000000..b85c6647
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/heading-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL heading Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/heading-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/heading-manual.html
new file mode 100644
index 0000000..f061e22
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/heading-manual.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+  <head>
+    <title>heading</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_HEADING"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXHeading"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "heading"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_HEADING"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:heading"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Text"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "heading"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "heading"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for heading.</p>
+    <div role='heading' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/img-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/img-manual-expected.txt
new file mode 100644
index 0000000..47629ed9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/img-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL img Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/img-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/img-manual.html
new file mode 100644
index 0000000..5de47dd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/img-manual.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<html>
+  <head>
+    <title>img</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_IMAGE"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Image"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXImage"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "image"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleImage"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_GRAPHIC"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Image"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "img"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for img.</p>
+    <div role='img' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/link-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/link-manual-expected.txt
new file mode 100644
index 0000000..ff49e7e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/link-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL link Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/link-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/link-manual.html
new file mode 100644
index 0000000..cf3efc0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/link-manual.html
@@ -0,0 +1,115 @@
+<!doctype html>
+<html>
+  <head>
+    <title>link</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LINK"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Hyperlink"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXLink"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "link"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_LINKED"
+               ],
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_LINKED"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleHypertext"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LINK"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "HyperLink"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Value"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "link"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for link.</p>
+    <div role='link' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/list-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/list-manual-expected.txt
new file mode 100644
index 0000000..1380550c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/list-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL list Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/list-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/list-manual.html
new file mode 100644
index 0000000..8b8331c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/list-manual.html
@@ -0,0 +1,93 @@
+<!doctype html>
+<html>
+  <head>
+    <title>list</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LIST"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXList"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXContentList"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "content list"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_READONLY"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LIST"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "List"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "list"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for list.</p>
+    <div role='list' id='test'>
+    <div role='listitem'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_not_owned_by_or_child_of_combobox-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_not_owned_by_or_child_of_combobox-manual-expected.txt
new file mode 100644
index 0000000..cd0de90
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_not_owned_by_or_child_of_combobox-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL listbox not owned by or child of combobox Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_not_owned_by_or_child_of_combobox-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_not_owned_by_or_child_of_combobox-manual.html
new file mode 100644
index 0000000..5af61d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_not_owned_by_or_child_of_combobox-manual.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<html>
+  <head>
+    <title>listbox not owned by or child of combobox</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LIST_BOX"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXList"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "list"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LIST"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "List"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Selection"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "listbox not owned by or child of combobox"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for listbox not owned by or child of combobox.</p>
+    <div role='listbox' id='test'>
+    <div role='option'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_owned_by_or_child_of_combobox-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_owned_by_or_child_of_combobox-manual-expected.txt
new file mode 100644
index 0000000..66c08436
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_owned_by_or_child_of_combobox-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL listbox owned by or child of combobox Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_owned_by_or_child_of_combobox-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_owned_by_or_child_of_combobox-manual.html
new file mode 100644
index 0000000..7d34cc2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listbox_owned_by_or_child_of_combobox-manual.html
@@ -0,0 +1,114 @@
+<!doctype html>
+<html>
+  <head>
+    <title>listbox owned by or child of combobox</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MENU"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXList"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "list"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LIST"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "List"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Selection"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "listbox owned by or child of combobox"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for listbox owned by or child of combobox.</p>
+    <div role='combobox'>
+    <div role='textbox'>content</div>
+    <div role='listbox' id='test'>
+      <div role='option'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/listitem-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listitem-manual-expected.txt
new file mode 100644
index 0000000..42e38d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listitem-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL listitem Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/listitem-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listitem-manual.html
new file mode 100644
index 0000000..009970d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/listitem-manual.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+  <head>
+    <title>listitem</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LIST_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "group"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_READONLY"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LISTITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "ListItem"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "SelectionItem"
+               ],
+               [
+                  "property",
+                  "SelectionItem.SelectionContainer",
+                  "is",
+                  "the containing list"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "listitem"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for listitem.</p>
+    <div role='list'>
+    <div role='listitem' id='test'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/log-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/log-manual-expected.txt
new file mode 100644
index 0000000..088e824
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/log-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL log Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/log-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/log-manual.html
new file mode 100644
index 0000000..a8a87665
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/log-manual.html
@@ -0,0 +1,137 @@
+<!doctype html>
+<html>
+  <head>
+    <title>log</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LOG"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:log"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live-role:log"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationLog"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "log"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:log"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live-role:log"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "log"
+               ],
+               [
+                  "property",
+                  "LiveSetting",
+                  "is",
+                  "Polite (1)"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "log"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for log.</p>
+    <div role='log' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/main_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/main_new-manual-expected.txt
new file mode 100644
index 0000000..467f2d3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/main_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL main NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/main_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/main_new-manual.html
new file mode 100644
index 0000000..26c7a13a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/main_new-manual.html
@@ -0,0 +1,107 @@
+<!doctype html>
+<html>
+  <head>
+    <title>main NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:main"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXLandmarkMain"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "main"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:main"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "main"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Main"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "main NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for main NEW.</p>
+    <div role='main' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/marquee-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/marquee-manual-expected.txt
new file mode 100644
index 0000000..fbad439
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/marquee-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL marquee Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/marquee-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/marquee-manual.html
new file mode 100644
index 0000000..25bf5a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/marquee-manual.html
@@ -0,0 +1,127 @@
+<!doctype html>
+<html>
+  <head>
+    <title>marquee</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MARQUEE"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:off"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:off"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationMarquee"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "marquee"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:marquee"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:off"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:off"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_ANIMATION"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "marquee"
+               ],
+               [
+                  "property",
+                  "LiveSetting",
+                  "is",
+                  "Off (0)"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "marquee"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for marquee.</p>
+    <div role='marquee' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/math-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/math-manual-expected.txt
new file mode 100644
index 0000000..0dc22a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/math-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL math Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/math-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/math-manual.html
new file mode 100644
index 0000000..3ff203c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/math-manual.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<html>
+  <head>
+    <title>math</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MATH"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXDocumentMath"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "math"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_EQUATION"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "math"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "math"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for math.</p>
+    <div role='math' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menu-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menu-manual-expected.txt
new file mode 100644
index 0000000..9bbc72a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menu-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL menu Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menu-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menu-manual.html
new file mode 100644
index 0000000..d336e2c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menu-manual.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+  <head>
+    <title>menu</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MENU"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXMenu"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "menu"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_MENUPOPUP"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Menu"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "menu"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for menu.</p>
+    <div role='menu' id='test'>
+    <div role='menuitemradio'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menubar-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menubar-manual-expected.txt
new file mode 100644
index 0000000..bdf333f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menubar-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL menubar Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menubar-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menubar-manual.html
new file mode 100644
index 0000000..f4bc7d2a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menubar-manual.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+  <head>
+    <title>menubar</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MENU_BAR"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXMenuBar"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "menu bar"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_MENUBAR"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "MenuBar"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "menubar"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for menubar.</p>
+    <div role='menubar' id='test'>
+    <div role='menuitemradio'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_not_owned_by_or_child_of_group-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_not_owned_by_or_child_of_group-manual-expected.txt
new file mode 100644
index 0000000..9e1aeba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_not_owned_by_or_child_of_group-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL menuitem not owned by or child of group Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_not_owned_by_or_child_of_group-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_not_owned_by_or_child_of_group-manual.html
new file mode 100644
index 0000000..7352b358
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_not_owned_by_or_child_of_group-manual.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<html>
+  <head>
+    <title>menuitem not owned by or child of group</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MENU_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXMenuItem"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "menu item"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_MENUITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "MenuItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "menuitem not owned by or child of group"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for menuitem not owned by or child of group.</p>
+    <div role='menu'>
+    <div role='menuitem' id='test'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_owned_by_or_child_of_group-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_owned_by_or_child_of_group-manual-expected.txt
new file mode 100644
index 0000000..ee9525b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_owned_by_or_child_of_group-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL menuitem owned by or child of group Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_owned_by_or_child_of_group-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_owned_by_or_child_of_group-manual.html
new file mode 100644
index 0000000..04d9af5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitem_owned_by_or_child_of_group-manual.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<html>
+  <head>
+    <title>menuitem owned by or child of group</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MENU_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXMenuButton"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "menu button"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_MENUITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "MenuItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "menuitem owned by or child of group"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for menuitem owned by or child of group.</p>
+    <div role='menu'>
+    <div role='group'>
+      <div role='menuitem' id='test'>content 1</div>
+    </div>
+    <div role='menuitem'>content 2</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemcheckbox-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemcheckbox-manual-expected.txt
new file mode 100644
index 0000000..515b5ba4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemcheckbox-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL menuitemcheckbox Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemcheckbox-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemcheckbox-manual.html
new file mode 100644
index 0000000..1868ebe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemcheckbox-manual.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+  <head>
+    <title>menuitemcheckbox</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_CHECK_MENU_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXMenuItem"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "menu item"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_CHECK_MENU_ITEM"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_CHECKBUTTON or ROLE_SYSTEM_MENUITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "MenuItem"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Toggle"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "menuitemcheckbox"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for menuitemcheckbox.</p>
+    <div role='menu'>
+    <div role='menuitemcheckbox' id='test'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemradio-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemradio-manual-expected.txt
new file mode 100644
index 0000000..3686b9e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemradio-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL menuitemradio Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemradio-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemradio-manual.html
new file mode 100644
index 0000000..bdd0fc3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/menuitemradio-manual.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+  <head>
+    <title>menuitemradio</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_RADIO_MENU_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXMenuItem"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "menu item"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_RADIO_MENU_ITEM"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_RADIOBUTTON or ROLE_SYSTEM_MENUITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "MenuItem"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Toggle"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "SelectionItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "menuitemradio"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for menuitemradio.</p>
+    <div role='menu'>
+    <div role='menuitemradio' id='test'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/navigation_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/navigation_new-manual-expected.txt
new file mode 100644
index 0000000..25ed64a5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/navigation_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL navigation NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/navigation_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/navigation_new-manual.html
new file mode 100644
index 0000000..8ff8d74
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/navigation_new-manual.html
@@ -0,0 +1,107 @@
+<!doctype html>
+<html>
+  <head>
+    <title>navigation NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:navigation"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXLandmarkNavigation"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "navigation"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:navigation"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "navigation"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Navigation"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "navigation NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for navigation NEW.</p>
+    <div role='navigation' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/none_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/none_new-manual-expected.txt
new file mode 100644
index 0000000..bdafb8b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/none_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL none NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/none_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/none_new-manual.html
new file mode 100644
index 0000000..feb096a5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/none_new-manual.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html>
+  <head>
+    <title>none NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "none NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for none NEW.</p>
+    <div role='none' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/note-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/note-manual-expected.txt
new file mode 100644
index 0000000..ec28206
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/note-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL note Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/note-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/note-manual.html
new file mode 100644
index 0000000..4210dddb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/note-manual.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<html>
+  <head>
+    <title>note</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_COMMENT"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXDocumentNote"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "note"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_NOTE"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "note"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "note"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for note.</p>
+    <div role='note' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_inside_combobox-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_inside_combobox-manual-expected.txt
new file mode 100644
index 0000000..65f4bc3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_inside_combobox-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL option inside combobox Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_inside_combobox-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_inside_combobox-manual.html
new file mode 100644
index 0000000..0d11730
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_inside_combobox-manual.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<html>
+  <head>
+    <title>option inside combobox</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_MENU_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXStaticText"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "text"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LISTITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "ListItem"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Invoke"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "option inside combobox"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for option inside combobox.</p>
+    <div role='option' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_not_inside_combobox-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_not_inside_combobox-manual-expected.txt
new file mode 100644
index 0000000..21a4d35d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_not_inside_combobox-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL option not inside combobox Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_not_inside_combobox-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_not_inside_combobox-manual.html
new file mode 100644
index 0000000..e25ff8f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/option_not_inside_combobox-manual.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<html>
+  <head>
+    <title>option not inside combobox</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LIST_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXStaticText"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "text"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_LISTITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "ListItem"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Invoke"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "option not inside combobox"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for option not inside combobox.</p>
+    <div role='option' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/presentation-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/presentation-manual-expected.txt
new file mode 100644
index 0000000..f01e45e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/presentation-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL presentation Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/presentation-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/presentation-manual.html
new file mode 100644
index 0000000..0436e7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/presentation-manual.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<html>
+  <head>
+    <title>presentation</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "presentation"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for presentation.</p>
+    <div role='presentation' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/progressbar-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/progressbar-manual-expected.txt
new file mode 100644
index 0000000..3c55a7a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/progressbar-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL progressbar Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/progressbar-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/progressbar-manual.html
new file mode 100644
index 0000000..be7adc7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/progressbar-manual.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<html>
+  <head>
+    <title>progressbar</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PROGRESS_BAR"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Value"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXProgressIndicator"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "progress indicator"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SYSTEM_READONLY"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAcesssibleValue"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_PROGRESSBAR"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "ProgressBar"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "RangeValue"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "progressbar"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for progressbar.</p>
+    <div role='progressbar' aria-valuenow='20' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/radio-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radio-manual-expected.txt
new file mode 100644
index 0000000..334c3379
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radio-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL radio Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/radio-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radio-manual.html
new file mode 100644
index 0000000..aac0707
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radio-manual.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+  <head>
+    <title>radio</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_RADIO_BUTTON"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXRadioButton"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "radio button"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_RADIOBUTTON"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "RadioButton"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Toggle"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "SelectionItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "radio"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for radio.</p>
+    <div role='radio' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/radiogroup-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radiogroup-manual-expected.txt
new file mode 100644
index 0000000..9bd8a178
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radiogroup-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL radiogroup Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/radiogroup-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radiogroup-manual.html
new file mode 100644
index 0000000..649ceab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/radiogroup-manual.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<html>
+  <head>
+    <title>radiogroup</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PANEL"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXRadioGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "radio group"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_GROUPING"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "List"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "radiogroup"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for radiogroup.</p>
+    <div role='radiogroup' id='test'>
+    <div role='radio'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_with_an_accessible_name_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_with_an_accessible_name_new-manual-expected.txt
new file mode 100644
index 0000000..5abe01a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_with_an_accessible_name_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL region with an accessible name NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_with_an_accessible_name_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_with_an_accessible_name_new-manual.html
new file mode 100644
index 0000000..c4942d0f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_with_an_accessible_name_new-manual.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<html>
+  <head>
+    <title>region with an accessible name NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:region"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXLandmarkRegion"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "region"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:region"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "region"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Custom"
+               ],
+               [
+                  "property",
+                  "LocalizedLandmarkType",
+                  "is",
+                  "region"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "region with an accessible name NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for region with an accessible name NEW.</p>
+    <div role='region' aria-label='name for region' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_without_an_accessible_name_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_without_an_accessible_name_new-manual-expected.txt
new file mode 100644
index 0000000..c3e9915f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_without_an_accessible_name_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL region without an accessible name NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_without_an_accessible_name_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_without_an_accessible_name_new-manual.html
new file mode 100644
index 0000000..e088085
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/region_without_an_accessible_name_new-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>region without an accessible name NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SECTION"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "group"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_SECTION"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "Control Type",
+                  "is",
+                  "Group"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "region without an accessible name NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for region without an accessible name NEW.</p>
+    <div role='region' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_inside_treegrid-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_inside_treegrid-manual-expected.txt
new file mode 100644
index 0000000..7eba6a7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_inside_treegrid-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL row inside treegrid Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_inside_treegrid-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_inside_treegrid-manual.html
new file mode 100644
index 0000000..6d875e02
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_inside_treegrid-manual.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+  <head>
+    <title>row inside treegrid</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TABLE_ROW"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXRow"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "row"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_OUTLINEITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "DataItem"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "row"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "SelectionItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "row inside treegrid"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for row inside treegrid.</p>
+    <div role='treegrid'>
+    <div role='row' id='test'>
+      <div role='gridcell'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_not_inside_treegrid-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_not_inside_treegrid-manual-expected.txt
new file mode 100644
index 0000000..96ffb824
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_not_inside_treegrid-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL row not inside treegrid Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_not_inside_treegrid-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_not_inside_treegrid-manual.html
new file mode 100644
index 0000000..500f098d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/row_not_inside_treegrid-manual.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+  <head>
+    <title>row not inside treegrid</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TABLE_ROW"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXRow"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "row"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_ROW"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "DataItem"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "row"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "SelectionItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "row not inside treegrid"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for row not inside treegrid.</p>
+    <div role='grid'>
+    <div role='row' id='test'>
+      <div role='gridcell'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowgroup-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowgroup-manual-expected.txt
new file mode 100644
index 0000000..04e5d069
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowgroup-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL rowgroup Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowgroup-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowgroup-manual.html
new file mode 100644
index 0000000..06eb8d5a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowgroup-manual.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<html>
+  <head>
+    <title>rowgroup</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PANEL"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "accessible",
+                  "is",
+                  "false"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_GROUPING"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "rowgroup"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for rowgroup.</p>
+    <div role='grid'>
+    <div role='rowgroup' id='test'>
+      <div role='row'>
+        <div role='cell'>content</div>
+      </div>
+      <div role='row'>
+        <div role='cell'>content</div>
+      </div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowheader-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowheader-manual-expected.txt
new file mode 100644
index 0000000..9480de4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowheader-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL rowheader Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowheader-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowheader-manual.html
new file mode 100644
index 0000000..01b86f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/rowheader-manual.html
@@ -0,0 +1,101 @@
+<!doctype html>
+<html>
+  <head>
+    <title>rowheader</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_ROW_HEADER"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "TableCell"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXCell"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "cell"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleTableCell"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_ROWHEADER"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "HeaderItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "rowheader"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for rowheader.</p>
+    <div role='grid'>
+    <div role='row'>
+      <div role='rowheader' id='test'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/scrollbar-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/scrollbar-manual-expected.txt
new file mode 100644
index 0000000..c6204fa7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/scrollbar-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL scrollbar Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/scrollbar-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/scrollbar-manual.html
new file mode 100644
index 0000000..66c1a0e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/scrollbar-manual.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+  <head>
+    <title>scrollbar</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SCROLL_BAR"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Value"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXScrollBar"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "scroll bar"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAcesssibleValue"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_SCROLLBAR"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "ScrollBar"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "RangeValue"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "scrollbar"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for scrollbar.</p>
+    <div role='scrollbar' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/search_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/search_new-manual-expected.txt
new file mode 100644
index 0000000..f1f9a8f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/search_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL search NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/search_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/search_new-manual.html
new file mode 100644
index 0000000..9d97257
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/search_new-manual.html
@@ -0,0 +1,107 @@
+<!doctype html>
+<html>
+  <head>
+    <title>search NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:search"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXLandmarkSearch"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "search"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_LANDMARK"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:search"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "search"
+               ],
+               [
+                  "property",
+                  "Landmark Type",
+                  "is",
+                  "Search"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "search NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for search NEW.</p>
+    <div role='search' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/searchbox_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/searchbox_new-manual-expected.txt
new file mode 100644
index 0000000..637c2aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/searchbox_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL searchbox NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/searchbox_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/searchbox_new-manual.html
new file mode 100644
index 0000000..3126a6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/searchbox_new-manual.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<html>
+  <head>
+    <title>searchbox NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_ENTRY"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:searchbox"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "EditableText"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXTextField"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXSearchField"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "search text field"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "text-input-type:search"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_TEXT"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Edit"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "search box"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "searchbox NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for searchbox NEW.</p>
+    <div role='searchbox' contenteditable id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_focusable_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_focusable_new-manual-expected.txt
new file mode 100644
index 0000000..66b5860
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_focusable_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL separator focusable NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_focusable_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_focusable_new-manual.html
new file mode 100644
index 0000000..8d7d32e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_focusable_new-manual.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+  <head>
+    <title>separator focusable NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SEPARATOR"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Value"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXSplitter"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "splitter"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleValue"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_SEPARATOR"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Thumb"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "RangeValue"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "separator focusable NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for separator focusable NEW.</p>
+    <div role='separator' tabindex='0' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_non-focusable-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_non-focusable-manual-expected.txt
new file mode 100644
index 0000000..05cd589
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_non-focusable-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL separator non-focusable Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_non-focusable-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_non-focusable-manual.html
new file mode 100644
index 0000000..ac5e2372
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/separator_non-focusable-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>separator non-focusable</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SEPARATOR"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXSplitter"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "splitter"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_SEPARATOR"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Separator"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "separator non-focusable"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for separator non-focusable.</p>
+    <div role='separator' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/slider-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/slider-manual-expected.txt
new file mode 100644
index 0000000..cb5a0da
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/slider-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL slider Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/slider-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/slider-manual.html
new file mode 100644
index 0000000..a1077a38
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/slider-manual.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+  <head>
+    <title>slider</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SLIDER"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Value"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXSlider"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "slider"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAcesssibleValue"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_SLIDER"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Slider"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "RangeValue"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "slider"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for slider.</p>
+    <div role='slider' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/spinbutton-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/spinbutton-manual-expected.txt
new file mode 100644
index 0000000..865eda5b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/spinbutton-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL spinbutton Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/spinbutton-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/spinbutton-manual.html
new file mode 100644
index 0000000..5f62aa6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/spinbutton-manual.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+  <head>
+    <title>spinbutton</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SPIN_BUTTON"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Value"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXIncrementor"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "stepper"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAcesssibleValue"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_SPINBUTTON"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Spinner"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "RangeValue"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "spinbutton"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for spinbutton.</p>
+    <div role='spinbutton' id='test'>10</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/status-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/status-manual-expected.txt
new file mode 100644
index 0000000..c3ab0280
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/status-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL status Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/status-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/status-manual.html
new file mode 100644
index 0000000..3fb304a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/status-manual.html
@@ -0,0 +1,133 @@
+<!doctype html>
+<html>
+  <head>
+    <title>status</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_STATUSBAR"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live-role:status"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationStatus"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "application status"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:polite"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live-role:status"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_STATUSBAR"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "status"
+               ],
+               [
+                  "property",
+                  "LiveSetting",
+                  "is",
+                  "Polite (1)"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "status"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for status.</p>
+    <div role='status' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/switch_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/switch_new-manual-expected.txt
new file mode 100644
index 0000000..45d95e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/switch_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL switch NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/switch_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/switch_new-manual.html
new file mode 100644
index 0000000..4aeb6bb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/switch_new-manual.html
@@ -0,0 +1,115 @@
+<!doctype html>
+<html>
+  <head>
+    <title>switch NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TOGGLE_BUTTON"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:switch"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXCheckBox"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXSwitch"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "switch"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_TOGGLE_BUTTON"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:switch"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_CHECKBUTTON"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Button"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "toggleswitch"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Toggle"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "switch NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for switch NEW.</p>
+    <div role='switch' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tab-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tab-manual-expected.txt
new file mode 100644
index 0000000..09a8250
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tab-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL tab Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tab-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tab-manual.html
new file mode 100644
index 0000000..e3efdad4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tab-manual.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<html>
+  <head>
+    <title>tab</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PAGE_TAB"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXRadioButton"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "tab"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_PAGETAB"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "TabItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "tab"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for tab.</p>
+    <div role='tablist'>
+    <div role='tab' id='test'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/table_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/table_new-manual-expected.txt
new file mode 100644
index 0000000..8f1e376
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/table_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL table NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/table_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/table_new-manual.html
new file mode 100644
index 0000000..76bb643c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/table_new-manual.html
@@ -0,0 +1,152 @@
+<!doctype html>
+<html>
+  <head>
+    <title>table NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TABLE"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:table"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Table"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXTable"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "table"
+               ],
+               [
+                  "property",
+                  "AXColumnHeaderUIElements",
+                  "is",
+                  "[colheader1, colheader2]"
+               ],
+               [
+                  "property",
+                  "AXHeader",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXRowHeaderUIElements",
+                  "is",
+                  "[rowheader1, rowheader2]"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:table"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleTable2"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_TABLE"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Table"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Grid"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Table"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "table NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for table NEW.</p>
+    <div role='table' id='test'>
+    <div role='row' id='headerrow'>
+      <div role='columnheader' id='colheader1'>content</div>
+      <div role='columnheader' id='colheader2'>content</div>
+    </div>
+    <div role='row'>
+      <div role='rowheader' id='rowheader1'>content</div>
+      <div role='cell'>content</div>
+    </div>
+    <div role='row'>
+      <div role='rowheader' id='rowheader2'>content</div>
+      <div role='cell'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tablist-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tablist-manual-expected.txt
new file mode 100644
index 0000000..2690fd6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tablist-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL tablist Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tablist-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tablist-manual.html
new file mode 100644
index 0000000..b21c3b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tablist-manual.html
@@ -0,0 +1,111 @@
+<!doctype html>
+<html>
+  <head>
+    <title>tablist</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_PAGE_TAB_LIST"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXTabGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "tab group"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_PAGETABLIST"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Tab"
+               ],
+               [
+                  "property",
+                  "Control Pattern",
+                  "is",
+                  "Selection"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "tablist"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for tablist.</p>
+    <div role='tablist' id='test'>
+    <div role='tab'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tabpanel-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tabpanel-manual-expected.txt
new file mode 100644
index 0000000..0db45e6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tabpanel-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL tabpanel Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tabpanel-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tabpanel-manual.html
new file mode 100644
index 0000000..58f399d6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tabpanel-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>tabpanel</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SCROLL_PANE"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXTabPanel"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "tab panel"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_PANE or ROLE_SYSTEM_PROPERTYPAGE"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Pane"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "tabpanel"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for tabpanel.</p>
+    <div role='tabpanel' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/term_new-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/term_new-manual-expected.txt
new file mode 100644
index 0000000..8e2e8544
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/term_new-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL term NEW Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/term_new-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/term_new-manual.html
new file mode 100644
index 0000000..9985d48e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/term_new-manual.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+  <head>
+    <title>term NEW</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_DESCRIPTION_TERM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXTerm"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "term"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "IA2_ROLE_TEXT_FRAME"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:term"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Text"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "term"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "term NEW"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for term NEW.</p>
+    <div role='term' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_false-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_false-manual-expected.txt
new file mode 100644
index 0000000..113914b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_false-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL textbox when aria-multiline is false Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_false-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_false-manual.html
new file mode 100644
index 0000000..8a37537c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_false-manual.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+  <head>
+    <title>textbox when aria-multiline is false</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_ENTRY"
+               ],
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_SINGLE_LINE"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "EditableText"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXTextField"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "text field"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "IA2_STATE_SINGLE_LINE"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_TEXT"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Edit"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "textbox when aria-multiline is false"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for textbox when aria-multiline is false.</p>
+    <div role='textbox' contenteditable aria-multiline='false' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_true-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_true-manual-expected.txt
new file mode 100644
index 0000000..c16423b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_true-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL textbox when aria-multiline is true Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_true-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_true-manual.html
new file mode 100644
index 0000000..d572471
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/textbox_when_aria-multiline_is_true-manual.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+  <head>
+    <title>textbox when aria-multiline is true</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_ENTRY"
+               ],
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "STATE_MULTI_LINE"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "EditableText"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXTextArea"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "text entry area"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "states",
+                  "contains",
+                  "IA2_STATE_MULTI_LINE"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_TEXT"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Edit"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "textbox when aria-multiline is true"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for textbox when aria-multiline is true.</p>
+    <div role='textbox' contenteditable aria-multiline='true' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/timer-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/timer-manual-expected.txt
new file mode 100644
index 0000000..d2cb97b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/timer-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL timer Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/timer-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/timer-manual.html
new file mode 100644
index 0000000..9751038
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/timer-manual.html
@@ -0,0 +1,131 @@
+<!doctype html>
+<html>
+  <head>
+    <title>timer</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TIMER"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:off"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:off"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live-role:timer"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXApplicationTimer"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "timer"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "xml-roles:timer"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live:off"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "live:off"
+               ],
+               [
+                  "property",
+                  "objectAttributes",
+                  "contains",
+                  "container-live-role:timer"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Group"
+               ],
+               [
+                  "property",
+                  "LocalizedControlType",
+                  "is",
+                  "timer"
+               ],
+               [
+                  "property",
+                  "LiveSetting",
+                  "is",
+                  "Off (0)"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "timer"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for timer.</p>
+    <div role='timer' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/toolbar-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/toolbar-manual-expected.txt
new file mode 100644
index 0000000..37c7fd1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/toolbar-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL toolbar Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/toolbar-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/toolbar-manual.html
new file mode 100644
index 0000000..47e29835
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/toolbar-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>toolbar</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TOOL_BAR"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXToolbar"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "toolbar"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_TOOLBAR"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "ToolBar"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "toolbar"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for toolbar.</p>
+    <div role='toolbar' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tooltip-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tooltip-manual-expected.txt
new file mode 100644
index 0000000..6adc4de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tooltip-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL tooltip Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tooltip-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tooltip-manual.html
new file mode 100644
index 0000000..d9686afd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tooltip-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+  <head>
+    <title>tooltip</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TOOL_TIP"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXGroup"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXUserInterfaceTooltip"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "tooltip"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_TOOLTIP"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "ToolTip"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "tooltip"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for tooltip.</p>
+    <div role='tooltip' id='test'>content</div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tree-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tree-manual-expected.txt
new file mode 100644
index 0000000..c3900d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tree-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL tree Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/tree-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tree-manual.html
new file mode 100644
index 0000000..ad13930f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/tree-manual.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+  <head>
+    <title>tree</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TREE"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXOutline"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "outline"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_OUTLINE"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "Tree"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "tree"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for tree.</p>
+    <div role='tree' id='test'>
+    <div role='treeitem'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/treegrid-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treegrid-manual-expected.txt
new file mode 100644
index 0000000..9a5ede22
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treegrid-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL treegrid Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/treegrid-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treegrid-manual.html
new file mode 100644
index 0000000..6b0683a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treegrid-manual.html
@@ -0,0 +1,119 @@
+<!doctype html>
+<html>
+  <head>
+    <title>treegrid</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TREE_TABLE"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Table"
+               ],
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "Selection"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXTable"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "<nil>"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "table"
+               ]
+            ],
+            "IAccessible2" : [
+               [
+                  "property",
+                  "interfaces",
+                  "contains",
+                  "IAccessibleTable2"
+               ],
+               [
+                  "result",
+                  "IAccessible::accSelect()",
+                  "is",
+                  "TBD"
+               ],
+               [
+                  "result",
+                  "IAccessible::get_accSelection()",
+                  "is",
+                  "TBD"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_OUTLINE"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "DataGrid"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "treegrid"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for treegrid.</p>
+    <div role='treegrid' id='test'>
+    <div role='row'>
+      <div role='gridcell'>content</div>
+    </div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/treeitem-manual-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treeitem-manual-expected.txt
new file mode 100644
index 0000000..a69bc517f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treeitem-manual-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL treeitem Uncaught ReferenceError: ATTAcomm is not defined
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/core-aam/treeitem-manual.html b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treeitem-manual.html
new file mode 100644
index 0000000..7dee1530
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/core-aam/treeitem-manual.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<html>
+  <head>
+    <title>treeitem</title>
+    <link rel="stylesheet" href="/resources/testharness.css">
+    <link rel="stylesheet" href="/wai-aria/scripts/manual.css">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/wai-aria/scripts/ATTAcomm.js"></script>
+    <script>
+    setup({explicit_timeout: true, explicit_done: true });
+
+    var theTest = new ATTAcomm(
+    {
+   "steps" : [
+      {
+         "element" : "test",
+         "test" : {
+            "ATK" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_TREE_ITEM"
+               ]
+            ],
+            "AXAPI" : [
+               [
+                  "property",
+                  "AXRole",
+                  "is",
+                  "AXRow"
+               ],
+               [
+                  "property",
+                  "AXSubrole",
+                  "is",
+                  "AXOutlineRow"
+               ],
+               [
+                  "property",
+                  "AXRoleDescription",
+                  "is",
+                  "outline row"
+               ]
+            ],
+            "MSAA" : [
+               [
+                  "property",
+                  "role",
+                  "is",
+                  "ROLE_SYSTEM_OUTLINEITEM"
+               ]
+            ],
+            "UIA" : [
+               [
+                  "property",
+                  "ControlType",
+                  "is",
+                  "TreeItem"
+               ]
+            ]
+         },
+         "title" : "step 1",
+         "type" : "test"
+      }
+   ],
+   "title" : "treeitem"
+}
+
+    ) ;
+    </script>
+  </head>
+  <body>
+  <p>This test examines the ARIA properties for treeitem.</p>
+    <div role='tree'>
+    <div role='treeitem' id='test'>content</div>
+  </div>
+
+  <div id="manualMode"></div>
+  <div id="log"></div>
+  <div id="ATTAmessages"></div>
+  </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-definition/grid-shorthand-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-definition/grid-shorthand-001.html
new file mode 100644
index 0000000..476415e8d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-definition/grid-shorthand-001.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: 'grid' shorthand does not reset gutter properties</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-shorthand">
+<meta name="flags" content="dom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #grid {
+    display: grid;
+    grid-column-gap: 10px;
+    grid-row-gap: 20px;
+  }
+</style>
+<div id="grid"></div>
+<script>
+  var grid = document.getElementById("grid");
+
+  test(
+    () => {
+      assert_equals(window.getComputedStyle(grid)["grid-template-columns"], "none");
+      assert_equals(window.getComputedStyle(grid)["grid-template-rows"], "none");
+      assert_equals(window.getComputedStyle(grid)["grid-column-gap"], "10px");
+      assert_equals(window.getComputedStyle(grid)["grid-row-gap"], "20px");
+    }, "Check gutter properties initial values");
+
+  grid.style.grid = "100px / 200px";
+
+  test(
+    () => {
+      assert_equals(window.getComputedStyle(grid)["grid-template-columns"], "200px");
+      assert_equals(window.getComputedStyle(grid)["grid-template-rows"], "100px");
+      assert_equals(window.getComputedStyle(grid)["grid-column-gap"], "10px");
+      assert_equals(window.getComputedStyle(grid)["grid-row-gap"], "20px");
+    }, "Check gutter properties after setting 'grid' shorthand");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode-expected.txt
index 2fbe8a8d..6bd5c1b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode-expected.txt
@@ -1,10 +1,9 @@
 This is a testharness.js-based test.
-Found 133 tests; 131 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 132 tests; 131 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS createElement(a)
 PASS createElement(abbr)
 PASS createElement(acronym)
 PASS createElement(address)
-FAIL createElement(applet) assert_true: HTMLAppletElement is not supported expected true got false
 PASS createElement(area)
 PASS createElement(article)
 PASS createElement(aside)
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode.html b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode.html
index 5ed7b08c..6c86630 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-cloneNode.html
@@ -54,7 +54,6 @@
 create_element_and_check("abbr",      "HTMLElement");
 create_element_and_check("acronym",   "HTMLElement");
 create_element_and_check("address",   "HTMLElement");
-create_element_and_check("applet",    "HTMLAppletElement");
 create_element_and_check("area",      "HTMLAreaElement");
 create_element_and_check("article",   "HTMLElement");
 create_element_and_check("aside",     "HTMLElement");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects-expected.txt
index b70318f3..be1d776 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 PASS Check if the first nested browsing context is returned by window['c']
-FAIL Check if window['a'] contains all applet, embed, form, img, and object elements, and their order assert_equals: The length should be 5. expected 5 but got 4
+FAIL Check if window['a'] contains all embed, form, img, and object elements, and their order assert_equals: The length should be 5. expected 5 but got 4
 PASS Check that window['fs'] does not return the frameset element with name='fs' (historical)
 PASS Check if window['b'] returns the elements with the id='b'
 PASS Check if window['d'] returns the element with id='d'
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html
index f020e0e..bd3a7b6d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/named-access-on-the-window-object/named-objects.html
@@ -9,7 +9,6 @@
 <div style="display:none">
   <p name="a" id="p1"></p>
   <a name="a" id="a1" href="#"></a>
-  <applet name="a" id="app1"></applet>
   <area name="a" id="area1"></area>
   <embed name="a" id="embed1"></embed>
   <form name="a" id="form1"></form>
@@ -36,7 +35,7 @@
   assert_equals(window['a'].length, 5, "The length should be 5.");
   assert_true(window['a'] instanceof HTMLCollection);
   assert_array_equals(window['a'],
-                      [ document.getElementById('app1'), document.getElementById('embed1'),
+                      [ document.getElementById('embed1'),
                         document.getElementById('form1'), document.getElementById('img1'),
                         document.getElementById('obj1') ],
                       "The elements are not in tree order.");
@@ -44,10 +43,10 @@
   document.getElementById('form1').setAttribute("name", "");
   document.getElementById('embed1').setAttribute("name", "");
   assert_array_equals(window['a'],
-                      [ document.getElementById('app1'), document.getElementById('img1'),
+                      [ document.getElementById('img1'),
                         document.getElementById('obj1') ],
                       "Window['a'] should not contain the elements with empty name attribute.");
-}, "Check if window['a'] contains all applet, embed, form, img, and object elements, and their order");
+}, "Check if window['a'] contains all embed, form, img, and object elements, and their order");
 
 var t = async_test("Check that window['fs'] does not return the frameset element with name='fs' (historical)");
 function on_load () {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-03-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-03-expected.txt
deleted file mode 100644
index 23d3fe25..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-03-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This is a testharness.js-based test.
-FAIL If there is one applet, it should be returned (name) assert_equals: expected (string) "test1" but got (undefined) undefined
-FAIL If there are two applets, a collection should be returned. (name) assert_equals: expected (string) "test2" but got (undefined) undefined
-FAIL If there is one applet, it should be returned (id) assert_true: "test3" in document should be true expected true got false
-FAIL If there are two applets, a collection should be returned. (id) assert_true: "test4" in document should be true expected true got false
-FAIL If there are two applets, a collection should be returned. (name and id) assert_equals: expected (string) "test5" but got (undefined) undefined
-FAIL If there are two applets, a collection should be returned. (id and name) assert_equals: expected (string) "test6" but got (undefined) undefined
-FAIL A name shouldn't affect getting an applet by id assert_true: "test7" in document should be true expected true got false
-FAIL An id shouldn't affect getting an applet by name assert_equals: expected (string) "test8" but got (undefined) undefined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-03.html b/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-03.html
index 4c330b6..be2ca173 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-03.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-03.html
@@ -6,105 +6,13 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
-<div id="test">
 <applet name=test1></applet>
-
-<applet name=test2></applet>
-<applet name=test2></applet>
-
-<applet id=test3></applet>
-
-<applet id=test4></applet>
-<applet id=test4></applet>
-
-<applet name=test5></applet>
-<applet id=test5></applet>
-
-<applet id=test6></applet>
-<applet name=test6></applet>
-
-<applet id=test7 name=fail></applet>
-
-<applet name=test8 id=fail></applet>
-</div>
 <script>
 test(function() {
   var applet = document.getElementsByTagName("applet")[0];
-  assert_equals(applet.name, "test1");
+  assert_equals(applet.name, undefined);
 
-  assert_true("test1" in document, '"test1" in document should be true');
-  assert_equals(document.test1, applet);
-}, "If there is one applet, it should be returned (name)");
-
-test(function() {
-  var applet1 = document.getElementsByTagName("applet")[1];
-  assert_equals(applet1.name, "test2");
-  var applet2 = document.getElementsByTagName("applet")[2];
-  assert_equals(applet2.name, "test2");
-
-  assert_true("test2" in document, '"test2" in document should be true');
-  var collection = document.test2;
-  assert_class_string(collection, "HTMLCollection", "collection should be an HTMLCollection");
-  assert_array_equals(collection, [applet1, applet2]);
-}, "If there are two applets, a collection should be returned. (name)");
-
-test(function() {
-  var applet = document.getElementsByTagName("applet")[3];
-  assert_equals(applet.id, "test3");
-
-  assert_true("test3" in document, '"test3" in document should be true');
-  assert_equals(document.test3, applet);
-}, "If there is one applet, it should be returned (id)");
-
-test(function() {
-  var applet1 = document.getElementsByTagName("applet")[4];
-  assert_equals(applet1.id, "test4");
-  var applet2 = document.getElementsByTagName("applet")[5];
-  assert_equals(applet2.id, "test4");
-
-  assert_true("test4" in document, '"test4" in document should be true');
-  var collection = document.test4;
-  assert_class_string(collection, "HTMLCollection", "collection should be an HTMLCollection");
-  assert_array_equals(collection, [applet1, applet2]);
-}, "If there are two applets, a collection should be returned. (id)");
-
-test(function() {
-  var applet1 = document.getElementsByTagName("applet")[6];
-  assert_equals(applet1.name, "test5");
-  var applet2 = document.getElementsByTagName("applet")[7];
-  assert_equals(applet2.id, "test5");
-
-  assert_true("test5" in document, '"test5" in document should be true');
-  var collection = document.test5;
-  assert_class_string(collection, "HTMLCollection", "collection should be an HTMLCollection");
-  assert_array_equals(collection, [applet1, applet2]);
-}, "If there are two applets, a collection should be returned. (name and id)");
-
-test(function() {
-  var applet1 = document.getElementsByTagName("applet")[8];
-  assert_equals(applet1.id, "test6");
-  var applet2 = document.getElementsByTagName("applet")[9];
-  assert_equals(applet2.name, "test6");
-
-  assert_true("test6" in document, '"test6" in document should be true');
-  var collection = document.test6;
-  assert_class_string(collection, "HTMLCollection", "collection should be an HTMLCollection");
-  assert_array_equals(collection, [applet1, applet2]);
-}, "If there are two applets, a collection should be returned. (id and name)");
-
-test(function() {
-  var applet = document.getElementsByTagName("applet")[10];
-  assert_equals(applet.id, "test7");
-
-  assert_true("test7" in document, '"test7" in document should be true');
-  assert_equals(document.test7, applet);
-}, "A name shouldn't affect getting an applet by id");
-
-test(function() {
-  var applet = document.getElementsByTagName("applet")[11];
-  assert_equals(applet.name, "test8");
-
-  assert_true("test8" in document, '"test8" in document should be true');
-  assert_equals(document.test8, applet);
-}, "An id shouldn't affect getting an applet by name");
+  assert_false("test1" in document, '"test1" in document should be false');
+  assert_equals(document.test1, undefined);
+}, "applet elements are (mostly) gone");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-08-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-08-expected.txt
deleted file mode 100644
index 60e2d574..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-08-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL If there is a div and applet with same id, the applet should be returned assert_true: expected true got false
-PASS If there is a div and object with same id, the object should be returned
-PASS If there is a div and img with same id, the img should be returned
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-08.html b/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-08.html
index a5c26f39..bb024d9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-08.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/documents/dom-tree-accessors/nameditem-08.html
@@ -1,14 +1,11 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<title>Named items: duplicate id attributes for applet, object and img</title>
+<title>Named items: duplicate id attributes for object and img</title>
 <link rel="help" href="https://html.spec.whatwg.org/multipage/dom.html#dom-document-nameditem">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
 <div id="test">
-<div id=test1></div>
-<applet id=test1></applet>
-
 <div id=test2></div>
 <object id=test2></object>
 
@@ -17,14 +14,6 @@
 </div>
 <script>
 test(function() {
-  var applet = document.querySelector("applet");
-  assert_equals(applet.id, "test1");
-
-  assert_true("test1" in document);
-  assert_equals(document.test1, applet);
-}, "If there is a div and applet with same id, the applet should be returned");
-
-test(function() {
   var object = document.querySelector("object");
   assert_equals(object.id, "test2");
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/historical-expected.txt
new file mode 100644
index 0000000..69557f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/historical-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS document.applets is always empty
+PASS HTMLAppletElement is no more
+FAIL document.all cannot find applet assert_equals: expected (undefined) undefined but got (object) Element node <applet name="war" align="left"></applet>
+PASS document cannot find applet
+PASS window cannot find applet
+PASS applet is not styled
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/historical.html b/third_party/WebKit/LayoutTests/external/wpt/html/dom/historical.html
new file mode 100644
index 0000000..a36b4b2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/historical.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>Historical HTML APIs</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<applet name=war align=left></applet>
+<script>
+test(() => {
+  assert_array_equals(document.applets, []);
+}, "document.applets is always empty");
+
+test(() => {
+  const ap = document.getElementsByTagName("applet")[0];
+  assert_equals(self.HTMLAppletElement, undefined);
+  assert_true(ap instanceof window.HTMLUnknownElement);
+}, "HTMLAppletElement is no more")
+
+test(() => {
+  assert_equals(document.all.war, undefined);
+}, "document.all cannot find applet")
+
+test(() => {
+  assert_equals(document.war, undefined);
+}, "document cannot find applet")
+
+test(() => {
+  assert_equals(self.war, undefined);
+}, "window cannot find applet")
+
+test(() => {
+  assert_equals(self.getComputedStyle(document.getElementsByTagName("applet")[0], "").cssFloat, "none");
+}, "applet is not styled")
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
index fe3ab29..4c47c43 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 5323 tests; 5125 PASS, 198 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 5310 tests; 5126 PASS, 184 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver
 PASS Document interface: attribute domain
 PASS Document interface: attribute referrer
@@ -4877,7 +4877,7 @@
 PASS PromiseRejectionEvent interface object name
 PASS PromiseRejectionEvent interface: existence and properties of interface prototype object
 PASS PromiseRejectionEvent interface: existence and properties of interface prototype object's "constructor" property
-FAIL PromiseRejectionEvent interface: attribute promise Illegal invocation
+PASS PromiseRejectionEvent interface: attribute promise
 PASS PromiseRejectionEvent interface: attribute reason
 PASS Navigator interface: existence and properties of interface object
 PASS Navigator interface object length
@@ -5180,19 +5180,6 @@
 FAIL HTMLAppletElement interface: attribute object assert_own_property: self does not have own property "HTMLAppletElement" expected property "HTMLAppletElement" missing
 FAIL HTMLAppletElement interface: attribute vspace assert_own_property: self does not have own property "HTMLAppletElement" expected property "HTMLAppletElement" missing
 FAIL HTMLAppletElement interface: attribute width assert_own_property: self does not have own property "HTMLAppletElement" expected property "HTMLAppletElement" missing
-FAIL HTMLAppletElement must be primary interface of document.createElement("applet") assert_own_property: self does not have own property "HTMLAppletElement" expected property "HTMLAppletElement" missing
-FAIL Stringification of document.createElement("applet") assert_equals: class string of document.createElement("applet") expected "[object HTMLAppletElement]" but got "[object HTMLUnknownElement]"
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "align" with the proper type assert_inherits: property "align" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "alt" with the proper type assert_inherits: property "alt" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "archive" with the proper type assert_inherits: property "archive" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "code" with the proper type assert_inherits: property "code" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "codeBase" with the proper type assert_inherits: property "codeBase" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "height" with the proper type assert_inherits: property "height" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "hspace" with the proper type assert_inherits: property "hspace" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "name" with the proper type assert_inherits: property "name" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "object" with the proper type assert_inherits: property "object" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "vspace" with the proper type assert_inherits: property "vspace" not found in prototype chain
-FAIL HTMLAppletElement interface: document.createElement("applet") must inherit property "width" with the proper type assert_inherits: property "width" not found in prototype chain
 PASS HTMLMarqueeElement interface: existence and properties of interface object
 PASS HTMLMarqueeElement interface object length
 PASS HTMLMarqueeElement interface object name
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.html
index 8440615..6ce1516 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.html
@@ -204,7 +204,6 @@
     MessageEvent: ['new MessageEvent("message", { data: 5 })'],
     MessageChannel: [],
     MessagePort: [],
-    HTMLAppletElement: ['document.createElement("applet")'],
     HTMLMarqueeElement: ['document.createElement("marquee")'],
     HTMLFrameSetElement: ['document.createElement("frameset")'],
     HTMLFrameElement: ['document.createElement("frame")'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.worker-expected.txt
index 75a553a..18e170a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 589 tests; 540 PASS, 49 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 589 tests; 541 PASS, 48 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver
 PASS EventListener interface: existence and properties of interface object
 PASS NodeList interface: existence and properties of interface object
@@ -284,7 +284,7 @@
 PASS PromiseRejectionEvent interface object name
 PASS PromiseRejectionEvent interface: existence and properties of interface prototype object
 PASS PromiseRejectionEvent interface: existence and properties of interface prototype object's "constructor" property
-FAIL PromiseRejectionEvent interface: attribute promise Illegal invocation
+PASS PromiseRejectionEvent interface: attribute promise
 PASS PromiseRejectionEvent interface: attribute reason
 PASS Navigator interface: existence and properties of interface object
 PASS PluginArray interface: existence and properties of interface object
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_loop_base.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_loop_base.html
new file mode 100644
index 0000000..4917d9c3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_loop_base.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Audio Test: audio_loop_base</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-loop" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if audio.loop is set to true that expecting the seeking event is fired more than once" />
+    <meta name=timeout content=long>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <audio id="m" controls>The user agent doesn't support media element.</audio>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        var name = document.getElementsByName("assert")[0].content;
+        var t = async_test(name);
+
+        var looped = false;
+
+        function startTest() {
+            if (looped) {
+                t.step(function() {
+                    assert_true(true, "looped");
+                });
+                t.done();
+                media.pause();
+            }
+
+            looped = true;
+        }
+
+        media.addEventListener("seeking", startTest, false);
+        media.loop = true;
+        media.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/error-codes/error.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/error-codes/error.html
new file mode 100644
index 0000000..5123c68f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/error-codes/error.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<title>error</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id="log"></div>
+<script>
+function error_test(tagName, src) {
+  test(function() {
+    assert_equals(document.createElement(tagName).error, null);
+  }, tagName + '.error initial value');
+
+  async_test(function(t) {
+    var e = document.createElement(tagName);
+    e.src = src;
+    e.onloadeddata = t.step_func(function() {
+      assert_equals(e.error, null);
+      t.done();
+    });
+  }, tagName + '.error after successful load');
+
+  // TODO: MEDIA_ERR_ABORTED, MEDIA_ERR_NETWORK, MEDIA_ERR_DECODE
+
+  async_test(function(t) {
+    var e = document.createElement(tagName);
+    e.src = '';
+    e.onerror = t.step_func(function() {
+      assert_true(e.error instanceof MediaError);
+      assert_equals(e.error.code, 4);
+      assert_equals(e.error.code, e.error.MEDIA_ERR_SRC_NOT_SUPPORTED);
+      assert_equals(typeof e.error.message, 'string', 'error.message type');
+      t.done();
+    });
+  }, tagName + '.error after setting src to the empty string');
+}
+
+error_test('audio', getAudioURI('/media/sound_5'));
+error_test('video', getVideoURI('/media/movie_5'));
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplay.html
new file mode 100644
index 0000000..8e1b32d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplay.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - canplay</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger canplay event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("canplay", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - canplay");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger canplay event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("canplay", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - canplay");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplay_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplay_noautoplay.html
new file mode 100644
index 0000000..8f3372501
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplay_noautoplay.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - canplay</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function () {
+  var t = async_test("setting src attribute on non-autoplay audio should trigger canplay event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("canplay", function() {
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - canplay");
+
+test(function () {
+  var t = async_test("setting src attribute on non-autoplay video should trigger canplay event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("canplay", function() {
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - canplay");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough.html
new file mode 100644
index 0000000..827e796
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - canplaythrough</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger canplaythrough event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("canplaythrough", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - canplaythrough");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger canplaythrough event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("canplaythrough", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - canplaythrough");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough_noautoplay.html
new file mode 100644
index 0000000..75a70985
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_canplaythrough_noautoplay.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - canplaythrough</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay audio should trigger canplaythrough event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("canplaythrough", function() {
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - canplaythrough");
+
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay video should trigger canplaythrough event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("canplaythrough", function() {
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - canplaythrough");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata.html
new file mode 100644
index 0000000..f0e89c3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadeddata</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger loadeddata event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadeddata", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadeddata");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger loadeddata event", {timeout:5000});
+  var a = document.getElementById("v");
+  v.addEventListener("loadeddata", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - loadeddata");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html
new file mode 100644
index 0000000..0c81f33
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadeddata_noautoplay.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadeddata</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay audio should trigger loadeddata event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadeddata", function() {
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadeddata");
+
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay video should trigger loadeddata event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("loadeddata", function() {
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - loadeddata");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata.html
new file mode 100644
index 0000000..234121e5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadedmetadata</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger loadedmetadata event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadedmetadata", function() {
+    t.done();
+    a.pause();
+  });
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadedmetadata");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger loadedmetadata event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("loadedmetadata", function() {
+    t.done();
+    v.pause();
+  });
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - loadedmetadata");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html
new file mode 100644
index 0000000..382f3f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadedmetadata_noautoplay.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadedmetadata</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay audio should trigger loadedmetadata event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadedmetadata", function() {
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadedmetadata");
+
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay video should trigger loadedmetadata event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("loadedmetadata", function() {
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events, loadedmetadata");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadstart.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadstart.html
new file mode 100644
index 0000000..de456821
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadstart.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadstart</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger loadstart event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadstart", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadstart");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger loadstart event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("loadstart", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - loadstart");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadstart_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadstart_noautoplay.html
new file mode 100644
index 0000000..b575e7a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_loadstart_noautoplay.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadstart</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay audio should trigger loadstart event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadstart", function() {
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadstart");
+
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay video should trigger loadstart event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("loadstart", function() {
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - loadstart");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_canplaythrough.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_canplaythrough.html
new file mode 100644
index 0000000..a1e7e41
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_canplaythrough.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - canplay, then canplaythrough</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger canplay then canplaythrough event", {timeout:5000});
+  var a = document.getElementById("a");
+  var found_canplay = false;
+  a.addEventListener("canplay", function() {
+    found_canplay = true;
+  });
+  a.addEventListener("canplaythrough", function() {
+    t.step(function() {
+     assert_true(found_canplay);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - canplay, then canplaythrough");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger canplay then canplaythrough event", {timeout:5000});
+  var v = document.getElementById("v");
+  var found_canplay = false;
+  v.addEventListener("canplay", function() {
+    found_canplay = true;
+  });
+  v.addEventListener("canplaythrough", function() {
+    t.step(function() {
+     assert_true(found_canplay);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - canplay, then canplaythrough");
+ </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_playing.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_playing.html
new file mode 100644
index 0000000..a5a67dd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_canplay_playing.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - canplay, then playing</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger canplay then playing event", {timeout:5000});
+  var a = document.getElementById("a");
+  var found_canplay = false;
+  a.addEventListener("canplay", function() {
+    found_canplay = true;
+  });
+  a.addEventListener("playing", function() {
+    t.step(function() {
+     assert_true(found_canplay);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - canplay, then playing");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger canplay then playing event", {timeout:5000});
+  var v = document.getElementById("v");
+  var found_canplay = false;
+  v.addEventListener("canplay", function() {
+    found_canplay = true;
+  });
+  v.addEventListener("playing", function() {
+    t.step(function() {
+     assert_true(found_canplay);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - canplay, then playing");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html
new file mode 100644
index 0000000..3aba368
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_loadedmetadata_loadeddata.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadedmetadata, then loadeddata</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger loadedmetadata then loadeddata event", {timeout:5000});
+  var a = document.getElementById("a");
+  var found_loadedmetadata = false;
+  a.addEventListener("loadedmetadata", function() {
+    found_loadedmetadata = true;
+  });
+  a.addEventListener("loadeddata", function() {
+    t.step(function() {
+     assert_true(found_loadedmetadata);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadedmetadata, then loadeddata");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger loadedmetadata then loadeddata event", {timeout:5000});
+  var v = document.getElementById("v");
+  var found_loadedmetadata = false;
+  v.addEventListener("loadedmetadata", function() {
+    found_loadedmetadata = true;
+  });
+  v.addEventListener("loadeddata", function() {
+    t.step(function() {
+     assert_true(found_loadedmetadata);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - loadedmetadata, then loadeddata");
+ </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_loadstart_progress.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_loadstart_progress.html
new file mode 100644
index 0000000..75e3ba77
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_order_loadstart_progress.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - loadstart, then progress</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger loadstart then progress event", {timeout:5000});
+  var a = document.getElementById("a");
+  var found_loadstart = false;
+  a.addEventListener("loadstart", function() {
+    found_loadstart = true;
+  });
+  a.addEventListener("progress", function() {
+    t.step(function() {
+     assert_true(found_loadstart);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - loadstart, then progress");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger loadstart then progress event", {timeout:5000});
+  var v = document.getElementById("v");
+  var found_loadstart = false;
+  v.addEventListener("loadstart", function() {
+    found_loadstart = true;
+  });
+  v.addEventListener("progress", function() {
+    t.step(function() {
+     assert_true(found_loadstart);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - loadstart, then progress");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause.html
new file mode 100644
index 0000000..1f7904c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - pause</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("calling pause() on autoplay audio should trigger pause event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("pause", function() {
+    t.step(function() {
+     assert_true(true);
+    });
+    t.done();
+  }, false);
+  a.addEventListener("play", function() {
+    a.pause(); // pause right after play
+  });
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - pause");
+
+test(function() {
+  var t = async_test("calling pause() on autoplay video should trigger pause event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("pause", function() {
+    t.step(function() {
+     assert_true(true);
+    });
+    t.done();
+  }, false);
+  v.addEventListener("play", function() {
+    v.pause(); // pause right after play
+  });
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - pause");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause_noautoplay-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause_noautoplay-expected.txt
new file mode 100644
index 0000000..e4dd682
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause_noautoplay-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = The play() request was interrupted by a call to pause(). https://goo.gl/LdLk22
+PASS audio events - pause
+PASS calling play() then pause() on non-autoplay audio should trigger pause event
+PASS video events - pause
+PASS calling play() then pause() on non-autoplay video should trigger pause event
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause_noautoplay.html
new file mode 100644
index 0000000..5548234
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_pause_noautoplay.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - pause</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("calling play() then pause() on non-autoplay audio should trigger pause event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("pause", function() {
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+  a.play();
+  a.pause();
+}, "audio events - pause");
+
+test(function() {
+  var t = async_test("calling play() then pause() on non-autoplay video should trigger pause event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("pause", function() {
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  v.play();
+  v.pause();
+}, "video events - pause");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play.html
new file mode 100644
index 0000000..82b2ca4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - play</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger play event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("play", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - play");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger play event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("play", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - play");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play_noautoplay-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play_noautoplay-expected.txt
new file mode 100644
index 0000000..5a6b7f16
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play_noautoplay-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = The play() request was interrupted by a call to pause(). https://goo.gl/LdLk22
+PASS audio events - play
+PASS calling play() on audio should trigger play event
+PASS video events - play
+PASS calling play() on video should trigger play event
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play_noautoplay.html
new file mode 100644
index 0000000..67285a95
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_play_noautoplay.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - play</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("calling play() on audio should trigger play event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("play", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+  a.play();
+}, "audio events - play");
+
+test(function() {
+  var t = async_test("calling play() on video should trigger play event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("play", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  v.play();
+}, "video events - play");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_playing.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_playing.html
new file mode 100644
index 0000000..3741a1c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_playing.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - playing</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger playing event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("playing", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - playing");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger playing event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("playing", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - playing");
+ </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_playing_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_playing_noautoplay.html
new file mode 100644
index 0000000..f750085e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_playing_noautoplay.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - playing</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("calling play() on audio should trigger playing event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("playing", function() {
+    t.done();
+    a.pause();
+  });
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+  a.play();
+}, "audio events - playing");
+
+test(function() {
+  var t = async_test("calling play() on video should trigger playing event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("playing", function() {
+    t.done();
+    v.pause();
+  });
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  v.play();
+}, "video events - playing");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_progress.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_progress.html
new file mode 100644
index 0000000..269f824
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_progress.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - progress</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on autoplay audio should trigger progress event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("progress", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - progress");
+
+test(function() {
+  var t = async_test("setting src attribute on autoplay video should trigger progress event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("progress", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - progress");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_progress_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_progress_noautoplay.html
new file mode 100644
index 0000000..c594f30
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_progress_noautoplay.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - progress</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay audio should trigger progress event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("progress", function() {
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - progress");
+
+test(function() {
+  var t = async_test("setting src attribute on non-autoplay video should trigger progress event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("progress", function() {
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - progress");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate.html
new file mode 100644
index 0000000..cc0a17f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - timeupdate</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+var ta = async_test("setting src attribute on a sufficiently long autoplay audio should trigger timeupdate event", {timeout:5000});
+var a = document.getElementById("a");
+a.addEventListener("timeupdate", function() {
+  ta.done();
+  a.pause();
+}, false);
+a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+
+var tv = async_test("setting src attribute on a sufficiently long autoplay video should trigger timeupdate event", {timeout:5000});
+var v = document.getElementById("v");
+v.addEventListener("timeupdate", function() {
+  tv.done();
+  v.pause();
+}, false);
+v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate_noautoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate_noautoplay.html
new file mode 100644
index 0000000..feb4b85
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/event_timeupdate_noautoplay.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - timeupdate</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("calling play() on a sufficiently long audio should trigger timeupdate event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("timeupdate", function() {
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+  a.play();
+}, "audio events - timeupdate");
+
+test(function() {
+  var t = async_test("calling play() on a sufficiently long video should trigger timeupdate event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("timeupdate", function() {
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  v.play();
+}, "video events - timeupdate");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues-expected.txt
new file mode 100644
index 0000000..0886fd3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL TextTrack.activeCues, empty list assert_not_equals: t1.activeCues and t2.activeCues should be different objects got disallowed value null
+FAIL TextTrack.activeCues, after addCue() assert_equals: t1.activeCues should return same object expected null but got object "[object TextTrackCueList]"
+FAIL TextTrack.activeCues, different modes assert_equals: t1.activeCues should return the same object after setting mode to showing expected null but got object "[object TextTrackCueList]"
+FAIL TextTrack.activeCues, video loading assert_equals: t1.activeCues should return the same object after loading a video expected null but got object "[object TextTrackCueList]"
+FAIL TextTrack.activeCues, video playing assert_unreached: Reached unreachable code
+FAIL TextTrack.activeCues, adding cue during playback assert_unreached: Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues.html
new file mode 100644
index 0000000..689ec12
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/activeCues.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<title>TextTrack.activeCues</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/media.js></script>
+<div id=log></div>
+<script>
+setup(function(){
+    window.video = document.createElement('video');
+    window.t1 = video.addTextTrack('subtitles');
+    window.track = document.createElement('track');
+    track['default'] = true;
+    video.appendChild(track);
+    window.t2 = track.track;
+    t2.mode = 'showing';
+    window.t1_cues = t1.activeCues;
+    window.t2_cues = t2.activeCues;
+    document.body.appendChild(video);
+    if (!t1)
+        throw new Error('t1 was undefined')
+}, {timeout:25000});
+function smoke_test() {
+  assert_true('HTMLTrackElement' in window, 'track not supported');
+}
+
+test(function(){
+    smoke_test();
+    assert_equals(t1.activeCues, t1_cues, 't1.activeCues should return same object');
+    assert_equals(t2.activeCues, t2_cues, 't2.activeCues should return same object');
+    assert_not_equals(t1.activeCues, t2.activeCues, 't1.activeCues and t2.activeCues should be different objects');
+    assert_not_equals(t1.activeCues, null, 't1.activeCues should not be null');
+    assert_not_equals(t2.activeCues, null, 't2.activeCues should not be null');
+    assert_equals(t1.activeCues.length, 0, 't1.activeCues should have length 0');
+    assert_equals(t2.activeCues.length, 0, 't2.activeCues should have length 0');
+}, document.title+', empty list');
+test(function(){
+    smoke_test();
+    var c = new VTTCue(0, 1, "text");
+    t1.addCue(c);
+    assert_equals(t1.activeCues, t1_cues, "t1.activeCues should return same object");
+    assert_equals(t1.activeCues.length, 0, "t1.activeCues.length");
+    var c2 = new VTTCue(1, 2, "text2");
+    t1.addCue(c2);
+    assert_equals(t1.activeCues, t1_cues, "t1.activeCues should return the same object after adding a second cue");
+    assert_equals(t1.activeCues.length, 0, "t1.activeCues.length after adding a second cue");
+}, document.title+', after addCue()');
+test(function(){
+    smoke_test();
+    t1.mode = 'showing';
+    assert_equals(t1.activeCues, t1_cues, "t1.activeCues should return the same object after setting mode to showing");
+    t1.mode = 'hidden';
+    assert_equals(t1.activeCues, t1_cues, "t1.activeCues should return the same object after setting mode to hidden");
+    t1.mode = 'disabled';
+    assert_equals(t1.activeCues, null, "t1.activeCues should be null when mode is disabled");
+    assert_equals(t1_cues.length, 0, "t1_cues should still be intact after setting mode to disabled");
+}, document.title+', different modes');
+
+// ok now let's load in a video
+var test1 = async_test(document.title+', video loading', {timeout:20000});
+var test2 = async_test(document.title+', video playing', {timeout:20000});
+var test3 = async_test(document.title+', adding cue during playback', {timeout:20000});
+test1.step(smoke_test);
+test2.step(smoke_test);
+test3.step(smoke_test);
+test1.step(function(){
+    t1.mode = 'showing';
+    video.onloadeddata = test1.step_func(function(e) {
+        video.onplaying = test2.step_func(function(e) {
+            try {
+                assert_equals(t1.activeCues, t1_cues, "t1.activeCues should return the same object after playing a video");
+                assert_equals(t1.activeCues.length, 1, "t1.activeCues.length after the video has started playing");
+            } catch(ex) {
+                test2.step(function() { throw ex; });
+                test3.step(function() { assert_unreached(); });
+                return;
+            }
+            test3.step(function(){
+                var c3 = new VTTCue(0, 2, "text3");
+                t1.addCue(c3);
+                assert_equals(t1.activeCues.length, 1, "t1.activeCues.length after adding a cue in the same script");
+                setTimeout(test3.step_func(function(){
+                    assert_equals(t1.activeCues.length, 2, "t1.activeCues.length after the event loop has spun");
+                    test3.done();
+                }, 0));
+            });
+            test2.done();
+        });
+        try {
+            assert_equals(t1.activeCues, t1_cues, "t1.activeCues should return the same object after loading a video");
+            assert_equals(t2.activeCues, t2_cues, "t2.activeCues should return the same object after loading a video");
+            assert_equals(t1.activeCues.length, 0, "t1.activeCues.length before the video has started playing");
+            assert_equals(t2.activeCues.length, 0, "t1.activeCues.length before the video has started playing");
+        } catch(ex) {
+            test1.step(function() { throw ex; });
+            test2.step(function() { assert_unreached(); });
+            test3.step(function() { assert_unreached(); });
+            return;
+        }
+        video.play();
+        test1.done();
+    });
+    video.src = getVideoURI("/media/movie_5");
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/autoplay-overrides-preload.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/autoplay-overrides-preload.html
new file mode 100644
index 0000000..91103c5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/autoplay-overrides-preload.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<title>autoplay overrides preload</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id=log></div>
+<script>
+['none', 'metadata'].forEach(function(preload) {
+  ['first', 'last'].forEach(function(order) {
+    async_test(function(t) {
+      var a = document.createElement('audio');
+      a.src = getAudioURI('/media/sound_5');
+      if (order == 'first') {
+        a.autoplay = true;
+        a.preload = preload;
+      } else {
+        a.preload = preload;
+        a.autoplay = true;
+      }
+      a.addEventListener('playing', t.step_func(function() {
+        assert_equals(a.readyState, a.HAVE_ENOUGH_DATA);
+        assert_false(a.paused);
+        t.done();
+      }));
+    }, 'autoplay (set ' + order + ') overrides preload "' + preload + '"');
+  });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html
new file mode 100644
index 0000000..8c12011e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<title>load() fires abort/emptied events when networkState is not NETWORK_EMPTY</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id=log></div>
+<script>
+function load_test(t, v) {
+  assert_not_equals(v.networkState, v.NETWORK_EMPTY);
+
+  var expected_events = [];
+  if (v.networkState == v.NETWORK_LOADING || v.networkState == v.NETWORK_IDLE) {
+    expected_events.push('abort');
+  }
+  if (v.networkState != v.NETWORK_EMPTY) {
+    expected_events.push('emptied');
+  }
+
+  var actual_events = [];
+  v.onabort = v.onemptied = t.step_func(function(e) {
+    actual_events.push(e.type);
+  });
+
+  v.onloadstart = t.step_func(function() {
+    assert_array_equals(actual_events, expected_events);
+    t.done();
+  });
+
+  v.load();
+
+  assert_array_equals(actual_events, [], 'events should be fired in queued tasks');
+}
+
+async_test(function(t) {
+  var v = document.createElement('video');
+  // suspend is fired optionally "if the user agent intends to not attempt to
+  // fetch the resource" or "once the entire media resource has been fetched"
+  v.preload = 'none';
+  v.src = getAudioURI('/media/sound_5');
+  v.onsuspend = t.step_func(function() {
+    v.onsuspend = null;
+    assert_equals(v.networkState, v.NETWORK_IDLE);
+    load_test(t, v);
+  });
+}, 'NETWORK_IDLE');
+
+async_test(function(t) {
+  var v = document.createElement('video');
+  v.src = 'resources/delayed-broken-video.py';
+  v.onloadstart = t.step_func(function() {
+    v.onloadstart = null;
+    assert_equals(v.networkState, v.NETWORK_LOADING);
+    load_test(t, v);
+  });
+}, 'NETWORK_LOADING');
+
+async_test(function(t) {
+  var v = document.createElement('video');
+  v.src = 'data:,';
+  v.onerror = t.step_func(function() {
+    v.onerror = null;
+    assert_equals(v.networkState, v.NETWORK_NO_SOURCE);
+    load_test(t, v);
+  });
+  assert_equals(v.networkState, v.NETWORK_NO_SOURCE);
+}, 'NETWORK_NO_SOURCE');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_loadstart.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_loadstart.html
new file mode 100644
index 0000000..8f0fffc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_loadstart.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video}.networkState - NETWORK_LOADING</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#dom-media-networkstate">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+var ta = async_test("audioElement.networkState should be NETWORK_LOADING during loadstart event", {timeout:5000});
+var a = document.getElementById("a");
+a.addEventListener("loadstart", function() {
+  ta.step(function() {
+   assert_equals(a.networkState,
+   a.NETWORK_LOADING);
+  });
+  ta.done();
+  a.pause();
+}, false);
+a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+
+var tv = async_test("videoElement.networkState should be NETWORK_LOADING during loadstart event", {timeout:5000});
+var v = document.getElementById("v");
+v.addEventListener("loadstart", function() {
+  tv.step(function() {
+   assert_equals(a.networkState,
+   v.NETWORK_LOADING);
+  });
+  tv.done();
+  v.pause();
+}, false);
+v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_progress-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_progress-expected.txt
new file mode 100644
index 0000000..3dbc872
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_progress-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL audioElement.networkState should be NETWORK_LOADING during progress event assert_equals: expected 2 but got 1
+FAIL videoElement.networkState should be NETWORK_LOADING during progress event assert_equals: expected 2 but got 1
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_progress.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_progress.html
new file mode 100644
index 0000000..cf23e82
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/networkState_during_progress.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video}.networkState - NETWORK_LOADING</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#dom-media-networkstate">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+var ta = async_test("audioElement.networkState should be NETWORK_LOADING during progress event", {timeout:5000});
+var a = document.getElementById("a");
+a.addEventListener("progress", function() {
+  ta.step(function() {
+   assert_equals(a.networkState,
+   a.NETWORK_LOADING);
+  });
+  ta.done();
+  a.pause();
+}, false);
+a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+
+var tv = async_test("videoElement.networkState should be NETWORK_LOADING during progress event", {timeout:5000});
+var v = document.getElementById("v");
+v.addEventListener("progress", function() {
+  tv.step(function() {
+   assert_equals(v.networkState,
+   v.NETWORK_LOADING);
+  });
+  tv.done();
+  v.pause();
+}, false);
+v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html
new file mode 100644
index 0000000..e9b6589
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>currentTime</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id=log></div>
+<script>
+test(function() {
+  var v = document.createElement('video');
+  assert_equals(v.currentTime, 0);
+}, 'currentTime initial value');
+
+test(function() {
+  var v = document.createElement('video');
+  assert_equals(v.readyState, v.HAVE_NOTHING);
+  v.currentTime = Number.MAX_VALUE;
+  assert_equals(v.currentTime, Number.MAX_VALUE);
+  assert_false(v.seeking);
+}, 'setting currentTime when readyState is HAVE_NOTHING');
+
+async_test(function(t) {
+  var v = document.createElement('video');
+  v.src = getVideoURI('/media/movie_5');
+  v.onloadedmetadata = t.step_func(function() {
+    assert_greater_than(v.readyState, v.HAVE_NOTHING);
+    assert_false(v.seeking);
+    v.currentTime = 1;
+    assert_true(v.seeking);
+    t.done();
+  });
+}, 'setting currentTime when readyState is greater than HAVE_NOTHING');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_false_during_play.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_false_during_play.html
new file mode 100644
index 0000000..28c5633
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_false_during_play.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - paused property</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("audio.paused should be false during play event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("play", function() {
+    t.step(function() {
+     assert_false(a.paused);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - paused property");
+
+test(function() {
+  var t = async_test("video.paused should be false during play event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("play", function() {
+    t.step(function() {
+     assert_false(v.paused);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - paused property");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_true_during_pause-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_true_during_pause-expected.txt
new file mode 100644
index 0000000..6a6aa9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_true_during_pause-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = The play() request was interrupted by a call to pause(). https://goo.gl/LdLk22
+PASS audio events - paused property
+PASS audio.paused should be true during pause event
+PASS video events - paused property
+PASS video.paused should be true during pause event
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_true_during_pause.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_true_during_pause.html
new file mode 100644
index 0000000..6c4eb7c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/paused_true_during_pause.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - paused property</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" controls>
+  </audio>
+  <video id="v" controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("audio.paused should be true during pause event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("pause", function() {
+    t.step(function() {
+     assert_true(a.paused);
+    });
+    t.done();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+  a.play();
+  a.pause();
+}, "audio events - paused property");
+
+test(function() {
+  var t = async_test("video.paused should be true during pause event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("pause", function() {
+    t.step(function() {
+     assert_true(v.paused);
+    });
+    t.done();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+  v.play();
+  v.pause();
+}, "video events - paused property");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document-expected.txt
new file mode 100644
index 0000000..aa9a81c3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL paused state when moving to other document assert_false: paused after moving expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html
new file mode 100644
index 0000000..342771d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-to-other-document.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>paused state when moving to other document</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id="log"></div>
+<video hidden></video>
+<iframe hidden></iframe>
+<script>
+async_test(function(t) {
+  var v = document.querySelector('video');
+  v.src = getVideoURI('/media/movie_300');
+  v.play();
+  v.onplaying = t.step_func(function() {
+    assert_false(v.paused, 'paused after playing');
+    document.querySelector('iframe').contentDocument.body.appendChild(v);
+    assert_false(v.paused, 'paused after moving');
+    setTimeout(t.step_func(function() {
+      assert_false(v.paused, 'paused after stable state')
+      t.done();
+    }), 0);
+  });
+  v.onpause = t.step_func(function() { assert_unreached(); });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document-expected.txt
new file mode 100644
index 0000000..915f171
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL paused state when moving within a document assert_false: paused after moving expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document.html
new file mode 100644
index 0000000..a28322d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-move-within-document.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>paused state when moving within a document</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id="log"></div>
+<video hidden></video>
+<div id="elsewhere"></div>
+<script>
+async_test(function(t) {
+  var v = document.querySelector('video');
+  v.src = getVideoURI('/media/movie_300');
+  v.play();
+  v.onplaying = t.step_func(function() {
+    assert_false(v.paused, 'paused after playing');
+    document.getElementById('elsewhere').appendChild(v);
+    assert_false(v.paused, 'paused after moving');
+    setTimeout(t.step_func(function() {
+      assert_false(v.paused, 'paused after stable state')
+      t.done();
+    }), 0);
+  });
+  v.onpause = t.step_func(function() { assert_unreached(); });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-expected.txt
new file mode 100644
index 0000000..946bc05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL paused state when removing from a document assert_false: paused after removing expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html
new file mode 100644
index 0000000..7a4b0bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>paused state when removing from a document</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id="log"></div>
+<video hidden></video>
+<script>
+function afterStableState(func) {
+  var a = new Audio();
+  a.volume = 0;
+  a.addEventListener('volumechange', func);
+}
+
+async_test(function(t) {
+  var v = document.querySelector('video');
+  v.src = getVideoURI('/media/movie_300');
+  v.play();
+  v.onplaying = t.step_func(function() {
+    assert_false(v.paused, 'paused after playing');
+    v.parentNode.removeChild(v);
+    assert_false(v.paused, 'paused after removing');
+    afterStableState(t.step_func(function() {
+      assert_true(v.paused, 'paused after stable state');
+      v.onpause = t.step_func(function() {
+        assert_true(v.paused, 'paused in pause event');
+        // re-insert and verify that it stays paused
+        document.body.appendChild(v);
+        setTimeout(t.step_func(function() {
+          assert_true(v.paused, 'paused after re-inserting');
+          t.done();
+        }), 0);
+      });
+    }));
+  });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document-expected.txt
new file mode 100644
index 0000000..08960a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL play() in detached document assert_false: expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html
new file mode 100644
index 0000000..9c6fd5f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/play-in-detached-document.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>play() in detached document</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id="log"></div>
+<script>
+// Negative test for failure to play in a detached document.
+async_test(function(t)
+{
+  var doc = document.implementation.createHTMLDocument("");
+  var v = doc.createElement("video");
+  doc.body.appendChild(v);
+  v.src = getVideoURI("/media/movie_5");
+  v.play();
+  v.addEventListener("timeupdate", t.step_func(function() {
+    assert_false(v.paused);
+    if (v.currentTime > 0) {
+      t.done();
+    }
+  }));
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay.html
new file mode 100644
index 0000000..76aef1dbc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<title>autoplay</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id="log"></div>
+<script>
+function autoplay_test(tagName, src) {
+  function expect_events(t, e, expected_events) {
+    var actual_events = [];
+    var callback = t.step_func(function(ev) {
+      actual_events.push(ev.type);
+      assert_array_equals(actual_events,
+                          expected_events.slice(0, actual_events.length));
+      if (expected_events.length == actual_events.length) {
+        t.done();
+      }
+    });
+    ['canplay', 'canplaythrough',
+     'pause', 'play', 'playing'].forEach(function(type) {
+      e.addEventListener(type, callback);
+    });
+  }
+
+  async_test(function(t) {
+    var e = document.createElement(tagName);
+    e.src = src;
+    e.autoplay = true;
+    expect_events(t, e, ['canplay', 'play', 'playing', 'canplaythrough']);
+  }, tagName + '.autoplay');
+
+  async_test(function(t) {
+    var e = document.createElement(tagName);
+    e.src = src;
+    e.autoplay = true;
+    e.pause(); // sets the autoplaying flag to false
+    e.load(); // sets the autoplaying flag to true
+    expect_events(t, e, ['canplay', 'play', 'playing', 'canplaythrough']);
+  }, tagName + '.autoplay and load()');
+
+  async_test(function(t) {
+    var e = document.createElement(tagName);
+    e.src = src;
+    e.autoplay = true;
+    e.play(); // sets the autoplaying flag to false
+    // play() also sets the paused attribute to false; there is no way for the
+    // autoplaying flag to be true when the paused attribute is false.
+    assert_equals(e.paused, false);
+    expect_events(t, e, ['play', 'canplay', 'playing', 'canplaythrough']);
+  }, tagName + '.autoplay and play()');
+
+  async_test(function(t) {
+    var e = document.createElement(tagName);
+    e.src = src;
+    e.autoplay = true;
+    e.pause(); // sets the autoplaying flag to false
+    expect_events(t, e, ['canplay', 'canplaythrough']);
+  }, tagName + '.autoplay and pause()');
+
+  async_test(function(t) {
+    var e = document.createElement(tagName);
+    e.src = src;
+    e.autoplay = true;
+    document.body.appendChild(e);
+    document.body.removeChild(e);
+    // in stable state, internal pause steps sets the autoplaying flag to false
+    expect_events(t, e, ['canplay', 'canplaythrough']);
+  }, tagName + '.autoplay and internal pause steps');
+}
+
+autoplay_test('audio', getAudioURI('/media/sound_5'));
+autoplay_test('video', getVideoURI('/media/movie_5'));
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplay.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplay.html
new file mode 100644
index 0000000..09ad89f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplay.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - readyState property during canplay</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("audio.readyState should be >= HAVE_FUTURE_DATA during canplay event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("canplay", function() {
+    t.step(function() {
+     assert_greater_than_equal(a.readyState, a.HAVE_FUTURE_DATA);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - readyState property during canplay");
+
+test(function() {
+  var t = async_test("video.readyState should be >= HAVE_FUTURE_DATA during canplay event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("canplay", function() {
+    t.step(function() {
+     assert_greater_than_equal(v.readyState, v.HAVE_FUTURE_DATA);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - readyState property during canplay");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplaythrough.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplaythrough.html
new file mode 100644
index 0000000..7ef7b5f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_canplaythrough.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - readyState property during canplaythrough</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("audio.readyState should be HAVE_ENOUGH_DATA during canplaythrough event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("canplaythrough", function() {
+    t.step(function() {
+     assert_equals(a.readyState,
+      a.HAVE_ENOUGH_DATA);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - readyState property during canplaythrough");
+
+test(function() {
+  var t = async_test("video.readyState should be HAVE_ENOUGH_DATA during canplaythrough event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("canplaythrough", function() {
+    t.step(function() {
+     assert_equals(v.readyState,
+      v.HAVE_ENOUGH_DATA);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - readyState property during canplaythrough");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html
new file mode 100644
index 0000000..1de85eb8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadeddata.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - readyState property during loadeddata</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("audio.readyState should be >= HAVE_CURRENT_DATA during loadeddata event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadeddata", function() {
+    t.step(function() {
+     assert_greater_than_equal(a.readyState, a.HAVE_CURRENT_DATA);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - readyState property during loadeddata");
+
+test(function() {
+  var t = async_test("video.readyState should be >= HAVE_CURRENT_DATA during loadeddata event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("loadeddata", function() {
+    t.step(function() {
+     assert_greater_than_equal(v.readyState, v.HAVE_CURRENT_DATA);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - readyState property during loadeddata");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html
new file mode 100644
index 0000000..85db8af
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_loadedmetadata.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - readyState property during loadedmetadata</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("audio.readyState should be >= HAVE_METADATA during loadedmetadata event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("loadedmetadata", function() {
+    t.step(function() {
+     assert_greater_than_equal(a.readyState, a.HAVE_METADATA);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - readyState property during loadedmetadata");
+
+test(function() {
+  var t = async_test("video.readyState should be >= HAVE_METADATA during loadedmetadata event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("loadedmetadata", function() {
+    t.step(function() {
+     assert_greater_than_equal(v.readyState, v.HAVE_METADATA);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - readyState property during loadedmetadata");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_playing.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_playing.html
new file mode 100644
index 0000000..92a1b7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/readyState_during_playing.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<html>
+ <head>
+  <title>{audio,video} events - readyState property during playing</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/common/media.js"></script>
+ </head>
+ <body>
+  <p><a href="https://html.spec.whatwg.org/multipage/#mediaevents">spec reference</a></p>
+  <audio id="a" autoplay controls>
+  </audio>
+  <video id="v" autoplay controls>
+  </video>
+  <div id="log"></div>
+  <script>
+test(function() {
+  var t = async_test("audio.readyState should be >= HAVE_FUTURE_DATA during playing event", {timeout:5000});
+  var a = document.getElementById("a");
+  a.addEventListener("playing", function() {
+    t.step(function() {
+     assert_greater_than_equal(a.readyState, a.HAVE_FUTURE_DATA);
+    });
+    t.done();
+    a.pause();
+  }, false);
+  a.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+}, "audio events - readyState property during playing");
+
+test(function() {
+  var t = async_test("video.readyState should be >= HAVE_FUTURE_DATA during playing event", {timeout:5000});
+  var v = document.getElementById("v");
+  v.addEventListener("playing", function() {
+    t.step(function() {
+     assert_greater_than_equal(v.readyState, v.HAVE_FUTURE_DATA);
+    });
+    t.done();
+    v.pause();
+  }, false);
+  v.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+}, "video events - readyState property during playing");
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html
new file mode 100644
index 0000000..3d577dac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>seek to currentTime</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+  var v = document.createElement('video');
+  v.src = getVideoURI('/media/movie_5');
+  v.onloadedmetadata = t.step_func(function() {
+    assert_greater_than(v.readyState, v.HAVE_NOTHING, 'readyState');
+    assert_greater_than(v.seekable.length, 0, 'seekable ranges');
+    assert_false(v.seeking, 'seeking before setting currentTime');
+    v.currentTime = v.currentTime;
+    assert_true(v.seeking, 'seeking after setting currentTime');
+    var events = [];
+    v.onseeking = v.ontimeupdate = v.onseeked = t.step_func(function(e) {
+      events.push(e.type);
+      // v.seeking can be true or false in the seeking event, see
+      // https://www.w3.org/Bugs/Public/show_bug.cgi?id=24774
+      if (e.type != 'seeking') {
+        assert_equals(v.seeking, false, 'seeking in ' + e.type + ' event');
+      }
+      if (e.type == 'seeked') {
+        assert_array_equals(events, ['seeking', 'timeupdate', 'seeked'],
+                            'fired events');
+        t.done();
+      }
+    });
+  });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm
new file mode 100644
index 0000000..a31f6c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>seek to Number.MAX_VALUE</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+  var v = document.createElement('video');
+  v.src = getVideoURI('/media/movie_5');
+  v.onloadedmetadata = t.step_func(function() {
+    assert_equals(v.seekable.length, 1);
+    v.currentTime = Number.MAX_VALUE;
+    assert_true(v.seeking, 'seeking after setting');
+    assert_equals(v.currentTime, v.seekable.end(0), 'currentTime after setting');
+    v.onseeked = t.step_func(function(e) {
+      assert_false(v.seeking, 'seeking in seeked event');
+      assert_equals(v.currentTime, v.seekable.end(0), 'currentTime in seeked event');
+      t.done();
+    });
+  });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm
new file mode 100644
index 0000000..56a9902
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>seek to negative time</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+  var v = document.createElement('video');
+  v.src = getVideoURI('/media/movie_5');
+  v.onloadedmetadata = t.step_func(function() {
+    assert_equals(v.seekable.start(0), 0, 'earliest seekable time');
+    v.currentTime = -1;
+    assert_true(v.seeking, 'seeking after setting');
+    assert_equals(v.currentTime, 0, 'currentTime after setting');
+    v.onseeked = t.step_func(function(e) {
+      assert_false(v.seeking, 'seeking in seeked event');
+      assert_equals(v.currentTime, 0, 'currentTime in seeked event');
+      t.done();
+    });
+  });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html
new file mode 100644
index 0000000..b2840d2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Track element - text tracks API test</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#text-track-api">
+<link rel="author" title="Hyunjin Cho">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<h1>Track element and API Test</h1>
+<div style="display:none;">
+    <video id="tracktest" src="/media/movie_300.mp4">
+        <track kind="subtitles" src="resources/track.en.vtt" srclang="en" label="English">
+        <track kind="captions" src="resources/track.en.vtt" srclang="en" label="English with Captions">
+        <track id="french" kind="subtitles" src="resources/track.fr.vtt" srclang="fr" label="Francais">
+        <track kind="subtitles" src="resources/track.de.vtt" srclang="de" label="Deutsch">
+    </video>
+</div>
+<div id="log"></div>
+<script>
+test(function() {
+    var t1 = document.getElementById('tracktest').textTracks;
+    assert_not_equals(t1, undefined, "textTracks member should not be undefined");
+}, "Check the track elements");
+test(function() {
+    var t2 = document.getElementById('tracktest').textTracks.getTrackById("french");
+    assert_not_equals(t2, undefined, "textTracks member should not be undefined");
+}, "Check getTrackById method");
+test(function() {
+    var t3 = document.getElementById('tracktest').textTracks.length;
+    assert_equals(t3, 4, "textTracks List should be 4");
+}, "Count track list");
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order-expected.txt
new file mode 100644
index 0000000..7f91f9d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS Text track cue order, decreasing start times.
+PASS Text track cue order, equal start times varying end times.
+PASS Text track cue order, equal start and end times.
+PASS Text track cue order, after re-insertion.
+FAIL Text track cue order, equal start and end times with startTime mutations. assert_equals: "1" moved first expected "123" but got "231"
+PASS Text track cue order, equal start and end times with endTime mutations.
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html
new file mode 100644
index 0000000..58e11eb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<title>Text track cue order</title>
+<link rel="help" href="https://html.spec.whatwg.org/#text-track-cue-order">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+function concat_cuetext(cues) {
+    return Array.prototype.reduce.call(cues, function(acc, value) {
+        return acc + value.text;
+    }, "");
+}
+
+setup(function() {
+    window.video = document.createElement('video');
+});
+
+test(function() {
+    let track = video.addTextTrack('subtitles');
+    track.addCue(new VTTCue(8, 9, '1'));
+    track.addCue(new VTTCue(4, 5, '2'));
+    track.addCue(new VTTCue(2, 3, '3'));
+    assert_equals(concat_cuetext(track.cues), '321');
+}, document.title + ', decreasing start times.');
+
+test(function() {
+    let track = video.addTextTrack('subtitles');
+    track.addCue(new VTTCue(2, 9, '1'));
+    track.addCue(new VTTCue(2, 3, '2'));
+    track.addCue(new VTTCue(2, 5, '3'));
+    assert_equals(concat_cuetext(track.cues), '132');
+}, document.title + ', equal start times varying end times.');
+
+test(function() {
+    let track = video.addTextTrack('subtitles');
+    track.addCue(new VTTCue(2, 3, '1'));
+    track.addCue(new VTTCue(2, 3, '2'));
+    track.addCue(new VTTCue(2, 3, '3'));
+    assert_equals(concat_cuetext(track.cues), '123');
+}, document.title + ', equal start and end times.');
+
+test(function() {
+    let track = video.addTextTrack('subtitles');
+    track.addCue(new VTTCue(2, 5, '1'));
+    track.addCue(new VTTCue(2, 5, '2'));
+    track.addCue(new VTTCue(2, 5, '3'));
+    assert_equals(concat_cuetext(track.cues), '123', 'initial order');
+
+    let cue = track.cues[0];
+    track.removeCue(cue);
+    assert_equals(concat_cuetext(track.cues), '23', '"1" removed');
+
+    track.addCue(cue);
+    assert_equals(concat_cuetext(track.cues), '231', '"1" reinserted');
+}, document.title + ', after re-insertion.');
+
+test(function() {
+    let track = video.addTextTrack('subtitles');
+    track.addCue(new VTTCue(2, 5, '1'));
+    track.addCue(new VTTCue(2, 5, '2'));
+    track.addCue(new VTTCue(2, 5, '3'));
+    assert_equals(concat_cuetext(track.cues), '123', 'initial order');
+
+    track.cues[0].startTime = 4;
+    assert_equals(concat_cuetext(track.cues), '231', '"1" moved last');
+
+    track.cues[2].startTime = 2;
+    assert_equals(concat_cuetext(track.cues), '123', '"1" moved first');
+}, document.title + ', equal start and end times with startTime mutations.');
+
+test(function() {
+    let track = video.addTextTrack('subtitles');
+    track.addCue(new VTTCue(2, 5, '1'));
+    track.addCue(new VTTCue(2, 5, '2'));
+    track.addCue(new VTTCue(2, 5, '3'));
+    assert_equals(concat_cuetext(track.cues), '123', 'initial order');
+
+    track.cues[2].endTime = 9;
+    assert_equals(concat_cuetext(track.cues), '312', '"3" moved first');
+
+    track.cues[1].endTime = 3;
+    assert_equals(concat_cuetext(track.cues), '321', '"1" moved last');
+}, document.title + ', equal start and end times with endTime mutations.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt
new file mode 100644
index 0000000..774fd0c7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted-expected.txt
@@ -0,0 +1,24 @@
+This is a testharness.js-based test.
+PASS getting audio.muted (parser-created)
+PASS setting audio.muted (parser-created)
+FAIL getting audio.muted with muted="" (parser-created) assert_true: expected true got false
+FAIL setting audio.muted with muted="" (parser-created) assert_equals: expected true but got false
+PASS getting video.muted (parser-created)
+PASS setting video.muted (parser-created)
+FAIL getting video.muted with muted="" (parser-created) assert_true: expected true got false
+FAIL setting video.muted with muted="" (parser-created) assert_equals: expected true but got false
+FAIL getting video.muted with muted="" after load (parser-created) assert_true: expected true got false
+PASS getting audio.muted (script-created)
+PASS setting audio.muted (script-created)
+PASS getting audio.muted with muted="" (script-created)
+PASS setting audio.muted with muted="" (script-created)
+FAIL getting audio.muted with muted="" (innerHTML-created) assert_true: expected true got false
+FAIL getting audio.muted with muted="" (document.write-created) assert_true: expected true got false
+PASS getting video.muted (script-created)
+PASS setting video.muted (script-created)
+PASS getting video.muted with muted="" (script-created)
+PASS setting video.muted with muted="" (script-created)
+FAIL getting video.muted with muted="" (innerHTML-created) assert_true: expected true got false
+FAIL getting video.muted with muted="" (document.write-created) assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html
new file mode 100644
index 0000000..906350d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/user-interface/muted.html
@@ -0,0 +1,152 @@
+<!doctype html>
+<title>muted</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<style>video { display: none; }</style>
+<div id=log></div>
+
+<script>
+function test_setting(e, muted, hasAttribute) {
+  assert_equals(e.muted, muted);
+  assert_equals(e.hasAttribute('muted'), hasAttribute);
+
+  e.muted = !e.muted;
+  assert_equals(e.muted, !muted);
+  assert_equals(e.hasAttribute('muted'), hasAttribute);
+
+  e.muted = !e.muted;
+  assert_equals(e.muted, muted);
+  assert_equals(e.hasAttribute('muted'), hasAttribute);
+}
+</script>
+
+<!-- These tests are inside <audio>/<video> so that the steps for updating the
+     muted IDL attribute cannot be delayed until the end tag is parsed. -->
+
+<audio id=a1>
+<script>
+var a1 = document.getElementById('a1');
+
+test(function() {
+  assert_false(a1.muted);
+}, 'getting audio.muted (parser-created)');
+
+test(function() {
+  test_setting(a1, false, false);
+}, 'setting audio.muted (parser-created)');
+</script>
+</audio>
+
+<audio id=a2 muted>
+<script>
+var a2 = document.getElementById('a2');
+
+test(function() {
+  assert_true(a2.muted);
+}, 'getting audio.muted with muted="" (parser-created)');
+
+test(function() {
+  test_setting(a2, true, true);
+}, 'setting audio.muted with muted="" (parser-created)');
+</script>
+</audio>
+
+<video id=v1>
+<script>
+var v1 = document.getElementById('v1');
+
+test(function() {
+  assert_false(v1.muted);
+}, 'getting video.muted (parser-created)');
+
+test(function() {
+  test_setting(v1, false, false);
+}, 'setting video.muted (parser-created)');
+</script>
+</video>
+
+<video id=v2 muted>
+<script>
+var v2 = document.getElementById('v2');
+
+test(function() {
+  assert_true(v2.muted);
+}, 'getting video.muted with muted="" (parser-created)');
+
+test(function() {
+  test_setting(v2, true, true);
+}, 'setting video.muted with muted="" (parser-created)');
+</script>
+</video>
+
+<!-- Negative test to ensure that the load algorithm does not update the
+     muted IDL attribute to match the content attribute. -->
+
+<video id=v3 muted></video>
+<script>
+async_test(function(t) {
+  var v = document.getElementById('v3');
+  assert_true(v.muted);
+  v.muted = false;
+  v.src = 'data:,'; // invokes load()
+  v.addEventListener('error', t.step_func(function() {
+    assert_false(v.muted);
+    t.done();
+  }));
+}, 'getting video.muted with muted="" after load (parser-created)');
+</script>
+
+<script>
+['audio', 'video'].forEach(function(tagName) {
+  test(function() {
+    var m = document.createElement(tagName);
+    assert_false(m.muted);
+  }, 'getting ' + tagName + '.muted (script-created)');
+
+  test(function() {
+    var m = document.createElement(tagName);
+    test_setting(m, false, false);
+  }, 'setting ' + tagName + '.muted (script-created)');
+
+  test(function() {
+    var m = document.createElement(tagName);
+    m.setAttribute('muted', '');
+    assert_false(m.muted);
+  }, 'getting ' + tagName + '.muted with muted="" (script-created)');
+
+  test(function() {
+    var m = document.createElement(tagName);
+    m.setAttribute('muted', '');
+    test_setting(m, false, true);
+  }, 'setting ' + tagName + '.muted with muted="" (script-created)');
+
+  // Spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=25153
+  /*
+  test(function() {
+    var m = document.createElement(tagName);
+    m.setAttribute('muted', '');
+    m = m.cloneNode(false);
+    assert_true(m.hasAttribute('muted'));
+    assert_false(m.muted);
+  }, 'getting ' + tagName + '.muted with muted="" (cloneNode-created)');
+  */
+
+  test(function() {
+    var div = document.createElement('div');
+    div.innerHTML = '<' + tagName + ' muted>';
+    m = div.firstChild;
+    assert_true(m.hasAttribute('muted'));
+    assert_true(m.muted);
+  }, 'getting ' + tagName + '.muted with muted="" (innerHTML-created)');
+
+  test(function() {
+    var id = tagName;
+    assert_equals(document.getElementById(id), null);
+    document.write('<' + tagName + ' id=' + id + ' muted>');
+    m = document.getElementById(id);
+    assert_true(m.hasAttribute('muted'));
+    assert_true(m.muted);
+  }, 'getting ' + tagName + '.muted with muted="" (document.write-created)');
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_loop_base.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_loop_base.html
new file mode 100644
index 0000000..348f1cd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_loop_base.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Video Test: video_loop_base</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-loop" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if video.loop is set to true that expecting the seeking event is fired more than once" />
+    <meta name=timeout content=long>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <div id="log"></div>
+    <video id="m" controls>The user agent doesn't support media element.</video>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        var name = document.getElementsByName("assert")[0].content;
+        var t = async_test(name);
+        var looped = false;
+
+        function startTest() {
+            if (looped) {
+                t.step(function() {
+                    assert_true(true, "looped");
+                });
+                t.done();
+                media.pause();
+            }
+
+            looped = true;
+        }
+
+        media.addEventListener("seeking", startTest, false);
+        media.loop = true;
+        media.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.canvas.readonly.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.canvas.readonly.html
new file mode 100644
index 0000000..5e1c22d2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.canvas.readonly.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.canvas.readonly</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.canvas.readonly</h1>
+<p class="desc">CanvasRenderingContext2D.canvas is readonly</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("CanvasRenderingContext2D.canvas is readonly");
+_addTest(function(canvas, ctx) {
+
+var c = document.createElement('canvas');
+var d = ctx.canvas;
+_assertDifferent(c, d, "c", "d");
+ctx.canvas = c;
+_assertSame(ctx.canvas, d, "ctx.canvas", "d");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.canvas.reference.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.canvas.reference.html
new file mode 100644
index 0000000..5bdb233
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.canvas.reference.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.canvas.reference</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.canvas.reference</h1>
+<p class="desc">CanvasRenderingContext2D.canvas refers back to its canvas</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("CanvasRenderingContext2D.canvas refers back to its canvas");
+_addTest(function(canvas, ctx) {
+
+_assertSame(ctx.canvas, canvas, "ctx.canvas", "canvas");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.exists.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.exists.html
new file mode 100644
index 0000000..f8b768ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.exists.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.getcontext.exists</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.getcontext.exists</h1>
+<p class="desc">The 2D context is implemented</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("The 2D context is implemented");
+_addTest(function(canvas, ctx) {
+
+_assertDifferent(canvas.getContext('2d'), null, "canvas.getContext('2d')", "null");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.extraargs.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.extraargs.html
new file mode 100644
index 0000000..f58911d0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.extraargs.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.getcontext.extraargs</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.getcontext.extraargs</h1>
+<p class="desc">The 2D context ignores extra getContext arguments</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("The 2D context ignores extra getContext arguments");
+_addTest(function(canvas, ctx) {
+
+_assertDifferent(canvas.getContext('2d', false, {}, [], 1, "2"), null, "canvas.getContext('2d', false, {}, [], 1, \"2\")", "null");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.shared.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.shared.html
new file mode 100644
index 0000000..a678a135
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.shared.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.getcontext.shared</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.getcontext.shared</h1>
+<p class="desc">getContext('2d') returns objects which share canvas state</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("getContext('2d') returns objects which share canvas state");
+_addTest(function(canvas, ctx) {
+
+var ctx2 = canvas.getContext('2d');
+ctx.fillStyle = '#f00';
+ctx2.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 50);
+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.unique.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.unique.html
new file mode 100644
index 0000000..d4d4a0d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.getcontext.unique.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.getcontext.unique</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.getcontext.unique</h1>
+<p class="desc">getContext('2d') returns the same object</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("getContext('2d') returns the same object");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.getContext('2d'), canvas.getContext('2d'), "canvas.getContext('2d')", "canvas.getContext('2d')");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.scaled-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.scaled-manual.html
new file mode 100644
index 0000000..6ea8ba4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.scaled-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.scaled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.scaled</h1>
+<p class="desc">CSS-scaled canvases get drawn correctly</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="25" style="width: 100px; height: 50px"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="2d.scaled.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("CSS-scaled canvases get drawn correctly");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#00f';
+ctx.fillRect(0, 0, 50, 25);
+ctx.fillStyle = '#0ff';
+ctx.fillRect(0, 0, 25, 10);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.scaled.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.scaled.png
new file mode 100644
index 0000000..8754077
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.scaled.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.exists.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.exists.html
new file mode 100644
index 0000000..f29f139
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.exists.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.type.exists</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.type.exists</h1>
+<p class="desc">The 2D context interface is a property of 'window'</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("The 2D context interface is a property of 'window'");
+_addTest(function(canvas, ctx) {
+
+_assert(window.CanvasRenderingContext2D, "window.CanvasRenderingContext2D");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.extend.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.extend.html
new file mode 100644
index 0000000..f4dfea8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.extend.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.type.extend</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.type.extend</h1>
+<p class="desc">Interface methods can be added</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Interface methods can be added");
+_addTest(function(canvas, ctx) {
+
+window.CanvasRenderingContext2D.prototype.fillRectGreen = function (x, y, w, h)
+{
+    this.fillStyle = '#0f0';
+    this.fillRect(x, y, w, h);
+};
+ctx.fillStyle = '#f00';
+ctx.fillRectGreen(0, 0, 100, 50);
+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.prototype.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.prototype.html
new file mode 100644
index 0000000..9888d7b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.prototype.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.type.prototype</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.type.prototype</h1>
+<p class="desc">window.CanvasRenderingContext2D.prototype are not [[Writable]] and not [[Configurable]], and its methods are [[Configurable]].</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("window.CanvasRenderingContext2D.prototype are not [[Writable]] and not [[Configurable]], and its methods are [[Configurable]].");
+_addTest(function(canvas, ctx) {
+
+_assert(window.CanvasRenderingContext2D.prototype, "window.CanvasRenderingContext2D.prototype");
+_assert(window.CanvasRenderingContext2D.prototype.fill, "window.CanvasRenderingContext2D.prototype.fill");
+window.CanvasRenderingContext2D.prototype = null;
+_assert(window.CanvasRenderingContext2D.prototype, "window.CanvasRenderingContext2D.prototype");
+delete window.CanvasRenderingContext2D.prototype;
+_assert(window.CanvasRenderingContext2D.prototype, "window.CanvasRenderingContext2D.prototype");
+window.CanvasRenderingContext2D.prototype.fill = 1;
+_assertSame(window.CanvasRenderingContext2D.prototype.fill, 1, "window.CanvasRenderingContext2D.prototype.fill", "1");
+delete window.CanvasRenderingContext2D.prototype.fill;
+_assertSame(window.CanvasRenderingContext2D.prototype.fill, undefined, "window.CanvasRenderingContext2D.prototype.fill", "undefined");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.replace.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.replace.html
new file mode 100644
index 0000000..1e333773
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/2d.type.replace.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: 2d.type.replace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>2d.type.replace</h1>
+<p class="desc">Interface methods can be overridden</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Interface methods can be overridden");
+_addTest(function(canvas, ctx) {
+
+var fillRect = window.CanvasRenderingContext2D.prototype.fillRect;
+window.CanvasRenderingContext2D.prototype.fillRect = function (x, y, w, h)
+{
+    this.fillStyle = '#0f0';
+    fillRect.call(this, x, y, w, h);
+};
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 100, 50);
+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/contains.json b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/contains.json
new file mode 100644
index 0000000..3f56f4f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/contains.json
@@ -0,0 +1,10 @@
+[
+    {
+        "id": "color-spaces-and-color-correction",
+        "original_id": "color-spaces-and-color-correction"
+    },
+    {
+        "id": "security-with-canvas-elements",
+        "original_id": "security-with-canvas-elements"
+    }
+]
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.arguments.missing.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.arguments.missing.html
new file mode 100644
index 0000000..37ae4e8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.arguments.missing.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: context.arguments.missing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>context.arguments.missing</h1>
+<p class="desc"></p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("");
+_addTest(function(canvas, ctx) {
+
+assert_throws(new TypeError(), function() { canvas.getContext(); });
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.casesensitive.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.casesensitive.html
new file mode 100644
index 0000000..5c64f7a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.casesensitive.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: context.casesensitive</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>context.casesensitive</h1>
+<p class="desc">Context name "2D" is unrecognised; matching is case sensitive</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Context name \"2D\" is unrecognised; matching is case sensitive");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.getContext('2D'), null, "canvas.getContext('2D')", "null");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.emptystring.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.emptystring.html
new file mode 100644
index 0000000..8f8b44a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.emptystring.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: context.emptystring</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>context.emptystring</h1>
+<p class="desc">getContext with empty string returns null</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("getContext with empty string returns null");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.getContext(""), null, "canvas.getContext(\"\")", "null");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badname.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badname.html
new file mode 100644
index 0000000..75f4427
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badname.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: context.unrecognised.badname</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>context.unrecognised.badname</h1>
+<p class="desc">getContext with unrecognised context name returns null</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("getContext with unrecognised context name returns null");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.getContext('This is not an implemented context in any real browser'), null, "canvas.getContext('This is not an implemented context in any real browser')", "null");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badsuffix.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badsuffix.html
new file mode 100644
index 0000000..2f65ae3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.badsuffix.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: context.unrecognised.badsuffix</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>context.unrecognised.badsuffix</h1>
+<p class="desc">Context name "2d" plus a suffix is unrecognised</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Context name \"2d\" plus a suffix is unrecognised");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.getContext("2d#"), null, "canvas.getContext(\"2d#\")", "null");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.nullsuffix.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.nullsuffix.html
new file mode 100644
index 0000000..1607fec8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.nullsuffix.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: context.unrecognised.nullsuffix</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>context.unrecognised.nullsuffix</h1>
+<p class="desc">Context name "2d" plus a "\0" suffix is unrecognised</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Context name \"2d\" plus a \"\\0\" suffix is unrecognised");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.getContext("2d\0"), null, "canvas.getContext(\"2d\\0\")", "null");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.unicode.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.unicode.html
new file mode 100644
index 0000000..c4eb943
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/context.unrecognised.unicode.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: context.unrecognised.unicode</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>context.unrecognised.unicode</h1>
+<p class="desc">Context name which kind of looks like "2d" is unrecognised</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Context name which kind of looks like \"2d\" is unrecognised");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.getContext("2\uFF44"), null, "canvas.getContext(\"2\\uFF44\")", "null"); // Fullwidth Latin Small Letter D
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.basic.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.basic.html
new file mode 100644
index 0000000..0bae976
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.basic.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: fallback.basic</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>fallback.basic</h1>
+<p class="desc">Fallback content is inserted into the DOM</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Fallback content is inserted into the DOM");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.childNodes.length, 1, "canvas.childNodes.length", "1");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.multiple.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.multiple.html
new file mode 100644
index 0000000..5c89be51
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.multiple.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: fallback.multiple</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>fallback.multiple</h1>
+<p class="desc">Fallback content with multiple elements</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL</p><p class="fallback">FAIL</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Fallback content with multiple elements");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.childNodes.length, 2, "canvas.childNodes.length", "2");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.nested.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.nested.html
new file mode 100644
index 0000000..e84739c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/fallback.nested.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: fallback.nested</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>fallback.nested</h1>
+<p class="desc">Fallback content containing another canvas (mostly testing parsers)</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><canvas><p class="fallback">FAIL (fallback content)</p></canvas><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Fallback content containing another canvas (mostly testing parsers)");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.childNodes.length, 2, "canvas.childNodes.length", "2");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/historical.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/historical.html
new file mode 100644
index 0000000..58ebc57
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/historical.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Historical canvas features</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+var canvas, context;
+setup(function() {
+  canvas = document.createElement("canvas");
+  context = canvas.getContext('2d');
+  path2d = new Path2D();
+});
+function t(member, obj) {
+  var name = obj === canvas ? "Canvas" : String(obj).match(/\[object (\S+)\]/)[1];
+  test(function() {
+    assert_false(member in obj);
+  }, name + " support for " + member);
+}
+// added in https://github.com/whatwg/html/commit/0ecbf0e010df16d9c6d11eef6b2c58419158c4da
+// renamed in https://github.com/whatwg/html/commit/2542a12cb25ee93534cbed1f31b5e1bc05fcdd0e
+t("supportsContext", canvas);
+
+// removed in https://github.com/whatwg/html/commit/2cfb8e3f03d3166842d2ad0f661459d26e2a40eb
+t("probablySupportsContext", canvas);
+
+// removed in https://github.com/whatwg/html/commit/ef72f55da4acdf266174225c6ca8bf2a650d0219
+t("width", context);
+t("height", context);
+
+// removed in https://github.com/whatwg/html/commit/740634d0f30a3b76e9da166ac2fa8835fcc073ab
+t("setContext", canvas);
+t("transferControlToProxy", canvas);
+t("CanvasProxy", window);
+t("commit", canvas);
+test(function() {
+  assert_throws(new TypeError(), function() {
+    new CanvasRenderingContext2D();
+  }, 'no arguments');
+  assert_throws(new TypeError(), function() {
+    new CanvasRenderingContext2D(1, 1);
+  }, 'with arguments');
+}, "CanvasRenderingContext2D constructors");
+
+// removed in https://github.com/whatwg/html/commit/e1d04f49a38e2254a783c28987457a95a47d9511
+t("addPathByStrokingPath", path2d);
+t("addText", path2d);
+t("addPathByStrokingText", path2d);
+
+// renamed in https://github.com/whatwg/html/commit/fcb0756dd94d96df9b8355741d82fcd5ca0a6154
+test(function() {
+  var canvas = document.createElement('canvas');
+  var context = canvas.getContext('bitmaprenderer');
+  if (context) {
+    assert_false('transferImageBitmap' in context);
+  }
+}, 'ImageBitmapRenderingContext support for transferImageBitmap');
+
+// renamed in https://github.com/whatwg/html/commit/3aec2a7e04a3402201afd29c224b57fa54497517
+t('Path', window);
+
+// removed in https://github.com/whatwg/html/commit/d5759b0435091e4858c9bff90319cbe5b040eda2
+t('toDataURLHD', canvas);
+t('toBlobHD', canvas);
+t('createImageDataHD', context);
+t('getImageDataHD', context);
+t('putImageDataHD', context);
+test(function() {
+  if ('ImageData' in window) {
+    assert_false('resolution' in new ImageData(1, 1));
+  }
+}, 'ImageData support for resolution');
+
+// dropped/renamed in https://github.com/whatwg/html/commit/ff07c6d630fb986f6c4f64b2fb87387b4f89647d
+t('drawSystemFocusRing', context);
+t('drawCustomFocusRing', context);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/imagedata-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/imagedata-expected.txt
new file mode 100644
index 0000000..8af818e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/imagedata-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS ImageData(w, h), width cannot be 0
+PASS ImageData(w, h), height cannot be 0
+PASS ImageData(w, h), exposed attributes check
+FAIL ImageData(buffer, w), the buffer size must be a multiple of 4 assert_throws: function "function () {
+        new ImageData(new Uint8ClampedArray(3), 1);
+    }" threw object "IndexSizeError: Failed to construct 'ImageData': The input data length is not a multiple of 4." that is not a DOMException InvalidStateError: property "code" is equal to 1, expected 11
+PASS ImageData(buffer, w), buffer size must be a multiple of the image width
+PASS ImageData(buffer, w, h), buffer.lenght == 4 * w * h must be true
+FAIL ImageData(buffer, w, opt h), Uint8ClampedArray argument type check assert_throws: function "function () {
+        new ImageData(new Int8Array(1), 1);
+    }" threw object "IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number." ("IndexSizeError") expected object "TypeError" ("TypeError")
+PASS ImageData(buffer, w, opt h), exposed attributes check
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/imagedata.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/imagedata.html
new file mode 100644
index 0000000..b5b4d0de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/imagedata.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>ImageData Tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+    assert_throws("IndexSizeError", function() {
+        new ImageData(0, 1);
+    });
+}, "ImageData(w, h), width cannot be 0");
+
+test(function() {
+    assert_throws("IndexSizeError", function() {
+        new ImageData(1, 0);
+    });
+}, "ImageData(w, h), height cannot be 0");
+
+test(function() {
+    var imageData = new ImageData(2, 3);
+    assert_equals(imageData.width, 2);
+    assert_equals(imageData.height, 3);
+    assert_equals(imageData.data.length, 24);
+    assert_true(imageData.data instanceof Uint8ClampedArray);
+}, "ImageData(w, h), exposed attributes check");
+
+test(function() {
+    assert_throws("InvalidStateError", function() {
+        new ImageData(new Uint8ClampedArray(3), 1);
+    });
+}, "ImageData(buffer, w), the buffer size must be a multiple of 4");
+
+test(function() {
+    assert_throws("IndexSizeError", function() {
+        new ImageData(new Uint8ClampedArray(16), 3);
+    });
+}, "ImageData(buffer, w), buffer size must be a multiple of the image width");
+
+test(function() {
+    assert_throws("IndexSizeError", function() {
+        new ImageData(new Uint8ClampedArray(16), 4, 3);
+    });
+}, "ImageData(buffer, w, h), buffer.lenght == 4 * w * h must be true");
+
+test(function() {
+    assert_throws(new TypeError(), function() {
+        new ImageData(new Int8Array(1), 1);
+    });
+}, "ImageData(buffer, w, opt h), Uint8ClampedArray argument type check");
+
+test(function() {
+    var imageData = new ImageData(new Uint8ClampedArray(24), 2);
+    assert_equals(imageData.width, 2);
+    assert_equals(imageData.height, 3);
+    assert_equals(imageData.data.length, 24);
+    assert_true(imageData.data instanceof Uint8ClampedArray);
+}, "ImageData(buffer, w, opt h), exposed attributes check");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.colour.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.colour.html
new file mode 100644
index 0000000..f680d50
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.colour.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.colour</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.colour</h1>
+<p class="desc">Initial state is transparent black</p>
+
+<p class="notes">Output should be transparent black (not transparent anything-else), but manual
+verification can only confirm that it's transparent - it's not possible to make
+the actual blackness visible.
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="initial.colour.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Initial state is transparent black");
+_addTest(function(canvas, ctx) {
+
+_assertPixel(canvas, 20,20, 0,0,0,0, "20,20", "0,0,0,0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.colour.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.colour.png
new file mode 100644
index 0000000..eeedd0f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.colour.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html
new file mode 100644
index 0000000..b51253a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.2dstate.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.2dstate</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.2dstate</h1>
+<p class="desc">Resetting the canvas state resets 2D state variables</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state resets 2D state variables");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 100;
+var default_val;
+
+default_val = ctx.strokeStyle;
+ctx.strokeStyle = "#ff0000";
+canvas.width = 100;
+_assertSame(ctx.strokeStyle, default_val, "ctx.strokeStyle", "default_val");
+
+default_val = ctx.fillStyle;
+ctx.fillStyle = "#ff0000";
+canvas.width = 100;
+_assertSame(ctx.fillStyle, default_val, "ctx.fillStyle", "default_val");
+
+default_val = ctx.globalAlpha;
+ctx.globalAlpha = 0.5;
+canvas.width = 100;
+_assertSame(ctx.globalAlpha, default_val, "ctx.globalAlpha", "default_val");
+
+default_val = ctx.lineWidth;
+ctx.lineWidth = 0.5;
+canvas.width = 100;
+_assertSame(ctx.lineWidth, default_val, "ctx.lineWidth", "default_val");
+
+default_val = ctx.lineCap;
+ctx.lineCap = "round";
+canvas.width = 100;
+_assertSame(ctx.lineCap, default_val, "ctx.lineCap", "default_val");
+
+default_val = ctx.lineJoin;
+ctx.lineJoin = "round";
+canvas.width = 100;
+_assertSame(ctx.lineJoin, default_val, "ctx.lineJoin", "default_val");
+
+default_val = ctx.miterLimit;
+ctx.miterLimit = 0.5;
+canvas.width = 100;
+_assertSame(ctx.miterLimit, default_val, "ctx.miterLimit", "default_val");
+
+default_val = ctx.shadowOffsetX;
+ctx.shadowOffsetX = 5;
+canvas.width = 100;
+_assertSame(ctx.shadowOffsetX, default_val, "ctx.shadowOffsetX", "default_val");
+
+default_val = ctx.shadowOffsetY;
+ctx.shadowOffsetY = 5;
+canvas.width = 100;
+_assertSame(ctx.shadowOffsetY, default_val, "ctx.shadowOffsetY", "default_val");
+
+default_val = ctx.shadowBlur;
+ctx.shadowBlur = 5;
+canvas.width = 100;
+_assertSame(ctx.shadowBlur, default_val, "ctx.shadowBlur", "default_val");
+
+default_val = ctx.shadowColor;
+ctx.shadowColor = "#ff0000";
+canvas.width = 100;
+_assertSame(ctx.shadowColor, default_val, "ctx.shadowColor", "default_val");
+
+default_val = ctx.globalCompositeOperation;
+ctx.globalCompositeOperation = "copy";
+canvas.width = 100;
+_assertSame(ctx.globalCompositeOperation, default_val, "ctx.globalCompositeOperation", "default_val");
+
+default_val = ctx.font;
+ctx.font = "25px serif";
+canvas.width = 100;
+_assertSame(ctx.font, default_val, "ctx.font", "default_val");
+
+default_val = ctx.textAlign;
+ctx.textAlign = "center";
+canvas.width = 100;
+_assertSame(ctx.textAlign, default_val, "ctx.textAlign", "default_val");
+
+default_val = ctx.textBaseline;
+ctx.textBaseline = "bottom";
+canvas.width = 100;
+_assertSame(ctx.textBaseline, default_val, "ctx.textBaseline", "default_val");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.clip.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.clip.html
new file mode 100644
index 0000000..044ccc58
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.clip.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.clip</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.clip</h1>
+<p class="desc">Resetting the canvas state resets the current clip region</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state resets the current clip region");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 100;
+ctx.rect(0, 0, 1, 1);
+ctx.clip();
+canvas.width = 100;
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 50);
+_assertPixel(canvas, 20,20, 0,255,0,255, "20,20", "0,255,0,255");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.different.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.different.html
new file mode 100644
index 0000000..0d02f40
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.different.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.different</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.different</h1>
+<p class="desc">Changing size resets canvas to transparent black</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="initial.reset.different.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Changing size resets canvas to transparent black");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 50, 50);
+_assertPixel(canvas, 20,20, 255,0,0,255, "20,20", "255,0,0,255");
+canvas.width = 50;
+_assertPixel(canvas, 20,20, 0,0,0,0, "20,20", "0,0,0,0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.different.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.different.png
new file mode 100644
index 0000000..d83fdd55b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.different.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.gradient.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.gradient.html
new file mode 100644
index 0000000..a1a8516
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.gradient.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.gradient</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.gradient</h1>
+<p class="desc">Resetting the canvas state does not invalidate any existing gradients</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state does not invalidate any existing gradients");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 50;
+var g = ctx.createLinearGradient(0, 0, 100, 0);
+g.addColorStop(0, '#0f0');
+g.addColorStop(1, '#0f0');
+canvas.width = 100;
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 100, 50);
+ctx.fillStyle = g;
+ctx.fillRect(0, 0, 100, 50);
+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.path.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.path.html
new file mode 100644
index 0000000..ab59ce9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.path.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.path</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.path</h1>
+<p class="desc">Resetting the canvas state resets the current path</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="initial.reset.path.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state resets the current path");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 100;
+ctx.rect(0, 0, 100, 50);
+canvas.width = 100;
+ctx.fillStyle = '#f00';
+ctx.fill();
+_assertPixel(canvas, 20,20, 0,0,0,0, "20,20", "0,0,0,0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.path.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.path.png
new file mode 100644
index 0000000..eeedd0f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.path.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.pattern.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.pattern.html
new file mode 100644
index 0000000..f569d21
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.pattern.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.pattern</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.pattern</h1>
+<p class="desc">Resetting the canvas state does not invalidate any existing patterns</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state does not invalidate any existing patterns");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 30;
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 30, 50);
+var p = ctx.createPattern(canvas, 'repeat-x');
+canvas.width = 100;
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 100, 50);
+ctx.fillStyle = p;
+ctx.fillRect(0, 0, 100, 50);
+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.same.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.same.html
new file mode 100644
index 0000000..b0bf73f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.same.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.same</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.same</h1>
+<p class="desc">Setting size (not changing the value) resets canvas to transparent black</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="initial.reset.same.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting size (not changing the value) resets canvas to transparent black");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 100;
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 50, 50);
+_assertPixel(canvas, 20,20, 255,0,0,255, "20,20", "255,0,0,255");
+canvas.width = 100;
+_assertPixel(canvas, 20,20, 0,0,0,0, "20,20", "0,0,0,0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.same.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.same.png
new file mode 100644
index 0000000..eeedd0f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.same.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.transform.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.transform.html
new file mode 100644
index 0000000..c5a92ca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/initial.reset.transform.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: initial.reset.transform</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>initial.reset.transform</h1>
+<p class="desc">Resetting the canvas state resets the current transformation matrix</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state resets the current transformation matrix");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 100;
+ctx.scale(0.1, 0.1);
+canvas.width = 100;
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 50);
+_assertPixel(canvas, 20,20, 0,255,0,255, "20,20", "0,255,0,255");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.dataURI.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.dataURI.html
new file mode 100644
index 0000000..d130579
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.dataURI.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.dataURI</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.dataURI</h1>
+<p class="desc">data: URIs do not count as different-origin, and do not taint the canvas</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="/images/green-100x50.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("data: URIs do not count as different-origin, and do not taint the canvas");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#0f0';
+ctx.fillRect(0, 0, 100, 50);
+var data = canvas.toDataURL();
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 100, 50);
+var img = new Image();
+deferTest();
+img.onload = t.step_func_done(function ()
+{
+    ctx.drawImage(img, 0, 0);
+    canvas.toDataURL(); // should be permitted
+    _assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");
+});
+img.src = data;
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.cross.html
new file mode 100644
index 0000000..ab9bc9f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.cross.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.drawImage.canvas.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.drawImage.canvas.cross</h1>
+<p class="desc">drawImage of unclean canvas makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("drawImage of unclean canvas makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+ctx.drawImage(canvas2, 0, 0);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.redirect.html
new file mode 100644
index 0000000..114b78c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.canvas.redirect.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.drawImage.canvas.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.drawImage.canvas.redirect</h1>
+<p class="desc">drawImage of unclean canvas makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("drawImage of unclean canvas makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+ctx.drawImage(canvas2, 0, 0);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.cross.html
new file mode 100644
index 0000000..99789f8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.cross.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.drawImage.image.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.drawImage.image.cross</h1>
+<p class="desc">drawImage of different-origin image makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("drawImage of different-origin image makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.redirect.html
new file mode 100644
index 0000000..29f33d8a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.drawImage.image.redirect.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.drawImage.image.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.drawImage.image.redirect</h1>
+<p class="desc">drawImage of different-origin image makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("drawImage of different-origin image makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.cross.html
new file mode 100644
index 0000000..aaa541a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.cross.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.canvas.fillStyle.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.canvas.fillStyle.cross</h1>
+<p class="desc">Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+var p = ctx.createPattern(canvas2, 'repeat');
+ctx.fillStyle = p;
+ctx.fillStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.redirect.html
new file mode 100644
index 0000000..2d1b73e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.fillStyle.redirect.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.canvas.fillStyle.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.canvas.fillStyle.redirect</h1>
+<p class="desc">Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+var p = ctx.createPattern(canvas2, 'repeat');
+ctx.fillStyle = p;
+ctx.fillStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.cross.html
new file mode 100644
index 0000000..1147990
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.cross.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.canvas.strokeStyle.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.canvas.strokeStyle.cross</h1>
+<p class="desc">Setting strokeStyle to a pattern of an unclean canvas makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting strokeStyle to a pattern of an unclean canvas makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+var p = ctx.createPattern(canvas2, 'repeat');
+ctx.strokeStyle = p;
+ctx.strokeStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.redirect.html
new file mode 100644
index 0000000..eb91932
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.strokeStyle.redirect.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.canvas.strokeStyle.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.canvas.strokeStyle.redirect</h1>
+<p class="desc">Setting strokeStyle to a pattern of an unclean canvas makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting strokeStyle to a pattern of an unclean canvas makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0);
+var p = ctx.createPattern(canvas2, 'repeat');
+ctx.strokeStyle = p;
+ctx.strokeStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.cross.html
new file mode 100644
index 0000000..338fdce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.cross.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.canvas.timing.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.canvas.timing.cross</h1>
+<p class="desc">Pattern safety depends on whether the source was origin-clean, not on whether it still is clean</p>
+
+<p class="notes">Disagrees with spec on "is" vs "was"
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Pattern safety depends on whether the source was origin-clean, not on whether it still is clean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.fillStyle = '#0f0';
+ctx2.fillRect(0, 0, 100, 50);
+var p = ctx.createPattern(canvas2, 'repeat');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0); // make canvas2 origin-unclean
+ctx.fillStyle = p;
+ctx.fillRect(0, 0, 100, 50);
+canvas.toDataURL();
+ctx.getImageData(0, 0, 1, 1);
+_assert(true, "true"); // okay if there was no exception
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.redirect.html
new file mode 100644
index 0000000..806c485
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.canvas.timing.redirect.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.canvas.timing.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.canvas.timing.redirect</h1>
+<p class="desc">Pattern safety depends on whether the source was origin-clean, not on whether it still is clean</p>
+
+<p class="notes">Disagrees with spec on "is" vs "was"
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Pattern safety depends on whether the source was origin-clean, not on whether it still is clean");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+ctx2.fillStyle = '#0f0';
+ctx2.fillRect(0, 0, 100, 50);
+var p = ctx.createPattern(canvas2, 'repeat');
+ctx2.drawImage(document.getElementById('yellow.png'), 0, 0); // make canvas2 origin-unclean
+ctx.fillStyle = p;
+ctx.fillRect(0, 0, 100, 50);
+canvas.toDataURL();
+ctx.getImageData(0, 0, 1, 1);
+_assert(true, "true"); // okay if there was no exception
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.create.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.create.cross.html
new file mode 100644
index 0000000..f6860368
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.create.cross.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.create.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.create.cross</h1>
+<p class="desc">Creating an unclean pattern does not make the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Creating an unclean pattern does not make the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+canvas.toDataURL();
+ctx.getImageData(0, 0, 1, 1);
+_assert(true, "true"); // okay if there was no exception
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.create.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.create.redirect.html
new file mode 100644
index 0000000..2993d07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.create.redirect.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.create.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.create.redirect</h1>
+<p class="desc">Creating an unclean pattern does not make the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Creating an unclean pattern does not make the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+canvas.toDataURL();
+ctx.getImageData(0, 0, 1, 1);
+_assert(true, "true"); // okay if there was no exception
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.cross.html
new file mode 100644
index 0000000..16995eb5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.cross.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.cross.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.cross.cross</h1>
+<p class="desc">Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+var p = ctx2.createPattern(document.getElementById('yellow.png'), 'repeat');
+ctx.fillStyle = p;
+ctx.fillRect(0, 0, 100, 50);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+canvas2.toDataURL();
+ctx2.getImageData(0, 0, 1, 1);
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.redirect.html
new file mode 100644
index 0000000..a65ffb5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.cross.redirect.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.cross.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.cross.redirect</h1>
+<p class="desc">Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas");
+_addTest(function(canvas, ctx) {
+
+var canvas2 = document.createElement('canvas');
+canvas2.width = 100;
+canvas2.height = 50;
+var ctx2 = canvas2.getContext('2d');
+var p = ctx2.createPattern(document.getElementById('yellow.png'), 'repeat');
+ctx.fillStyle = p;
+ctx.fillRect(0, 0, 100, 50);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+canvas2.toDataURL();
+ctx2.getImageData(0, 0, 1, 1);
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html
new file mode 100644
index 0000000..cdba44b6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.image.fillStyle.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.image.fillStyle.cross</h1>
+<p class="desc">Setting fillStyle to a pattern of a different-origin image makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting fillStyle to a pattern of a different-origin image makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+ctx.fillStyle = p;
+ctx.fillStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.redirect.html
new file mode 100644
index 0000000..3f0bbf6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.redirect.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.image.fillStyle.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.image.fillStyle.redirect</h1>
+<p class="desc">Setting fillStyle to a pattern of a different-origin image makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting fillStyle to a pattern of a different-origin image makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+ctx.fillStyle = p;
+ctx.fillStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.cross.html
new file mode 100644
index 0000000..51ab8d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.cross.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.image.strokeStyle.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.image.strokeStyle.cross</h1>
+<p class="desc">Setting strokeStyle to a pattern of a different-origin image makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting strokeStyle to a pattern of a different-origin image makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+ctx.strokeStyle = p;
+ctx.strokeStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.redirect.html
new file mode 100644
index 0000000..70a0267
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.image.strokeStyle.redirect.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.image.strokeStyle.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.pattern.image.strokeStyle.redirect</h1>
+<p class="desc">Setting strokeStyle to a pattern of a different-origin image makes the canvas origin-unclean</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting strokeStyle to a pattern of a different-origin image makes the canvas origin-unclean");
+_addTest(function(canvas, ctx) {
+
+var p = ctx.createPattern(document.getElementById('yellow.png'), 'repeat');
+ctx.strokeStyle = p;
+ctx.strokeStyle = 'red';
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.cross-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.cross-expected.txt
new file mode 100644
index 0000000..b3bbcb2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.cross-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Resetting the canvas state does not reset the origin-clean flag assert_throws: function "function () { canvas.toDataURL(); }" did not throw
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.cross.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.cross.html
new file mode 100644
index 0000000..617c3404b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.cross.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.reset.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.reset.cross</h1>
+<p class="desc">Resetting the canvas state does not reset the origin-clean flag</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state does not reset the origin-clean flag");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 50;
+ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+canvas.width = 100;
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.redirect-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.redirect-expected.txt
new file mode 100644
index 0000000..b3bbcb2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.redirect-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Resetting the canvas state does not reset the origin-clean flag assert_throws: function "function () { canvas.toDataURL(); }" did not throw
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.redirect.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.redirect.html
new file mode 100644
index 0000000..75b42d90
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.reset.redirect.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.reset.redirect</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>security.reset.redirect</h1>
+<p class="desc">Resetting the canvas state does not reset the origin-clean flag</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Resetting the canvas state does not reset the origin-clean flag");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 50;
+ctx.drawImage(document.getElementById('yellow.png'), 0, 0);
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+canvas.width = 100;
+assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+
+
+});
+</script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="data:text/javascript,addCrossOriginRedirectYellowImage()"></script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.default.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.default.html
new file mode 100644
index 0000000..004636d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.default.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.default</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.default</h1>
+<p class="desc">Default width/height when attributes are missing</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" ><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.default.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Default width/height when attributes are missing");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assert(!canvas.hasAttribute('width'), "!canvas.hasAttribute('width')");
+_assert(!canvas.hasAttribute('height'), "!canvas.hasAttribute('height')");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.default.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.default.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.default.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.get.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.get.png
new file mode 100644
index 0000000..47830c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.get.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.html
new file mode 100644
index 0000000..cd6796e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.idl</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.idl</h1>
+<p class="desc">Getting/setting width/height IDL attributes</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Getting/setting width/height IDL attributes");
+_addTest(function(canvas, ctx) {
+
+canvas.width = "100";
+canvas.height = "100";
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+
+canvas.width = "+1.5e2";
+canvas.height = "0x96";
+_assertSame(canvas.width, 150, "canvas.width", "150");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+
+canvas.width = 200 - Math.pow(2, 32);
+canvas.height = 200 - Math.pow(2, 32);
+_assertSame(canvas.width, 200, "canvas.width", "200");
+_assertSame(canvas.height, 200, "canvas.height", "200");
+
+canvas.width = 301.999;
+canvas.height = 301.001;
+_assertSame(canvas.width, 301, "canvas.width", "301");
+_assertSame(canvas.height, 301, "canvas.height", "301");
+
+canvas.width = "400x";
+canvas.height = "foo";
+_assertSame(canvas.width, 0, "canvas.width", "0");
+_assertSame(canvas.height, 0, "canvas.height", "0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.set.zero.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.set.zero.html
new file mode 100644
index 0000000..a10ac54
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.idl.set.zero.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.idl.set.zero</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.idl.set.zero</h1>
+<p class="desc">Setting width/height IDL attributes to 0</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting width/height IDL attributes to 0");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 0;
+canvas.height = 0;
+_assertSame(canvas.width, 0, "canvas.width", "0");
+_assertSame(canvas.height, 0, "canvas.height", "0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.html
new file mode 100644
index 0000000..ccf579e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.decimal</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.decimal</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100.999" height="100.999"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.decimal.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100.999', "canvas.getAttribute('width')", "'100.999'");
+_assertSame(canvas.getAttribute('height'), '100.999', "canvas.getAttribute('height')", "'100.999'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.decimal.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.html
new file mode 100644
index 0000000..84614691
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.em</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.em</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100em" height="100em"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.em.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100em', "canvas.getAttribute('width')", "'100em'");
+_assertSame(canvas.getAttribute('height'), '100em', "canvas.getAttribute('height')", "'100em'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.em.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.html
new file mode 100644
index 0000000..04a19b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.empty</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.empty</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="" height=""><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.empty.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '', "canvas.getAttribute('width')", "''");
+_assertSame(canvas.getAttribute('height'), '', "canvas.getAttribute('height')", "''");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.empty.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.html
new file mode 100644
index 0000000..7a7c726
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.exp</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.exp</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100e1" height="100e1"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.exp.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100e1', "canvas.getAttribute('width')", "'100e1'");
+_assertSame(canvas.getAttribute('height'), '100e1', "canvas.getAttribute('height')", "'100e1'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.exp.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.hex.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.hex.html
new file mode 100644
index 0000000..7532d775
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.hex.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.hex</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.hex</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="0x100" height="0x100"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 0, "canvas.width", "0");
+_assertSame(canvas.height, 0, "canvas.height", "0");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "0px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"0px\"");
+_assertSame(canvas.getAttribute('width'), '0x100', "canvas.getAttribute('width')", "'0x100'");
+_assertSame(canvas.getAttribute('height'), '0x100', "canvas.getAttribute('height')", "'0x100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.html
new file mode 100644
index 0000000..8dca5ef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.junk</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.junk</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="#!?" height="#!?"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.junk.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '#!?', "canvas.getAttribute('width')", "'#!?'");
+_assertSame(canvas.getAttribute('height'), '#!?', "canvas.getAttribute('height')", "'#!?'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.junk.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.html
new file mode 100644
index 0000000..c901dff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.minus</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.minus</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="-100" height="-100"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.minus.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '-100', "canvas.getAttribute('width')", "'-100'");
+_assertSame(canvas.getAttribute('height'), '-100', "canvas.getAttribute('height')", "'-100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.minus.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.html
new file mode 100644
index 0000000..efdcfeb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.octal</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.octal</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="0100" height="0100"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.octal.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '0100', "canvas.getAttribute('width')", "'0100'");
+_assertSame(canvas.getAttribute('height'), '0100', "canvas.getAttribute('height')", "'0100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.octal.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.html
new file mode 100644
index 0000000..1194858
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.onlyspace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.onlyspace</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="  " height="  "><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.onlyspace.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '  ', "canvas.getAttribute('width')", "'  '");
+_assertSame(canvas.getAttribute('height'), '  ', "canvas.getAttribute('height')", "'  '");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.onlyspace.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.html
new file mode 100644
index 0000000..9073424
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.percent</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.percent</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100%" height="100%"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.percent.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100%', "canvas.getAttribute('width')", "'100%'");
+_assertSame(canvas.getAttribute('height'), '100%', "canvas.getAttribute('height')", "'100%'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.percent.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.html
new file mode 100644
index 0000000..816f381d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.plus</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.plus</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="+100" height="+100"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.plus.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '+100', "canvas.getAttribute('width')", "'+100'");
+_assertSame(canvas.getAttribute('height'), '+100', "canvas.getAttribute('height')", "'+100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.plus.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.html
new file mode 100644
index 0000000..417674d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.space</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.space</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="  100" height="  100"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.space.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '  100', "canvas.getAttribute('width')", "'  100'");
+_assertSame(canvas.getAttribute('height'), '  100', "canvas.getAttribute('height')", "'  100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.space.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.html
new file mode 100644
index 0000000..76c6db0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.trailingjunk</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.trailingjunk</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100#!?" height="100#!?"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.trailingjunk.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100#!?', "canvas.getAttribute('width')", "'100#!?'");
+_assertSame(canvas.getAttribute('height'), '100#!?', "canvas.getAttribute('height')", "'100#!?'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.trailingjunk.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html
new file mode 100644
index 0000000..f4662b45f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.whitespace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.whitespace</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="
+	100" height="
+	100"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.parse.whitespace.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '\n\t\x0c100', "canvas.getAttribute('width')", "'\\n\\t\\x0c100'");
+_assertSame(canvas.getAttribute('height'), '\n\t\x0c100', "canvas.getAttribute('height')", "'\\n\\t\\x0c100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.whitespace.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.zero.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.zero.html
new file mode 100644
index 0000000..e42ebeb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.parse.zero.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.parse.zero</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.parse.zero</h1>
+<p class="desc">Parsing of non-negative integers</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="0" height="0"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 0, "canvas.width", "0");
+_assertSame(canvas.height, 0, "canvas.height", "0");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "0px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"0px\"");
+_assertSame(canvas.getAttribute('width'), '0', "canvas.getAttribute('width')", "'0'");
+_assertSame(canvas.getAttribute('height'), '0', "canvas.getAttribute('height')", "'0'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.html
new file mode 100644
index 0000000..e77ca8ee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.reflect.setcontent</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.reflect.setcontent</h1>
+<p class="desc">Setting content attributes updates IDL and content attributes</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.reflect.setcontent.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting content attributes updates IDL and content attributes");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '120');
+canvas.setAttribute('height', '60');
+_assertSame(canvas.getAttribute('width'), '120', "canvas.getAttribute('width')", "'120'");
+_assertSame(canvas.getAttribute('height'), '60', "canvas.getAttribute('height')", "'60'");
+_assertSame(canvas.width, 120, "canvas.width", "120");
+_assertSame(canvas.height, 60, "canvas.height", "60");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.png
new file mode 100644
index 0000000..47830c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setcontent.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.html
new file mode 100644
index 0000000..1522882
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.reflect.setidl</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.reflect.setidl</h1>
+<p class="desc">Setting IDL attributes updates IDL and content attributes</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.reflect.setidl.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting IDL attributes updates IDL and content attributes");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 120;
+canvas.height = 60;
+_assertSame(canvas.getAttribute('width'), '120', "canvas.getAttribute('width')", "'120'");
+_assertSame(canvas.getAttribute('height'), '60', "canvas.getAttribute('height')", "'60'");
+_assertSame(canvas.width, 120, "canvas.width", "120");
+_assertSame(canvas.height, 60, "canvas.height", "60");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.png
new file mode 100644
index 0000000..47830c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidl.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidlzero.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidlzero.html
new file mode 100644
index 0000000..2bace5a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.reflect.setidlzero.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.reflect.setidlzero</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.reflect.setidlzero</h1>
+<p class="desc">Setting IDL attributes to 0 updates IDL and content attributes</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Setting IDL attributes to 0 updates IDL and content attributes");
+_addTest(function(canvas, ctx) {
+
+canvas.width = 0;
+canvas.height = 0;
+_assertSame(canvas.getAttribute('width'), '0', "canvas.getAttribute('width')", "'0'");
+_assertSame(canvas.getAttribute('height'), '0', "canvas.getAttribute('height')", "'0'");
+_assertSame(canvas.width, 0, "canvas.width", "0");
+_assertSame(canvas.height, 0, "canvas.height", "0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.removed.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.removed.html
new file mode 100644
index 0000000..58fb899
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.removed.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.removed</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.removed</h1>
+<p class="desc">Removing content attributes reverts to default size</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="120" height="60"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.removed.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Removing content attributes reverts to default size");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 120, "canvas.width", "120");
+canvas.removeAttribute('width');
+_assertSame(canvas.width, 300, "canvas.width", "300");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.removed.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.removed.png
new file mode 100644
index 0000000..1ebf30d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.removed.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.set.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.set.png
new file mode 100644
index 0000000..47830c8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.set.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.html
new file mode 100644
index 0000000..0f4fb69f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.decimal</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.decimal</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.decimal.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '100.999');
+canvas.setAttribute('height', '100.999');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100.999', "canvas.getAttribute('width')", "'100.999'");
+_assertSame(canvas.getAttribute('height'), '100.999', "canvas.getAttribute('height')", "'100.999'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.decimal.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.html
new file mode 100644
index 0000000..5768d17
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.em</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.em</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.em.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '100em');
+canvas.setAttribute('height', '100em');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100em', "canvas.getAttribute('width')", "'100em'");
+_assertSame(canvas.getAttribute('height'), '100em', "canvas.getAttribute('height')", "'100em'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.em.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.html
new file mode 100644
index 0000000..65a5bc0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.empty</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.empty</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.empty.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '');
+canvas.setAttribute('height', '');
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '', "canvas.getAttribute('width')", "''");
+_assertSame(canvas.getAttribute('height'), '', "canvas.getAttribute('height')", "''");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.empty.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.html
new file mode 100644
index 0000000..673edad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.exp</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.exp</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.exp.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '100e1');
+canvas.setAttribute('height', '100e1');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100e1', "canvas.getAttribute('width')", "'100e1'");
+_assertSame(canvas.getAttribute('height'), '100e1', "canvas.getAttribute('height')", "'100e1'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.exp.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.hex.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.hex.html
new file mode 100644
index 0000000..e6fde53
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.hex.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.hex</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.hex</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '0x100');
+canvas.setAttribute('height', '0x100');
+_assertSame(canvas.width, 0, "canvas.width", "0");
+_assertSame(canvas.height, 0, "canvas.height", "0");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "0px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"0px\"");
+_assertSame(canvas.getAttribute('width'), '0x100', "canvas.getAttribute('width')", "'0x100'");
+_assertSame(canvas.getAttribute('height'), '0x100', "canvas.getAttribute('height')", "'0x100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.html
new file mode 100644
index 0000000..77b50fd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.junk</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.junk</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.junk.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '#!?');
+canvas.setAttribute('height', '#!?');
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '#!?', "canvas.getAttribute('width')", "'#!?'");
+_assertSame(canvas.getAttribute('height'), '#!?', "canvas.getAttribute('height')", "'#!?'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.junk.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.html
new file mode 100644
index 0000000..2bb09bb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.minus</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.minus</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.minus.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '-100');
+canvas.setAttribute('height', '-100');
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '-100', "canvas.getAttribute('width')", "'-100'");
+_assertSame(canvas.getAttribute('height'), '-100', "canvas.getAttribute('height')", "'-100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.minus.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.html
new file mode 100644
index 0000000..a6cb6d3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.octal</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.octal</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.octal.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '0100');
+canvas.setAttribute('height', '0100');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '0100', "canvas.getAttribute('width')", "'0100'");
+_assertSame(canvas.getAttribute('height'), '0100', "canvas.getAttribute('height')", "'0100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.octal.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.html
new file mode 100644
index 0000000..5e2dd0c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.onlyspace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.onlyspace</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.onlyspace.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '  ');
+canvas.setAttribute('height', '  ');
+_assertSame(canvas.width, 300, "canvas.width", "300");
+_assertSame(canvas.height, 150, "canvas.height", "150");
+_assertSame(canvas.getAttribute('width'), '  ', "canvas.getAttribute('width')", "'  '");
+_assertSame(canvas.getAttribute('height'), '  ', "canvas.getAttribute('height')", "'  '");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.png
new file mode 100644
index 0000000..a72d047
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.onlyspace.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.html
new file mode 100644
index 0000000..2a41c66
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.percent</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.percent</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.percent.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '100%');
+canvas.setAttribute('height', '100%');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100%', "canvas.getAttribute('width')", "'100%'");
+_assertSame(canvas.getAttribute('height'), '100%', "canvas.getAttribute('height')", "'100%'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.percent.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.html
new file mode 100644
index 0000000..f384d82d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.plus</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.plus</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.plus.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '+100');
+canvas.setAttribute('height', '+100');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '+100', "canvas.getAttribute('width')", "'+100'");
+_assertSame(canvas.getAttribute('height'), '+100', "canvas.getAttribute('height')", "'+100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.plus.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.html
new file mode 100644
index 0000000..8f85852
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.space</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.space</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.space.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '  100');
+canvas.setAttribute('height', '  100');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '  100', "canvas.getAttribute('width')", "'  100'");
+_assertSame(canvas.getAttribute('height'), '  100', "canvas.getAttribute('height')", "'  100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.space.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.html
new file mode 100644
index 0000000..f6d06ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.trailingjunk</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.trailingjunk</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.trailingjunk.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '100#!?');
+canvas.setAttribute('height', '100#!?');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '100#!?', "canvas.getAttribute('width')", "'100#!?'");
+_assertSame(canvas.getAttribute('height'), '100#!?', "canvas.getAttribute('height')", "'100#!?'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.trailingjunk.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.html
new file mode 100644
index 0000000..9d85fe7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.whitespace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.whitespace</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.setAttribute.whitespace.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '\n\t\x0c100');
+canvas.setAttribute('height', '\n\t\x0c100');
+_assertSame(canvas.width, 100, "canvas.width", "100");
+_assertSame(canvas.height, 100, "canvas.height", "100");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "100px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"100px\"");
+_assertSame(canvas.getAttribute('width'), '\n\t\x0c100', "canvas.getAttribute('width')", "'\\n\\t\\x0c100'");
+_assertSame(canvas.getAttribute('height'), '\n\t\x0c100', "canvas.getAttribute('height')", "'\\n\\t\\x0c100'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.png
new file mode 100644
index 0000000..f8426733
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.whitespace.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.zero.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.zero.html
new file mode 100644
index 0000000..d1b05ad2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.setAttribute.zero.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.setAttribute.zero</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.setAttribute.zero</h1>
+<p class="desc">Parsing of non-negative integers in setAttribute</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("Parsing of non-negative integers in setAttribute");
+_addTest(function(canvas, ctx) {
+
+canvas.setAttribute('width', '0');
+canvas.setAttribute('height', '0');
+_assertSame(canvas.width, 0, "canvas.width", "0");
+_assertSame(canvas.height, 0, "canvas.height", "0");
+_assertSame(window.getComputedStyle(canvas, null).getPropertyValue("width"), "0px", "window.getComputedStyle(canvas, null).getPropertyValue(\"width\")", "\"0px\"");
+_assertSame(canvas.getAttribute('width'), '0', "canvas.getAttribute('width')", "'0'");
+_assertSame(canvas.getAttribute('height'), '0', "canvas.getAttribute('height')", "'0'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.style.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.style.html
new file mode 100644
index 0000000..3bab3e79
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.style.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: size.attributes.style</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>size.attributes.style</h1>
+<p class="desc">Canvas size is independent of CSS resizing</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="50" height="30" style="width: 100px; height: 50px"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="size.attributes.style.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("Canvas size is independent of CSS resizing");
+_addTest(function(canvas, ctx) {
+
+_assertSame(canvas.width, 50, "canvas.width", "50");
+_assertSame(canvas.height, 30, "canvas.height", "30");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.style.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.style.png
new file mode 100644
index 0000000..eeedd0f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/size.attributes.style.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.jpeg.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.jpeg.html
new file mode 100644
index 0000000..1a95d4a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.jpeg.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Canvas test: toBlob.jpeg</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<canvas id="c"></canvas>
+<script>
+async_test(function() {
+    on_event(window, "load", this.step_func(function() {
+        var canvas = document.getElementById('c');
+        var ctx = canvas.getContext('2d');
+        canvas.toBlob(this.step_func_done(function(data) {
+            assert_equals(data.type, "image/jpeg");
+        }), 'image/jpeg');
+    }));
+}, "toBlob with image/jpeg returns a JPEG Blob");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.null.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.null.html
new file mode 100644
index 0000000..b66153c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.null.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Canvas test: toBlob.null</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toBlob.null</h1>
+<p class="desc">toBlob with zero dimension returns a null Blob</p>
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="0"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+async_test(function() {
+    on_event(window, "load", this.step_func(function() {
+         var toBlobCalled = false;
+         c.toBlob(this.step_func(function(blob) {
+           toBlobCalled = true;
+           _assertSame(blob, null, "blob", "null");
+           c.width = 0;
+           c.height = 100;
+           c.toBlob(this.step_func_done(function(blob) {
+             _assertSame(blob, null, "blob", "null");
+           }), 'image/jpeg');
+         }), 'image/jpeg');
+         assert_false(toBlobCalled, "toBlob callback shouldn't be called synchronously");
+    }));
+}, "toBlob with zero dimension returns a null Blob");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.png.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.png.html
new file mode 100644
index 0000000..1533bfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toBlob.png.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Canvas test: toBlob.png</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<canvas id="c"></canvas>
+<script>
+async_test(function() {
+    on_event(window, "load", this.step_func(function() {
+        var canvas = document.getElementById('c');
+        var ctx = canvas.getContext('2d');
+        canvas.toBlob(this.step_func_done(function(data) {
+            assert_equals(data.type, "image/png");
+        }), 'image/png');
+    }));
+}, "toBlob with image/png returns a PNG Blob");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.1.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.1.html
new file mode 100644
index 0000000..969d4f5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.1.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.arguments.1</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.arguments.1</h1>
+<p class="desc">toDataURL ignores extra arguments</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL ignores extra arguments");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL('image/png', 'another argument that should not raise an exception');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.2.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.2.html
new file mode 100644
index 0000000..3789466
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.2.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.arguments.2</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.arguments.2</h1>
+<p class="desc">toDataURL ignores extra arguments</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL ignores extra arguments");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL('image/png', 'another argument that should not raise an exception', 'and another');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.3.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.3.html
new file mode 100644
index 0000000..236aba5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.arguments.3.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.arguments.3</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.arguments.3</h1>
+<p class="desc">toDataURL ignores extra arguments</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL ignores extra arguments");
+_addTest(function(canvas, ctx) {
+
+// More arguments that should not raise exceptions
+var data = canvas.toDataURL('image/png', null, null, null);
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.bogustype.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.bogustype.html
new file mode 100644
index 0000000..ade95f0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.bogustype.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.bogustype</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.bogustype</h1>
+<p class="desc">toDataURL with a syntactically invalid type returns a PNG</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with a syntactically invalid type returns a PNG");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL('bogus');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.default.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.default.html
new file mode 100644
index 0000000..84f4c9e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.default.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.default</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.default</h1>
+<p class="desc">toDataURL with no arguments returns a PNG</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with no arguments returns a PNG");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL();
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.html
new file mode 100644
index 0000000..80a2fca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.jpeg.alpha</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.jpeg.alpha</h1>
+<p class="desc">toDataURL with JPEG composites onto black</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="toDataURL.jpeg.alpha.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with JPEG composites onto black");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = 'rgba(128, 255, 128, 0.5)';
+ctx.fillRect(0, 0, 100, 50);
+ctx.globalCompositeOperation = 'destination-over'; // should be ignored by toDataURL
+var data = canvas.toDataURL('image/jpeg');
+ctx.globalCompositeOperation = 'source-over';
+if (!data.match(/^data:image\/jpeg[;,]/)) {
+  _assert(true, "true");
+} else {
+  ctx.fillStyle = '#f00';
+  ctx.fillRect(0, 0, 100, 50);
+  var img = new Image();
+  deferTest();
+  img.onload = t.step_func_done(function ()
+  {
+      ctx.drawImage(img, 0, 0);
+      _assertPixelApprox(canvas, 50,25, 63,127,63,255, "50,25", "63,127,63,255", 8);
+  });
+  img.src = data;
+}
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.png
new file mode 100644
index 0000000..551871295
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.alpha.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.html
new file mode 100644
index 0000000..a896cbb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.jpeg.primarycolours</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.jpeg.primarycolours</h1>
+<p class="desc">toDataURL with JPEG handles simple colours correctly</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="toDataURL.jpeg.primarycolours.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with JPEG handles simple colours correctly");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#ff0';
+ctx.fillRect(0, 0, 25, 40);
+ctx.fillStyle = '#0ff';
+ctx.fillRect(25, 0, 50, 40);
+ctx.fillStyle = '#00f';
+ctx.fillRect(75, 0, 25, 40);
+ctx.fillStyle = '#fff';
+ctx.fillRect(0, 40, 100, 10);
+var data = canvas.toDataURL('image/jpeg'); // it is okay if this returns a PNG instead
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 100, 50);
+var img = new Image();
+deferTest();
+img.onload = t.step_func_done(function ()
+{
+    ctx.drawImage(img, 0, 0);
+    _assertPixelApprox(canvas, 12,20, 255,255,0,255, "12,20", "255,255,0,255", 8);
+    _assertPixelApprox(canvas, 50,20, 0,255,255,255, "50,20", "0,255,255,255", 8);
+    _assertPixelApprox(canvas, 87,20, 0,0,255,255, "87,20", "0,0,255,255", 8);
+    _assertPixelApprox(canvas, 50,45, 255,255,255,255, "50,45", "255,255,255,255", 8);
+});
+img.src = data;
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.png
new file mode 100644
index 0000000..cfd13690
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.primarycolours.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.html
new file mode 100644
index 0000000..aad56cd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.jpeg.quality.basic</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.jpeg.quality.basic</h1>
+<p class="desc">toDataURL with JPEG uses the quality parameter</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="toDataURL.jpeg.quality.basic.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with JPEG uses the quality parameter");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#00f';
+ctx.fillRect(0, 0, 100, 50);
+ctx.fillStyle = '#0ff';
+ctx.fillRect(0, 3, 100, 1);
+// Check for JPEG support first
+var data = canvas.toDataURL('image/jpeg');
+if (!data.match(/^data:image\/jpeg[;,]/)) {
+  _assert(true, "true");
+} else {
+  var data_hi = canvas.toDataURL('image/jpeg', 0.99);
+  var data_lo = canvas.toDataURL('image/jpeg', 0.01);
+  ctx.fillStyle = '#f00';
+  ctx.fillRect(0, 0, 100, 50);
+  deferTest();
+  var img_hi = new Image();
+  img_hi.onload = function ()
+  {
+      var img_lo = new Image();
+      img_lo.onload = t.step_func_done(function ()
+      {
+          ctx.drawImage(img_hi, 0, 0, 50, 50, 0, 0, 50, 50);
+          ctx.drawImage(img_lo, 0, 0, 50, 50, 50, 0, 50, 50);
+          _assert(data_hi.length > data_lo.length, "data_hi.length > data_lo.length");
+          _assertPixelApprox(canvas, 25,25, 0,0,255,255, "25,25", "0,0,255,255", 8);
+          _assertPixelApprox(canvas, 75,25, 0,0,255,255, "75,25", "0,0,255,255", 32);
+      });
+      img_lo.src = data_lo;
+  };
+  img_hi.src = data_hi;
+}
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.png
new file mode 100644
index 0000000..2f8a0bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.basic.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.notnumber.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.notnumber.html
new file mode 100644
index 0000000..3167e3c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.notnumber.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.jpeg.quality.notnumber</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.jpeg.quality.notnumber</h1>
+<p class="desc">toDataURL with JPEG handles non-numeric quality parameters</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with JPEG handles non-numeric quality parameters");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#00f';
+ctx.fillRect(0, 0, 100, 50);
+ctx.fillStyle = '#0ff';
+ctx.fillRect(0, 3, 100, 1);
+// Check for JPEG support first
+var data = canvas.toDataURL('image/jpeg');
+if (!data.match(/^data:image\/jpeg[;,]/)) {
+  _assert(true, "true");
+} else {
+    _assertSame(canvas.toDataURL('image/jpeg', 'bogus'), data, "canvas.toDataURL('image/jpeg', 'bogus')", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', {}), data, "canvas.toDataURL('image/jpeg', {})", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', null), data, "canvas.toDataURL('image/jpeg', null)", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', undefined), data, "canvas.toDataURL('image/jpeg', undefined)", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', true), data, "canvas.toDataURL('image/jpeg', true)", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', '0.01'), data, "canvas.toDataURL('image/jpeg', '0.01')", "data");
+}
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.outsiderange.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.outsiderange.html
new file mode 100644
index 0000000..885dc99b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpeg.quality.outsiderange.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.jpeg.quality.outsiderange</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.jpeg.quality.outsiderange</h1>
+<p class="desc">toDataURL with JPEG handles out-of-range quality parameters</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with JPEG handles out-of-range quality parameters");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#00f';
+ctx.fillRect(0, 0, 100, 50);
+ctx.fillStyle = '#0ff';
+ctx.fillRect(0, 3, 100, 1);
+// Check for JPEG support first
+var data = canvas.toDataURL('image/jpeg');
+if (!data.match(/^data:image\/jpeg[;,]/)) {
+  _assert(true, "true");
+} else {
+    _assertSame(canvas.toDataURL('image/jpeg', 10), data, "canvas.toDataURL('image/jpeg', 10)", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', -10), data, "canvas.toDataURL('image/jpeg', -10)", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', 1.01), data, "canvas.toDataURL('image/jpeg', 1.01)", "data");
+    _assertSame(canvas.toDataURL('image/jpeg', -0.01), data, "canvas.toDataURL('image/jpeg', -0.01)", "data");
+
+    _assert(canvas.toDataURL('image/jpeg', 1).length >= canvas.toDataURL('image/jpeg', 0.9).length, "canvas.toDataURL('image/jpeg', 1).length >= canvas.toDataURL('image/jpeg', 0.9).length");
+    _assert(canvas.toDataURL('image/jpeg', 0).length <= canvas.toDataURL('image/jpeg', 0.1).length, "canvas.toDataURL('image/jpeg', 0).length <= canvas.toDataURL('image/jpeg', 0.1).length");
+}
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpg.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpg.html
new file mode 100644
index 0000000..df12aee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.jpg.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.jpg</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.jpg</h1>
+<p class="desc">toDataURL with image/jpg is invalid type hence returns a PNG</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with image/jpg is invalid type hence returns a PNG");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL('image/jpg');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.ascii.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.ascii.html
new file mode 100644
index 0000000..b95c828
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.ascii.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.lowercase.ascii</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.lowercase.ascii</h1>
+<p class="desc">toDataURL type is case-insensitive</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL type is case-insensitive");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL('ImAgE/PnG');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+// If JPEG is supported at all, it must be supported case-insensitively
+data = canvas.toDataURL('image/jpeg');
+if (data.match(/^data:image\/jpeg[;,]/)) {
+    data = canvas.toDataURL('ImAgE/JpEg');
+    assert_regexp_match(data, /^data:image\/jpeg[;,]/);
+}
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.unicode.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.unicode.html
new file mode 100644
index 0000000..ab06d59
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.lowercase.unicode.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.lowercase.unicode</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.lowercase.unicode</h1>
+<p class="desc">toDataURL type is ASCII-case-insensitive</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL type is ASCII-case-insensitive");
+_addTest(function(canvas, ctx) {
+
+// Use LATIN CAPITAL LETTER I WITH DOT ABOVE (Unicode lowercase is "i")
+var data = canvas.toDataURL('\u0130mage/png');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+var data = canvas.toDataURL('\u0130mage/jpeg');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.nocontext.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.nocontext.html
new file mode 100644
index 0000000..fb614a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.nocontext.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.nocontext</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.nocontext</h1>
+<p class="desc">toDataURL works before any context has been got</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL works before any context has been got");
+_addTest(function(canvas, ctx) {
+
+var no_context_data = canvas.toDataURL();
+var ctx = canvas.getContext('2d');
+ctx.rect(0, 0, 100, 50);
+ctx.fillStyle = "rgba(0, 0, 0, 0)";
+ctx.fill();
+var data = canvas.toDataURL();
+assert_equals(no_context_data, data);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.html
new file mode 100644
index 0000000..cc067b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.png.complexcolours</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.png.complexcolours</h1>
+<p class="desc">toDataURL with PNG handles non-primary and non-solid colours correctly</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="toDataURL.png.complexcolours.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with PNG handles non-primary and non-solid colours correctly");
+_addTest(function(canvas, ctx) {
+
+// (These values are chosen to survive relatively alright through being premultiplied)
+ctx.fillStyle = 'rgba(1, 3, 254, 1)';
+ctx.fillRect(0, 0, 25, 25);
+ctx.fillStyle = 'rgba(8, 252, 248, 0.75)';
+ctx.fillRect(25, 0, 25, 25);
+ctx.fillStyle = 'rgba(6, 10, 250, 0.502)';
+ctx.fillRect(50, 0, 25, 25);
+ctx.fillStyle = 'rgba(12, 16, 244, 0.25)';
+ctx.fillRect(75, 0, 25, 25);
+var img = new Image();
+deferTest();
+img.onload = t.step_func_done(function ()
+{
+    ctx.drawImage(img, 0, 25);
+    // (The alpha values do not really survive float->int conversion, so just
+    // do approximate comparisons)
+    _assertPixel(canvas, 12,40, 1,3,254,255, "12,40", "1,3,254,255");
+    _assertPixelApprox(canvas, 37,40, 8,252,248,191, "37,40", "8,252,248,191", 2);
+    _assertPixelApprox(canvas, 62,40, 6,10,250,127, "62,40", "6,10,250,127", 4);
+    _assertPixelApprox(canvas, 87,40, 12,16,244,63, "87,40", "12,16,244,63", 8);
+});
+img.src = canvas.toDataURL();
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.png
new file mode 100644
index 0000000..b5f9c11
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.complexcolours.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.html
new file mode 100644
index 0000000..39917eb2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.png</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.png</h1>
+<p class="desc">toDataURL with image/png returns a PNG</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with image/png returns a PNG");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL('image/png');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.html
new file mode 100644
index 0000000..b962821d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.png.primarycolours</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.png.primarycolours</h1>
+<p class="desc">toDataURL with PNG handles simple colours correctly</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+<p class="output expectedtext">Expected output:<p><img src="toDataURL.png.primarycolours.png" class="output expected" id="expected" alt="">
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with PNG handles simple colours correctly");
+_addTest(function(canvas, ctx) {
+
+ctx.fillStyle = '#ff0';
+ctx.fillRect(0, 0, 25, 40);
+ctx.fillStyle = '#0ff';
+ctx.fillRect(25, 0, 50, 40);
+ctx.fillStyle = '#00f';
+ctx.fillRect(75, 0, 25, 40);
+ctx.fillStyle = '#fff';
+ctx.fillRect(0, 40, 100, 10);
+var data = canvas.toDataURL();
+ctx.fillStyle = '#f00';
+ctx.fillRect(0, 0, 100, 50);
+var img = new Image();
+deferTest();
+img.onload = t.step_func_done(function ()
+{
+    ctx.drawImage(img, 0, 0);
+    _assertPixel(canvas, 12,20, 255,255,0,255, "12,20", "255,255,0,255");
+    _assertPixel(canvas, 50,20, 0,255,255,255, "50,20", "0,255,255,255");
+    _assertPixel(canvas, 87,20, 0,0,255,255, "87,20", "0,0,255,255");
+    _assertPixel(canvas, 50,45, 255,255,255,255, "50,45", "255,255,255,255");
+});
+img.src = data;
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.png b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.png
new file mode 100644
index 0000000..cfd13690
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.png.primarycolours.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.unrecognised.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.unrecognised.html
new file mode 100644
index 0000000..3526cc3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.unrecognised.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.unrecognised</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.unrecognised</h1>
+<p class="desc">toDataURL with an unhandled type returns a PNG</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL with an unhandled type returns a PNG");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL('image/example');
+assert_regexp_match(data, /^data:image\/png[;,]/);
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zeroheight.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zeroheight.html
new file mode 100644
index 0000000..04c1132
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zeroheight.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.zeroheight</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.zeroheight</h1>
+<p class="desc">toDataURL on zero-size canvas returns 'data:,'</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" height="0"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL on zero-size canvas returns 'data:,'");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL();
+_assertSame(data, 'data:,', "data", "'data:,'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zerosize.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zerosize.html
new file mode 100644
index 0000000..7d2913d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zerosize.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.zerosize</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.zerosize</h1>
+<p class="desc">toDataURL on zero-size canvas returns 'data:,'</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="0" height="0"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL on zero-size canvas returns 'data:,'");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL();
+_assertSame(data, 'data:,', "data", "'data:,'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zerowidth.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zerowidth.html
new file mode 100644
index 0000000..d4020aa5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/toDataURL.zerowidth.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: toDataURL.zerowidth</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>toDataURL.zerowidth</h1>
+<p class="desc">toDataURL on zero-size canvas returns 'data:,'</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="0"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("toDataURL on zero-size canvas returns 'data:,'");
+_addTest(function(canvas, ctx) {
+
+var data = canvas.toDataURL();
+_assertSame(data, 'data:,', "data", "'data:,'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.delete.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.delete.html
new file mode 100644
index 0000000..98b67b90
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.delete.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: type.delete</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>type.delete</h1>
+<p class="desc">window.HTMLCanvasElement interface object is [[Configurable]]</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("window.HTMLCanvasElement interface object is [[Configurable]]");
+_addTest(function(canvas, ctx) {
+
+_assertSame(delete window.HTMLCanvasElement, true, "delete window.HTMLCanvasElement", "true");
+_assertSame(window.HTMLCanvasElement, undefined, "window.HTMLCanvasElement", "undefined");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.exists.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.exists.html
new file mode 100644
index 0000000..04aa975
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.exists.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: type.exists</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>type.exists</h1>
+<p class="desc">HTMLCanvasElement is a property of window</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("HTMLCanvasElement is a property of window");
+_addTest(function(canvas, ctx) {
+
+_assert(window.HTMLCanvasElement, "window.HTMLCanvasElement");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.extend.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.extend.html
new file mode 100644
index 0000000..5722730
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.extend.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: type.extend</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>type.extend</h1>
+<p class="desc">HTMLCanvasElement methods can be added, and the new methods used by canvases</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("HTMLCanvasElement methods can be added, and the new methods used by canvases");
+_addTest(function(canvas, ctx) {
+
+window.HTMLCanvasElement.prototype.getZero = function () { return 0; };
+_assertSame(canvas.getZero(), 0, "canvas.getZero()", "0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.name.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.name.html
new file mode 100644
index 0000000..a514eff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.name.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: type.name</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>type.name</h1>
+<p class="desc">HTMLCanvasElement type and toString</p>
+
+
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("HTMLCanvasElement type and toString");
+_addTest(function(canvas, ctx) {
+
+_assertSame(Object.prototype.toString.call(canvas), '[object HTMLCanvasElement]', "Object.prototype.toString.call(canvas)", "'[object HTMLCanvasElement]'");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.prototype.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.prototype.html
new file mode 100644
index 0000000..029a9fb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.prototype.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: type.prototype</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>type.prototype</h1>
+<p class="desc">window.HTMLCanvasElement has prototype, which is { ReadOnly, DontDelete }. prototype has getContext, which is not</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("window.HTMLCanvasElement has prototype, which is { ReadOnly, DontDelete }. prototype has getContext, which is not");
+_addTest(function(canvas, ctx) {
+
+_assert(window.HTMLCanvasElement.prototype, "window.HTMLCanvasElement.prototype");
+_assert(window.HTMLCanvasElement.prototype.getContext, "window.HTMLCanvasElement.prototype.getContext");
+window.HTMLCanvasElement.prototype = null;
+_assert(window.HTMLCanvasElement.prototype, "window.HTMLCanvasElement.prototype");
+delete window.HTMLCanvasElement.prototype;
+_assert(window.HTMLCanvasElement.prototype, "window.HTMLCanvasElement.prototype");
+window.HTMLCanvasElement.prototype.getContext = 1;
+_assertSame(window.HTMLCanvasElement.prototype.getContext, 1, "window.HTMLCanvasElement.prototype.getContext", "1");
+delete window.HTMLCanvasElement.prototype.getContext;
+_assertSame(window.HTMLCanvasElement.prototype.getContext, undefined, "window.HTMLCanvasElement.prototype.getContext", "undefined");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.replace.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.replace.html
new file mode 100644
index 0000000..70a0806
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-canvas-element/type.replace.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: type.replace</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<link rel="stylesheet" href="/common/canvas-tests.css">
+<body class="show_output">
+
+<h1>type.replace</h1>
+<p class="desc">HTMLCanvasElement methods can be replaced, and the replacement methods used by canvases</p>
+
+<p class="notes">Defined in "Web IDL" (draft)
+<p class="output">Actual output:</p>
+<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
+
+<ul id="d"></ul>
+<script>
+var t = async_test("HTMLCanvasElement methods can be replaced, and the replacement methods used by canvases");
+_addTest(function(canvas, ctx) {
+
+window.HTMLCanvasElement.prototype.getContext = function (name) { return 0; };
+_assertSame(canvas.getContext('2d'), 0, "canvas.getContext('2d')", "0");
+
+
+});
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-dimension.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-dimension.html
new file mode 100644
index 0000000..608ed331
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-dimension.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: dimension</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-embed-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<embed src="/images/blue.png" height="100" width="100" id="test">
+<script>
+  test(function () {
+    var height = getComputedStyle(document.getElementById("test"), false)["height"];
+    assert_equals(height, "100px", "The height of the embed element should be 100px.");
+  }, "Check the actual length of the embed element's height");
+
+  test(function () {
+    var width = getComputedStyle(document.getElementById("test"), false)["width"];
+    assert_equals(width, "100px", "The width of the embed element should be 100px.");
+  }, "Check the actual length of the embed element's width");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html
new file mode 100644
index 0000000..65cd672
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: The embed element represents nothing when its type and src attributs are removed</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-embed-element">
+<link rel="match" href="embed-represent-nothing-ref.html">
+<meta name="assert" content="Check if the embed element represents nothing when its src and type attributes are removed">
+<style>
+  embed {
+    background-color: red;
+    height: 100px;
+    width: 100px;
+  }
+</style>
+<body>
+  <p>Test passes if there is <strong>no red</strong>.</p>
+  <embed id="embed" src="/images/red-16x16.png" type="image/png">
+  <script>
+    document.getElementById("embed").removeAttribute("src");
+    document.getElementById("embed").removeAttribute("type");
+  </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-03.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-03.html
new file mode 100644
index 0000000..a16f3794
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-03.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: The embed element represents nothing when it has a media ancestor</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-embed-element">
+<link rel="match" href="embed-represent-nothing-ref.html">
+<meta name="assert" content="Check if the embed element represents nothing when it has a media ancestor">
+<style>
+  embed {
+    background-color: red;
+    height: 100px;
+    width: 100px;
+  }
+</style>
+<body>
+  <p>Test passes if there is <strong>no red</strong>.</p>
+  <video>
+    <embed src="/images/red-16x16.png">
+  </video>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html
new file mode 100644
index 0000000..7cc1b668a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: The embed element represents nothing when it has an object ancestor</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-embed-element">
+<link rel="match" href="embed-represent-nothing-ref.html">
+<meta name="assert" content="Check if the embed element represents nothing when it has a object ancestor that is not showing its fallback content">
+<style>
+  embed {
+    background-color: red;
+    height: 100px;
+    width: 100px;
+  }
+</style>
+<body>
+  <p>Test passes if there is <strong>no red</strong>.</p>
+  <object type="application/x-shockwave-flash">
+    <embed src="/images/red-16x16.png">
+  </object>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic-expected.txt
new file mode 100644
index 0000000..04456175
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS <img src="/images/green-256x256.png" data-expect="256">
+PASS <img srcset="/images/green-256x256.png 1x" data-expect="256">
+PASS <img srcset="/images/green-256x256.png 1.6x" data-expect="160">
+PASS <img srcset="/images/green-256x256.png 2x" data-expect="128">
+FAIL <img srcset="/images/green-256x256.png 10000x" data-expect="0"> assert_equals: naturalWidth expected 0 but got 1
+PASS <img srcset="/images/green-256x256.png 9e99999999999999999999999x" data-expect="0">
+PASS <img srcset="/images/green-256x256.png 256w" sizes="256px" data-expect="256">
+PASS <img srcset="/images/green-256x256.png 512w" sizes="256px" data-expect="128">
+PASS <img srcset="/images/green-256x256.png 256w" sizes="512px" data-expect="512">
+PASS <img srcset="/images/green-256x256.png 256w" sizes="1px" data-expect="1">
+FAIL <img srcset="/images/green-256x256.png 256w" sizes="0px" data-expect="0"> assert_equals: naturalWidth expected 0 but got 1
+PASS <img srcset="data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='-1%20-1%202%202'%20width='20'%20height='20'><circle%20r='1'/></svg> 2x" data-expect="10">
+PASS <img srcset="data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='-1%20-1%202%202'%20width='20'><circle%20r='1'/></svg> 2x" data-expect="10">
+PASS <img srcset="data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='-1%20-1%202%202'%20height='20'><circle%20r='1'/></svg> 2x" data-expect="10">
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html
new file mode 100644
index 0000000..f7d47b3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>img current pixel density basic</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<img src="/images/green-256x256.png" data-expect="256">
+<img srcset="/images/green-256x256.png 1x" data-expect="256">
+<img srcset="/images/green-256x256.png 1.6x" data-expect="160">
+<img srcset="/images/green-256x256.png 2x" data-expect="128">
+<img srcset="/images/green-256x256.png 10000x" data-expect="0">
+<img srcset="/images/green-256x256.png 9e99999999999999999999999x" data-expect="0">
+<img srcset="/images/green-256x256.png 256w" sizes="256px" data-expect="256">
+<img srcset="/images/green-256x256.png 512w" sizes="256px" data-expect="128">
+<img srcset="/images/green-256x256.png 256w" sizes="512px" data-expect="512">
+<img srcset="/images/green-256x256.png 256w" sizes="1px" data-expect="1">
+<img srcset="/images/green-256x256.png 256w" sizes="0px" data-expect="0">
+<!-- SVG -->
+<img srcset="data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='-1%20-1%202%202'%20width='20'%20height='20'><circle%20r='1'/></svg> 2x" data-expect="10">
+<img srcset="data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='-1%20-1%202%202'%20width='20'><circle%20r='1'/></svg> 2x" data-expect="10">
+<img srcset="data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='-1%20-1%202%202'%20height='20'><circle%20r='1'/></svg> 2x" data-expect="10">
+<script>
+setup({explicit_done:true});
+onload = function() {
+  [].forEach.call(document.images, function(img) {
+    test(function() {
+      var expected = parseFloat(img.dataset.expect);
+      assert_equals(img.width, expected, 'width');
+      assert_equals(img.height, expected, 'height');
+      assert_equals(img.clientWidth, expected, 'clientWidth');
+      assert_equals(img.clientHeight, expected, 'clientHeight');
+      assert_equals(img.naturalWidth, expected, 'naturalWidth');
+      assert_equals(img.naturalHeight, expected, 'naturalHeight');
+    }, img.outerHTML);
+  });
+  done();
+};
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change-expected.txt
new file mode 100644
index 0000000..be103ff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change-expected.txt
@@ -0,0 +1,47 @@
+This is a testharness.js-based test.
+PASS img (no src), onload, narrow
+PASS img (no src), resize to wide
+PASS img (empty src), onload, narrow
+PASS img (empty src), resize to wide
+PASS img (src only) broken image, onload, narrow
+PASS img (src only) broken image, resize to wide
+PASS img (src only) valid image, onload, narrow
+PASS img (src only) valid image, resize to wide
+PASS img (srcset 1 cand) broken image, onload, narrow
+PASS img (srcset 1 cand) broken image, resize to wide
+PASS img (srcset 1 cand) valid image, onload, narrow
+PASS img (srcset 1 cand) valid image, resize to wide
+PASS picture: source (max-width:500px) broken image, img broken image, onload, narrow
+PASS picture: source (max-width:500px) broken image, img broken image, resize to wide
+PASS picture: source (max-width:500px) broken image, img valid image, onload, narrow
+PASS picture: source (max-width:500px) broken image, img valid image, resize to wide
+PASS picture: source (max-width:500px) valid image, img broken image, onload, narrow
+PASS picture: source (max-width:500px) valid image, img broken image, resize to wide
+PASS picture: source (max-width:500px) valid image, img valid image, onload, narrow
+PASS picture: source (max-width:500px) valid image, img valid image, resize to wide
+PASS picture: same URL in source (max-width:500px) and img, onload, narrow
+FAIL picture: same URL in source (max-width:500px) and img, resize to wide assert_unreached: Got unexpected load event Reached unreachable code
+PASS img (no src), onload, wide
+PASS img (no src), resize to narrow
+PASS img (empty src), onload, wide
+PASS img (empty src), resize to narrow
+PASS img (src only) broken image, onload, wide
+PASS img (src only) broken image, resize to narrow
+PASS img (src only) valid image, onload, wide
+PASS img (src only) valid image, resize to narrow
+PASS img (srcset 1 cand) broken image, onload, wide
+PASS img (srcset 1 cand) broken image, resize to narrow
+PASS img (srcset 1 cand) valid image, onload, wide
+PASS img (srcset 1 cand) valid image, resize to narrow
+PASS picture: source (max-width:500px) broken image, img broken image, onload, wide
+PASS picture: source (max-width:500px) broken image, img broken image, resize to narrow
+PASS picture: source (max-width:500px) broken image, img valid image, onload, wide
+PASS picture: source (max-width:500px) broken image, img valid image, resize to narrow
+PASS picture: source (max-width:500px) valid image, img broken image, onload, wide
+PASS picture: source (max-width:500px) valid image, img broken image, resize to narrow
+PASS picture: source (max-width:500px) valid image, img valid image, onload, wide
+PASS picture: source (max-width:500px) valid image, img valid image, resize to narrow
+PASS picture: same URL in source (max-width:500px) and img, onload, wide
+FAIL picture: same URL in source (max-width:500px) and img, resize to narrow assert_unreached: Got unexpected load event Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html
new file mode 100644
index 0000000..2162471
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/environment-changes/viewport-change.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<title>img viewport change</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<style>
+.narrow { width:50px }
+.wide { width:1000px }
+</style>
+<div id=log></div>
+<script>
+setup({explicit_done:true});
+
+function resolve(url) {
+  if (url === "") {
+    return url;
+  }
+  var a = document.createElement('a');
+  a.href = url;
+  return a.href;
+}
+
+function insertIframe(className) {
+  var iframe = document.createElement('iframe');
+  iframe.className = className;
+  iframe.src = 'iframed.sub.html?id=' + token();
+  document.body.appendChild(iframe);
+}
+insertIframe('narrow');
+insertIframe('wide');
+
+var start_date = new Date();
+
+onload = function() {
+  var load_time = new Date() - start_date;
+  var iframes = document.getElementsByTagName('iframe');
+  [].forEach.call(iframes, function(iframe) {
+    [].forEach.call(iframe.contentDocument.images, function(img) {
+      var expected = {wide:resolve(img.dataset.wide), narrow:resolve(img.dataset.narrow)};
+      var current = iframe.className;
+      var next = current === 'wide' ? 'narrow' : 'wide';
+      var expect_change = expected[next].indexOf('broken.png') !== 0 && !('noChange' in img.dataset);
+
+      test(function() {
+        assert_equals(img.currentSrc, expected[current]);
+      }, img.dataset.desc + ', onload, ' + current);
+
+      async_test(function() {
+        img.onload = this.unreached_func('Got unexpected load event');
+        img.onerror = this.unreached_func('Got unexpected error event');
+        if (expect_change) {
+          img.onload = this.step_func_done(function() {
+            assert_equals(img.currentSrc, expected[next]);
+          });
+        } else {
+          setTimeout(this.step_func_done(), 500 + load_time);
+        }
+      }, img.dataset.desc + ', resize to ' + next);
+    });
+    iframe.classList.toggle('wide');
+    iframe.classList.toggle('narrow');
+  });
+  done();
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/relevant-mutations.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/relevant-mutations.html
new file mode 100644
index 0000000..c8e09e8d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/relevant-mutations.html
@@ -0,0 +1,416 @@
+<!doctype html>
+<title>img relevant mutations</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+
+<!-- should invoke update the image data -->
+
+<img data-desc="src set">
+<img src="/images/green-2x2.png" data-desc="src changed">
+<img src="/images/green-2x2.png" data-desc="src removed">
+
+<img data-desc="srcset set">
+<img srcset="/images/green-2x2.png" data-desc="srcset changed">
+<img srcset="/images/green-2x2.png" data-desc="srcset removed">
+
+<img data-desc="sizes set">
+<img sizes="" data-desc="sizes changed">
+<img sizes="" data-desc="sizes removed">
+
+<img src="/images/green-2x2.png" data-desc="src set to same value">
+
+<img data-desc="crossorigin absent to empty">
+<img data-desc="crossorigin absent to anonymous">
+<img data-desc="crossorigin absent to use-credentials">
+<img crossorigin data-desc="crossorigin empty to absent">
+<img crossorigin data-desc="crossorigin empty to use-credentials">
+<img crossorigin=anonymous data-desc="crossorigin anonymous to absent">
+<img crossorigin=anonymous data-desc="crossorigin anonymous to use-credentials">
+<img crossorigin=use-credentials data-desc="crossorigin use-credentials to absent">
+<img crossorigin=use-credentials data-desc="crossorigin use-credentials to empty">
+<img crossorigin=use-credentials data-desc="crossorigin use-credentials to anonymous">
+
+<img src="/images/green-2x2.png" data-desc="inserted into picture"><picture></picture>
+
+<picture><img src="/images/green-2x2.png" data-desc="removed from picture"></picture>
+
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, previous source inserted"></picture>
+
+<picture><source><img src="/images/green-2x2.png" data-desc="parent is picture, previous source removed"></picture>
+
+<picture><source><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has srcset set"></picture>
+<picture><source srcset=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has srcset changed"></picture>
+<picture><source srcset=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has srcset removed"></picture>
+
+<picture><source><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has sizes set"></picture>
+<picture><source sizes=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has sizes changed"></picture>
+<picture><source sizes=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has sizes removed"></picture>
+
+<picture><source><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has media set"></picture>
+<picture><source media=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has media changed"></picture>
+<picture><source media=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has media removed"></picture>
+
+<picture><source><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has type set"></picture>
+<picture><source type=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has type changed"></picture>
+<picture><source type=""><img src="/images/green-2x2.png" data-desc="parent is picture, previous source has type removed"></picture>
+
+<!-- should not invoke update the image data -->
+
+<img srcset="/images/green-2x2.png" data-desc="srcset is set to same value">
+<img srcset="/images/green-2x2.png" sizes data-desc="sizes is set to same value">
+
+<img src="/images/green-2x2.png" data-desc="crossorigin state not changed: absent, removeAttribute">
+<img src="/images/green-2x2.png" crossorigin data-desc="crossorigin state not changed: empty to anonymous">
+<img src="/images/green-2x2.png" crossorigin=anonymous data-desc="crossorigin state not changed: anonymous to foobar">
+<img src="/images/green-2x2.png" crossorigin=use-credentials data-desc="crossorigin state not changed: use-credentials to USE-CREDENTIALS">
+
+<img src="/images/green-2x2.png" data-desc="inserted into picture ancestor"><picture><span></span></picture>
+<picture><span><img src="/images/green-2x2.png" data-desc="removed from picture ancestor"></span></picture>
+
+<picture><span><img src="/images/green-2x2.png" data-desc="ancestor picture has a source inserted"></span></picture>
+<picture><source><span><img src="/images/green-2x2.png" data-desc="ancestor picture has a source removed"></span></picture>
+
+<picture><span><img src="/images/green-2x2.png" data-desc="ancestor picture; previous sibling source inserted"></span></picture>
+<picture><span><source><img src="/images/green-2x2.png" data-desc="ancestor picture; previous sibling source removed"></span></picture>
+
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following sibling source inserted"></picture>
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following sibling source removed"><source></picture>
+
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following sibling source has srcset set"><source></picture>
+
+<img src="/images/green-2x2.png" data-desc="media on img set">
+<img src="/images/green-2x2.png" data-desc="type on img set">
+<img src="/images/green-2x2.png" data-desc="class on img set">
+<img src="/images/green-2x2.png" data-desc="alt on img set">
+
+<picture><source><img src="/images/green-2x2.png" data-desc="src on previous sibling source set"></picture>
+<picture><source><img src="/images/green-2x2.png" data-desc="class on previous sibling source set"></picture>
+
+<img src="/images/green-2x2.png" data-desc="inserted/removed children of img">
+
+<picture><img src="/images/green-2x2.png" data-desc="picture is inserted; img has src"></picture><span></span>
+<picture><img srcset="/images/green-2x2.png" data-desc="picture is inserted; img has srcset"></picture><span></span>
+<picture><source srcset="/images/green-2x2.png"><img src="/images/green-2x2.png" data-desc="picture is inserted; img has previous sibling source"></picture><span></span>
+<picture><img src="/images/green-2x2.png" data-desc="picture is inserted; img has following sibling source"><source srcset="/images/green-2x2.png"></picture><span></span>
+
+<picture><img src="/images/green-2x2.png" data-desc="picture is removed; img has src"></picture>
+<picture><img srcset="/images/green-2x2.png" data-desc="picture is removed; img has srcset"></picture>
+<picture><source srcset="/images/green-2x2.png"><img src="/images/green-2x2.png" data-desc="picture is removed; img has previous sibling source"></picture>
+<picture><img src="/images/green-2x2.png" data-desc="picture is removed; img has following sibling source"><source srcset="/images/green-2x2.png"></picture>
+
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following img inserted"></picture>
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following img removed"><img></picture>
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following img has src set"><img></picture>
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following img has srcset set"><img></picture>
+<picture><img src="/images/green-2x2.png" data-desc="parent is picture, following img has sizes set"><img></picture>
+
+
+<script>
+setup({explicit_done:true});
+
+function t(desc, func, expect) {
+  async_test(function() {
+    var img = document.querySelector('[data-desc="' + desc + '"]');
+    img.onload = img.onerror = this.unreached_func('update the image data was run');
+    if (expect == 'timeout') {
+      setTimeout(this.step_func_done(), 1000);
+    } else {
+      img['on' + expect] = this.step_func_done(function() {});
+    }
+    func.call(this, img);
+  }, desc);
+}
+
+onload = function() {
+
+  t('src set', function(img) {
+    img.src = '/images/green-2x2.png';
+  }, 'load');
+
+  t('src changed', function(img) {
+    img.src = '/images/green-2x2.png ';
+  }, 'load');
+
+  t('src removed', function(img) {
+    img.removeAttribute('src');
+  }, 'timeout');
+
+  t('srcset set', function(img) {
+    img.srcset = '/images/green-2x2.png';
+  }, 'load');
+
+  t('srcset changed', function(img) {
+    img.srcset = '/images/green-2x2.png ';
+  }, 'load');
+
+  t('srcset removed', function(img) {
+    img.removeAttribute('srcset');
+  }, 'timeout');
+
+  t('sizes set', function(img) {
+    img.sizes = '';
+  }, 'timeout');
+
+  t('sizes changed', function(img) {
+    img.sizes = ' ';
+  }, 'timeout');
+
+  t('sizes removed', function(img) {
+    img.removeAttribute('sizes');
+  }, 'timeout');
+
+  t('src set to same value', function(img) {
+    img.src = '/images/green-2x2.png';
+  }, 'load');
+
+  t('crossorigin absent to empty', function(img) {
+    img.crossOrigin = '';
+  }, 'timeout');
+
+  t('crossorigin absent to anonymous', function(img) {
+    img.crossOrigin = 'anonymous';
+  }, 'timeout');
+
+  t('crossorigin absent to use-credentials', function(img) {
+    img.crossOrigin = 'use-credentials';
+  }, 'timeout');
+
+  t('crossorigin empty to absent', function(img) {
+    img.removeAttribute('crossorigin');
+  }, 'timeout');
+
+  t('crossorigin empty to use-credentials', function(img) {
+    img.crossOrigin = 'use-credentials';
+  }, 'timeout');
+
+  t('crossorigin anonymous to absent', function(img) {
+    img.removeAttribute('crossorigin');
+  }, 'timeout');
+
+  t('crossorigin anonymous to use-credentials', function(img) {
+    img.crossOrigin = 'use-credentials';
+  }, 'timeout');
+
+  t('crossorigin use-credentials to absent', function(img) {
+    img.removeAttribute('crossorigin');
+  }, 'timeout');
+
+  t('crossorigin use-credentials to empty', function(img) {
+    img.crossOrigin = '';
+  }, 'timeout');
+
+  t('crossorigin use-credentials to anonymous', function(img) {
+    img.crossOrigin = 'anonymous';
+  }, 'timeout');
+
+  t('inserted into picture', function(img) {
+    img.nextSibling.appendChild(img);
+  }, 'load');
+
+  t('removed from picture', function(img) {
+    img.parentNode.removeChild(img);
+  }, 'load');
+
+  t('parent is picture, previous source inserted', function(img) {
+    img.parentNode.insertBefore(document.createElement('source'), img);
+  }, 'load');
+
+  t('parent is picture, previous source removed', function(img) {
+    img.parentNode.removeChild(img.previousSibling);
+  }, 'load');
+
+  t('parent is picture, previous source has srcset set', function(img) {
+    img.previousSibling.srcset = '';
+  }, 'load');
+
+  t('parent is picture, previous source has srcset changed', function(img) {
+    img.previousSibling.srcset = ' ';
+  }, 'load');
+
+  t('parent is picture, previous source has srcset removed', function(img) {
+    img.previousSibling.removeAttribute('srcset');
+  }, 'load');
+
+  t('parent is picture, previous source has sizes set', function(img) {
+    img.previousSibling.sizes = '';
+  }, 'load');
+
+  t('parent is picture, previous source has sizes changed', function(img) {
+    img.previousSibling.sizes = ' ';
+  }, 'load');
+
+  t('parent is picture, previous source has sizes removed', function(img) {
+    img.previousSibling.removeAttribute('sizes');
+  }, 'load');
+
+  t('parent is picture, previous source has media set', function(img) {
+    img.previousSibling.media = '';
+  }, 'load');
+
+  t('parent is picture, previous source has media changed', function(img) {
+    img.previousSibling.media = ' ';
+  }, 'load');
+
+  t('parent is picture, previous source has media removed', function(img) {
+    img.previousSibling.removeAttribute('media');
+  }, 'load');
+
+  t('parent is picture, previous source has type set', function(img) {
+    img.previousSibling.type = '';
+  }, 'load');
+
+  t('parent is picture, previous source has type changed', function(img) {
+    img.previousSibling.type = ' ';
+  }, 'load');
+
+  t('parent is picture, previous source has type removed', function(img) {
+    img.previousSibling.removeAttribute('type');
+  }, 'load');
+
+  t('srcset is set to same value', function(img) {
+    img.srcset = "/images/green-2x2.png";
+  }, 'timeout');
+
+  t('sizes is set to same value', function(img) {
+    img.sizes = '';
+  }, 'timeout');
+
+  t('crossorigin state not changed: absent, removeAttribute', function(img) {
+    img.removeAttribute('crossorigin');
+  }, 'timeout');
+
+  t('crossorigin state not changed: empty to anonymous', function(img) {
+    img.crossOrigin = 'anonymous';
+  }, 'timeout');
+
+  t('crossorigin state not changed: anonymous to foobar', function(img) {
+    img.crossOrigin = 'foobar';
+  }, 'timeout');
+
+  t('crossorigin state not changed: use-credentials to USE-CREDENTIALS', function(img) {
+    img.crossOrigin = 'USE-CREDENTIALS';
+  }, 'timeout');
+
+  t('inserted into picture ancestor', function(img) {
+    img.nextSibling.firstChild.appendChild(img);
+  }, 'timeout');
+
+  t('removed from picture ancestor', function(img) {
+    img.parentNode.removeChild(img);
+  }, 'timeout');
+
+  t('ancestor picture has a source inserted', function(img) {
+    img.parentNode.parentNode.insertBefore(document.createElement('source'), img.parentNode);
+  }, 'timeout');
+
+  t('ancestor picture has a source removed', function(img) {
+    img.parentNode.parentNode.removeChild(img.parentNode.previousSibling);
+  }, 'timeout');
+
+  t('ancestor picture; previous sibling source inserted', function(img) {
+    img.parentNode.insertBefore(document.createElement('source'), img);
+  }, 'timeout');
+
+  t('ancestor picture; previous sibling source removed', function(img) {
+    img.parentNode.removeChild(img.previousSibling);
+  }, 'timeout');
+
+  t('parent is picture, following sibling source inserted', function(img) {
+    img.parentNode.appendChild(document.createElement('source'));
+  }, 'timeout');
+
+  t('parent is picture, following sibling source removed', function(img) {
+    img.parentNode.removeChild(img.nextSibling);
+  }, 'timeout');
+
+  t('parent is picture, following sibling source has srcset set', function(img) {
+    img.nextSibling.srcset = '';
+  }, 'timeout');
+
+  t('media on img set', function(img) {
+    img.setAttribute('media', '');
+  }, 'timeout');
+
+  t('type on img set', function(img) {
+    img.setAttribute('type', '');
+  }, 'timeout');
+
+  t('class on img set', function(img) {
+    img.className = '';
+  }, 'timeout');
+
+  t('alt on img set', function(img) {
+    img.alt = '';
+  }, 'timeout');
+
+  t('src on previous sibling source set', function(img) {
+    img.previousSibling.setAttribute('src', '');
+  }, 'timeout');
+
+  t('class on previous sibling source set', function(img) {
+    img.previousSibling.className = '';
+  }, 'timeout');
+
+  t('inserted/removed children of img', function(img) {
+    img.appendChild(document.createElement('source'));
+    setTimeout(this.step_func(function() {
+      img.removeChild(img.firstChild);
+    }), 0);
+  }, 'timeout');
+
+  t('picture is inserted; img has src', function(img) {
+    img.parentNode.nextSibling.appendChild(img.parentNode);
+  }, 'timeout');
+
+  t('picture is inserted; img has srcset', function(img) {
+    img.parentNode.nextSibling.appendChild(img.parentNode);
+  }, 'timeout');
+
+  t('picture is inserted; img has previous sibling source', function(img) {
+    img.parentNode.nextSibling.appendChild(img.parentNode);
+  }, 'timeout');
+
+  t('picture is inserted; img has following sibling source', function(img) {
+    img.parentNode.nextSibling.appendChild(img.parentNode);
+  }, 'timeout');
+
+  t('picture is removed; img has src', function(img) {
+    img.parentNode.parentNode.removeChild(img.parentNode);
+  }, 'timeout');
+
+  t('picture is removed; img has srcset', function(img) {
+    img.parentNode.parentNode.removeChild(img.parentNode);
+  }, 'timeout');
+
+  t('picture is removed; img has previous sibling source', function(img) {
+    img.parentNode.parentNode.removeChild(img.parentNode);
+  }, 'timeout');
+
+  t('picture is removed; img has following sibling source', function(img) {
+    img.parentNode.parentNode.removeChild(img.parentNode);
+  }, 'timeout');
+
+  t('parent is picture, following img inserted', function(img) {
+    img.parentNode.appendChild(document.createElement('img'));
+  }, 'timeout');
+
+  t('parent is picture, following img removed', function(img) {
+    img.parentNode.removeChild(img.nextSibling);
+  }, 'timeout');
+
+  t('parent is picture, following img has src set', function(img) {
+    img.nextSibling.src = '';
+  }, 'timeout');
+
+  t('parent is picture, following img has srcset set', function(img) {
+    img.nextSibling.srcset = '';
+  }, 'timeout');
+
+  t('parent is picture, following img has sizes set', function(img) {
+    img.nextSibling.sizes = '';
+  }, 'timeout');
+
+  done();
+};
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-events.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-events.html
new file mode 100644
index 0000000..4ead6f56
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-events.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: object-events</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+
+async_test(function(t) {
+  var obj = document.createElement("object");
+  obj.onerror = t.step_func_done(function(e){
+    assert_equals(Object.getPrototypeOf(e).constructor, Event, "The error event should use the Event interface.");
+    assert_true(e.isTrusted, "The error event should be a trusted event.");
+    assert_false(e.cancelable, "The error event should not be a cancelable event.");
+    assert_false(e.bubbles, "The error event should not be a bubble event.");
+    assert_equals(e.target, obj, "The error event target should be the corresponding object element.");
+  });
+
+  obj.onload = t.step_func_done(function(e){
+    assert_unreached("The load event should not be fired.");
+  });
+
+  obj.data = "file:\\http://nonexistent.html";
+  document.body.appendChild(obj);
+}, "error event (using 'file:' protocol)");
+
+async_test(function(t) {
+  var obj = document.createElement("object");
+  obj.onerror = t.step_func_done(function(e){
+    assert_equals(e.target, obj,
+                  "The error event should be fired on our element");
+  });
+  obj.onload = t.step_func_done(function(e){
+    assert_unreached("The load event should not be fired.");
+  });
+
+  obj.data = "http://test:test";
+  document.body.appendChild(obj);
+}, "error event (using 'http:' protocol)");
+
+
+async_test(function(t) {
+  var obj = document.createElement("object");
+  obj.onload = t.step_func_done(function(e){
+    assert_equals(Object.getPrototypeOf(e).constructor, Event, "The load event should use the Event interface.");
+    assert_true(e.isTrusted, "The load event should be a trusted event.");
+    assert_false(e.cancelable, "The load event should not be a cancelable event.");
+    assert_false(e.bubbles, "The load event should not be a bubble event.");
+    assert_equals(e.target, obj, "The load event target should be the corresponding object element.");
+  });
+
+  obj.onerror = t.step_func_done(function(e){
+    assert_unreached("The error event should not be fired.");
+  });
+
+  obj.data = "/images/blue.png";
+  document.body.appendChild(obj);
+}, "load event");
+
+async_test(function(t) {
+  var obj = document.createElement("object");
+  obj.onload = t.step_func_done(function(e){
+    assert_true(obj.contentWindow instanceof Window, "The object element should represent a nested browsing context.")
+    assert_equals(Object.getPrototypeOf(e).constructor, Event, "The load event should use the Event interface.");
+    assert_true(e.isTrusted, "The load event should be a trusted event.");
+    assert_false(e.cancelable, "The load event should not be a cancelable event.");
+    assert_false(e.bubbles, "The load event should not be a bubble event.");
+    assert_equals(e.target, obj, "The load event target should be the corresponding object element.");
+  });
+
+  obj.onerror = t.step_func_done(function(e){
+    assert_unreached("The error event should not be fired.");
+  });
+
+  obj.data = "about:blank";
+  document.body.appendChild(obj);
+}, "load event of about:blank");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback-expected.txt
new file mode 100644
index 0000000..4a7c309
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL the typemustmatch attribute is specified assert_true: typeMustMatch is not supported. expected true got false
+PASS the typemustmatch attribute is not specified
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback.html
new file mode 100644
index 0000000..d5469a3e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/object-fallback.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: display fallback content</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+var t1 = async_test("the typemustmatch attribute is specified");
+var t2 = async_test("the typemustmatch attribute is not specified");
+
+</script>
+<body onload="t1.done(); t2.done()">
+<object id="obj"></object>
+<div id="log"></div>
+<script>
+
+t1.step(function() {
+  var obj1 = document.createElement("object");
+  obj1.setAttribute("data", "/images/blue.png");
+  obj1.setAttribute("type", "text/plain");
+  obj1.setAttribute("typemustmatch", "");
+  obj1.onload = t1.step_func(function () {
+    assert_true("typeMustMatch" in obj1, "typeMustMatch is not supported.");
+    assert_unreached("The image of the first object should not be loaded.");
+  });
+  document.getElementById("obj").appendChild(obj1);
+});
+
+t2.step(function () {
+  var obj2 = document.createElement("object");
+  obj2.setAttribute("data", "test2.html");
+  obj2.setAttribute("type", "text/plain");
+  obj2.onload = t2.step_func( function () {
+    assert_not_equals(obj2.contentDocument, null, "The test2.html should be loaded.");
+  });
+  document.getElementById("obj").appendChild(obj2);
+});
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_absolute.htm b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_absolute.htm
new file mode 100644
index 0000000..bec2b0fb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_absolute.htm
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<meta charset=UTF-8>
+<title>The 'HTMLVideoElement' interface supports setting 'poster' to an absolute URL</title>
+<link rel="author" title="Microsoft" href="http://www.microsoft.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-video-poster">
+<link rel="match" href="video_dynamic_poster-ref.htm">
+<meta name="assert" content="The 'HTMLVideoElement' interface supports setting 'poster' to an absolute URL">
+<video id="video0">Your browser does not support video.</video>
+<script>
+var testElem = document.getElementById("video0");
+testElem.poster = "/media/poster.png";
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_relative.htm b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_relative.htm
new file mode 100644
index 0000000..4faca61
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_dynamic_poster_relative.htm
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<meta charset=UTF-8>
+<title>The 'HTMLVideoElement' interface supports setting 'poster' to a relative URL</title>
+<link rel="author" title="Microsoft" href="http://www.microsoft.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-video-poster">
+<link rel="match" href="video_dynamic_poster-ref.htm">
+<meta name="assert" content="The 'HTMLVideoElement' interface supports setting 'poster' to a relative URL">
+<video id="video0">Your browser does not support video.</video>
+<script>
+var testElem = document.getElementById("video0");
+testElem.poster = "../../../../media/poster.png";
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_initially_paused.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_initially_paused.html
new file mode 100644
index 0000000..b2725b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-video-element/video_initially_paused.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<meta charset=UTF-8>
+<title>Video elements should initially be paused</title>
+<link rel="match" href="video_initially_paused-ref.html">
+<link rel="author" title="Microsoft" href="http://www.microsoft.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-paused">
+<script src="/common/media.js"></script>
+<style>
+div#video {
+  padding: 6px 3px;
+}
+</style>
+<p>The following video element should be paused. (All clocks at zero).</p>
+<div id=video>
+<script>
+document.write(
+  "<video src='"+ getVideoURI('/media/movie_300') + "' >" +
+  "Your browser does not support the video element." +
+  "<\/video>");
+</script>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal-expected.txt
index 32f9652c..ee926f6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal-expected.txt
@@ -1,6 +1,7 @@
 This is a testharness.js-based test.
 PASS dialog element: showModal()
 PASS showModal() on a <dialog> that already has an open attribute throws an InvalidStateError exception
+PASS showModal() on a <dialog> after initial showModal() and removing the open attribute
 PASS showModal() on a <dialog> not in a Document throws an InvalidStateError exception
 PASS when opening multiple dialogs, only the newest one is non-inert
 FAIL opening dialog without focusable children assert_equals: expected Element node <dialog id="d6" open=""></dialog> but got Element node <body><div id="log"></div>
@@ -8,5 +9,6 @@
 <d...
 PASS opening dialog with multiple focusable children
 PASS opening dialog with multiple focusable children, one having the autofocus attribute
+PASS when opening multiple dialogs, the most recently opened is rendered on top
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html
index 30b30e1..b40d5fb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-showModal.html
@@ -38,6 +38,9 @@
   <input id="i82" value="foobar" autofocus>
   <button id="b8">OK</button>
 </dialog>
+<dialog id="d9"></dialog>
+<dialog id="d10"></dialog>
+<dialog id="d11"></dialog>
 <script>
   var d1 = document.getElementById('d1'),
       d2 = document.getElementById('d2'),
@@ -47,6 +50,9 @@
       d6 = document.getElementById('d6'),
       d7 = document.getElementById('d7'),
       d8 = document.getElementById('d8'),
+      d9 = document.getElementById('d9'),
+      d10 = document.getElementById('d10'),
+      d11 = document.getElementById('d11'),
       b0 = document.getElementById('b0'),
       b1 = document.getElementById('b1'),
       b3 = document.getElementById('b3'),
@@ -55,9 +61,11 @@
 
   test(function(){
     assert_false(d1.open);
+    assert_false(d1.hasAttribute("open"));
     d1.showModal();
     this.add_cleanup(function() { d1.close(); });
     assert_true(d1.open);
+    assert_equals(d1.getAttribute("open"), "");
     assert_equals(document.activeElement, b1);
   });
 
@@ -69,6 +77,16 @@
   }, "showModal() on a <dialog> that already has an open attribute throws an InvalidStateError exception");
 
   test(function(){
+    d9.showModal();
+    this.add_cleanup(function() { d9.close(); });
+    assert_true(d9.open);
+    d9.removeAttribute("open");
+    assert_false(d9.open);
+    d9.showModal();
+    assert_true(d9.open);
+  }, "showModal() on a <dialog> after initial showModal() and removing the open attribute");
+
+  test(function(){
     var d = document.createElement("dialog");
     assert_throws("INVALID_STATE_ERR", function() {
       d.showModal();
@@ -114,4 +132,41 @@
     assert_true(d8.open);
     assert_equals(document.activeElement, document.getElementById("i82"));
   }, "opening dialog with multiple focusable children, one having the autofocus attribute");
+
+  test(function(){
+    assert_false(d10.open);
+    assert_false(d11.open);
+    d10.showModal();
+    this.add_cleanup(function() { d10.close(); });
+    d11.showModal();
+    this.add_cleanup(function() { d11.close(); });
+    var rect10 = d10.getBoundingClientRect();
+    var rect11 = d11.getBoundingClientRect();
+
+    // The two <dialog>s are both in top layer, with the same position/size.
+    assert_equals(rect10.left, rect11.left);
+    assert_equals(rect10.top, rect11.top);
+    assert_equals(rect10.width, rect11.width);
+    assert_equals(rect10.height, rect11.height);
+
+    var pointX = rect10.left + rect10.width / 2,
+        pointY = rect10.top + rect10.height / 2;
+    function topElement() {
+      return document.elementFromPoint(pointX, pointY);
+    }
+
+    // d11 was most recently openened, and thus on top.
+    assert_equals(topElement(), d11);
+
+    // Removing the open attribute and running through the showModal() algorithm
+    // again should not promote d10 to the top.
+    d10.removeAttribute("open");
+    assert_equals(topElement(), d11);
+    d10.showModal();
+    assert_equals(topElement(), d11);
+
+    // Closing d11 with close() should cause d10 to be the topmost element.
+    d11.close();
+    assert_equals(topElement(), d10);
+  }, "when opening multiple dialogs, the most recently opened is rendered on top");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces-expected.txt
index a68e3a6..886e7b2c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 293 tests; 288 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 293 tests; 290 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Interfaces for a
 PASS Interfaces for A
 PASS Interfaces for abbr
@@ -8,8 +8,8 @@
 PASS Interfaces for ACRONYM
 PASS Interfaces for address
 PASS Interfaces for ADDRESS
-FAIL Interfaces for applet assert_equals: Element applet should have HTMLAppletElement as its primary interface. expected "[object HTMLAppletElement]" but got "[object HTMLUnknownElement]"
-FAIL Interfaces for APPLET assert_equals: Element APPLET should have HTMLAppletElement as its primary interface. expected "[object HTMLAppletElement]" but got "[object HTMLUnknownElement]"
+PASS Interfaces for applet
+PASS Interfaces for APPLET
 PASS Interfaces for area
 PASS Interfaces for AREA
 PASS Interfaces for article
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces.js b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces.js
index 5ccc891..96abf61e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/interfaces.js
@@ -3,7 +3,7 @@
   ["abbr", ""],
   ["acronym", ""],
   ["address", ""],
-  ["applet", "Applet"],
+  ["applet", "Unknown"],
   ["area", "Area"],
   ["article", ""],
   ["aside", ""],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id-attribute.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id-attribute.https.html
index 8e774bd..9d77a88 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id-attribute.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id-attribute.https.html
@@ -12,6 +12,7 @@
     id: "pass",
     total,
   });
+  assert_idl_attribute(request1, "id");
   assert_equals(request1.id, "pass", "Expected PaymentRequest.id to be 'pass'");
   const request2 = new PaymentRequest(methods, {
     total,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html
index 6b68783..5c54d48 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingaddresschange-attribute.https.html
@@ -21,6 +21,11 @@
 
 test(() => {
   const request = new PaymentRequest(defaultMethods, defaultDetails);
+  assert_idl_attribute(request, "onshippingaddresschange");
+}, "Must have a onshippingaddresschange IDL attribute");
+
+test(() => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
   const ev = new Event("shippingaddresschange");
   let didHandle = false;
   request.onshippingaddresschange = evt => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html
index 29c1189..a4d8fbc4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-onshippingoptionchange-attribute.https.html
@@ -21,6 +21,11 @@
 
 test(() => {
   const request = new PaymentRequest(defaultMethods, defaultDetails);
+  assert_idl_attribute(request, "onshippingoptionchange");
+}, "Must have a onshippingoptionchange IDL attribute");
+
+test(() => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
   const ev = new Event("shippingoptionchange");
   let didHandle = false;
   request.onshippingoptionchange = evt => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-shippingAddress-attribute.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-shippingAddress-attribute.https.html
new file mode 100644
index 0000000..0891835
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-shippingAddress-attribute.https.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!-- Copyright © 2017 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
+<meta charset="utf-8">
+<title>Test for PaymentRequest shippingAddress attribute</title>
+<link rel="help" href="https://w3c.github.io/payment-request/#shippingaddress-attribute">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+const validMethod = Object.freeze({ supportedMethods: "foo" });
+const validMethods = Object.freeze([validMethod]);
+const validAmount = Object.freeze({ currency: "USD", value: "5.00" });
+const validTotal = Object.freeze({
+  label: "label",
+  amount: validAmount,
+});
+const validDetails = Object.freeze({ total: validTotal });
+
+test(() => {
+  const request = new PaymentRequest(validMethods, validDetails);
+  assert_idl_attribute(request, "shippingAddress");
+}, "Must have a .shippingAddress IDL attribute.");
+
+test(() => {
+  const request = new PaymentRequest(validMethods, validDetails);
+  assert_equals(request.shippingAddress, null, "expected null");
+}, ".shippingAddress attribute must default to null.");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html
index 6e7252b..b1ed0d0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-shippingType-attribute.https.html
@@ -21,6 +21,11 @@
 });
 
 test(() => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  assert_idl_attribute(request, "shippingType");
+}, "Must have a shippingType IDL attribute");
+
+test(() => {
   const request1 = new PaymentRequest(defaultMethods, defaultDetails, {});
   assert_equals(request1.shippingType, null, "must be null");
   const request2 = new PaymentRequest(defaultMethods, defaultDetails, {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/helpers.js b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/helpers.js
index 0c22066..1716d93 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/helpers.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/helpers.js
@@ -1,5 +1,33 @@
 setup({ explicit_done: true, explicit_timeout: true });
 
+const validMethod = Object.freeze({
+  supportedMethods: "basic-card",
+});
+
+const validMethods = Object.freeze([validMethod]);
+
+const validAmount = Object.freeze({
+  currency: "USD",
+  value: "1.00",
+});
+
+const validTotal = Object.freeze({
+  label: "Valid total",
+  amount: validAmount,
+});
+const validDetails = {
+  total: validTotal,
+};
+
+test(() => {
+  try {
+    new PaymentRequest(validMethods, validDetails);
+  } catch (err) {
+    done();
+    throw err;
+  }
+}, "Can construct a payment request (smoke test).");
+
 /**
  * Pops up a payment sheet, allowing options to be
  * passed in if particular values are needed.
@@ -69,6 +97,11 @@
   test(() => {
     assert_equals(response.requestId, request.id, `Expected ids to match`);
     for (const [attribute, value] of Object.entries(expected)) {
+      assert_idl_attribute(
+        response,
+        attribute,
+        `Expected a ${attribute} IDL attribute`
+      );
       assert_equals(
         response[attribute],
         value,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/po-observe.html b/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/po-observe.html
index dcfd373f..d65c8a4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/po-observe.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/po-observe.html
@@ -36,7 +36,8 @@
     }
     function shouldExclude(entry) {
       // exclude all `resource` entries that aren't for "square.png"
-      return entry.type === "resource" && entry.name.indexOf("square.png") === -1
+      return entry.entryType === "resource" &&
+             entry.name.indexOf("square.png") === -1;
     }
     function runTest() {
       // this PerformanceObserver is a nop because we've already been notified about all of our `entryTypes`
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks-expected.txt
new file mode 100644
index 0000000..6a71eee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.dedicatedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.dedicatedworker-expected.txt
new file mode 100644
index 0000000..6a71eee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.dedicatedworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.dedicatedworker.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.dedicatedworker.html
new file mode 100644
index 0000000..bb3f11a9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.dedicatedworker.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>brand-checks.js dedicated worker wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+'use strict';
+fetch_tests_from_worker(new Worker('brand-checks.js'));
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.html
new file mode 100644
index 0000000..98d2e281
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>brand-checks.js browser context wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/test-utils.js"></script>
+
+<script src="brand-checks.js"></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.js b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.js
new file mode 100644
index 0000000..702c6530
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.js
@@ -0,0 +1,194 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/test-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+let ReadableStreamBYOBReader;
+let ReadableByteStreamController;
+
+test(() => {
+
+  // It's not exposed globally, but we test a few of its properties here.
+  ReadableStreamBYOBReader = realRSBYOBReader().constructor;
+
+  assert_equals(ReadableStreamBYOBReader.name, 'ReadableStreamBYOBReader', 'ReadableStreamBYOBReader should be set');
+
+}, 'Can get the ReadableStreamBYOBReader constructor indirectly');
+
+test(() => {
+
+  // It's not exposed globally, but we test a few of its properties here.
+  ReadableByteStreamController = realRBSController().constructor;
+
+  assert_equals(ReadableByteStreamController.name, 'ReadableByteStreamController',
+                'ReadableByteStreamController should be set');
+
+}, 'Can get the ReadableByteStreamController constructor indirectly');
+
+function fakeRS() {
+  return Object.setPrototypeOf({
+    cancel() { return Promise.resolve(); },
+    getReader() { return realRSBYOBReader(); },
+    pipeThrough(obj) { return obj.readable; },
+    pipeTo() { return Promise.resolve(); },
+    tee() { return [realRS(), realRS()]; }
+  }, ReadableStream.prototype);
+}
+
+function realRS() {
+  return new ReadableStream();
+}
+
+function fakeRSBYOBReader() {
+  return Object.setPrototypeOf({
+    get closed() { return Promise.resolve(); },
+    cancel() { return Promise.resolve(); },
+    read() { return Promise.resolve({ value: undefined, done: true }); },
+    releaseLock() { return; }
+  }, ReadableStreamBYOBReader.prototype);
+}
+
+function realRSBYOBReader() {
+  return new ReadableStream({ type: 'bytes' }).getReader({ mode: 'byob' });
+}
+
+function fakeRBSController() {
+  return Object.setPrototypeOf({
+    close() { },
+    enqueue() { },
+    error() { }
+  }, ReadableByteStreamController.prototype);
+}
+
+function realRBSController() {
+  let controller;
+  new ReadableStream({
+    start(c) {
+      controller = c;
+    },
+    type: 'bytes'
+  });
+  return controller;
+}
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableStreamBYOBReader(fakeRS()), 'constructor should throw');
+
+}, 'ReadableStreamBYOBReader enforces a brand check on its argument');
+
+promise_test(t => {
+
+  return getterRejectsForAll(t, ReadableStreamBYOBReader.prototype, 'closed',
+                             [fakeRSBYOBReader(), realRS(), realRBSController(), undefined, null]);
+
+}, 'ReadableStreamBYOBReader.prototype.closed enforces a brand check');
+
+promise_test(t => {
+
+  return methodRejectsForAll(t, ReadableStreamBYOBReader.prototype, 'cancel',
+                             [fakeRSBYOBReader(), realRS(), realRBSController(), undefined, null]);
+
+}, 'ReadableStreamBYOBReader.prototype.cancel enforces a brand check');
+
+promise_test(t => {
+
+  return methodRejectsForAll(t, ReadableStreamBYOBReader.prototype, 'read',
+                             [fakeRSBYOBReader(), realRS(), realRBSController(), undefined, null], [new Uint8Array(1)]);
+
+}, 'ReadableStreamBYOBReader.prototype.read enforces a brand check');
+
+test(() => {
+
+  methodThrowsForAll(ReadableStreamBYOBReader.prototype, 'releaseLock',
+                     [fakeRSBYOBReader(), realRS(), realRBSController(), undefined, null]);
+
+}, 'ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableByteStreamController(fakeRS()),
+                'Constructing a ReadableByteStreamController should throw');
+
+}, 'ReadableByteStreamController enforces a brand check on its arguments');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableByteStreamController(realRS()),
+                'Constructing a ReadableByteStreamController should throw');
+
+}, 'ReadableByteStreamController can\'t be given a fully-constructed ReadableStream');
+
+test(() => {
+
+  getterThrowsForAll(ReadableByteStreamController.prototype, 'byobRequest',
+                     [fakeRBSController(), realRS(), realRSBYOBReader(), undefined, null]);
+
+}, 'ReadableByteStreamController.prototype.byobRequest enforces a brand check');
+
+test(() => {
+
+  methodThrowsForAll(ReadableByteStreamController.prototype, 'close',
+                     [fakeRBSController(), realRS(), realRSBYOBReader(), undefined, null]);
+
+}, 'ReadableByteStreamController.prototype.close enforces a brand check');
+
+test(() => {
+
+  methodThrowsForAll(ReadableByteStreamController.prototype, 'enqueue',
+                     [fakeRBSController(), realRS(), realRSBYOBReader(), undefined, null], [new Uint8Array(1)]);
+
+}, 'ReadableByteStreamController.prototype.enqueue enforces a brand check');
+
+test(() => {
+
+  methodThrowsForAll(ReadableByteStreamController.prototype, 'error',
+                     [fakeRBSController(), realRS(), realRSBYOBReader(), undefined, null]);
+
+}, 'ReadableByteStreamController.prototype.error enforces a brand check');
+
+// ReadableStreamBYOBRequest can only be accessed asynchronously, so cram everything into one test.
+promise_test(t => {
+
+  let ReadableStreamBYOBRequest;
+  const rs = new ReadableStream({
+    pull(controller) {
+      return t.step(() => {
+        const byobRequest = controller.byobRequest;
+        ReadableStreamBYOBRequest = byobRequest.constructor;
+        brandChecks();
+        byobRequest.respond(1);
+      });
+    },
+    type: 'bytes'
+  });
+  const reader = rs.getReader({ mode: 'byob' });
+  return reader.read(new Uint8Array(1));
+
+  function fakeRSBYOBRequest() {
+    return Object.setPrototypeOf({
+      get view() {},
+      respond() {},
+      respondWithNewView() {}
+    }, ReadableStreamBYOBRequest.prototype);
+  }
+
+  function brandChecks() {
+    for (const badController of [fakeRBSController(), realRS(), realRSBYOBReader(), undefined, null]) {
+      assert_throws(new TypeError(), () => new ReadableStreamBYOBRequest(badController, new Uint8Array(1)),
+                    'ReadableStreamBYOBRequest constructor must throw for an invalid controller argument');
+    }
+    getterThrowsForAll(ReadableStreamBYOBRequest.prototype, 'view',
+                       [fakeRSBYOBRequest(), realRS(), realRSBYOBReader(), realRBSController(), undefined, null]);
+    methodThrowsForAll(ReadableStreamBYOBRequest.prototype, 'respond',
+                       [fakeRSBYOBRequest(), realRS(), realRSBYOBReader(), realRBSController(), undefined, null], [1]);
+    methodThrowsForAll(ReadableStreamBYOBRequest.prototype, 'respondWithNewView',
+                       [fakeRSBYOBRequest(), realRS(), realRSBYOBReader(), realRBSController(), undefined, null],
+                       [new Uint8Array(1)]);
+  }
+
+}, 'ReadableStreamBYOBRequest enforces brand checks');
+
+done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.serviceworker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.serviceworker.https-expected.txt
new file mode 100644
index 0000000..5bb50fd9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.serviceworker.https-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS Service worker test setup
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.serviceworker.https.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.serviceworker.https.html
new file mode 100644
index 0000000..2439cdb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.serviceworker.https.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>brand-checks.js service worker wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+
+<script>
+'use strict';
+service_worker_test('brand-checks.js', 'Service worker test setup');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.sharedworker-expected.txt
new file mode 100644
index 0000000..6a71eee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.sharedworker-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Can get the ReadableStreamBYOBReader constructor indirectly bytes type is not yet implemented
+FAIL Can get the ReadableByteStreamController constructor indirectly bytes type is not yet implemented
+PASS ReadableStreamBYOBReader enforces a brand check on its argument
+FAIL ReadableStreamBYOBReader.prototype.closed enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.cancel enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.read enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBReader.prototype.releaseLock enforces a brand check Cannot read property 'prototype' of undefined
+PASS ReadableByteStreamController enforces a brand check on its arguments
+PASS ReadableByteStreamController can't be given a fully-constructed ReadableStream
+FAIL ReadableByteStreamController.prototype.byobRequest enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.close enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.enqueue enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableByteStreamController.prototype.error enforces a brand check Cannot read property 'prototype' of undefined
+FAIL ReadableStreamBYOBRequest enforces brand checks bytes type is not yet implemented
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.sharedworker.html b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.sharedworker.html
new file mode 100644
index 0000000..cff72ec
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/readable-byte-streams/brand-checks.sharedworker.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>brand-checks.js shared worker wrapper file</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+'use strict';
+fetch_tests_from_worker(new SharedWorker('brand-checks.js'));
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/resources/test-utils.js b/third_party/WebKit/LayoutTests/external/wpt/streams/resources/test-utils.js
index 00ca56a..4c58e75 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/resources/test-utils.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/resources/test-utils.js
@@ -33,6 +33,7 @@
 
 self.methodThrows = (obj, methodName, target, args) => {
   const method = obj[methodName];
+  assert_equals(typeof method, 'function', methodName + ' should exist');
 
   assert_throws(new TypeError(), () => method.apply(target, args), methodName + ' should throw a TypeError');
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness-expected.txt
index ebea98f..9c2b64c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness-expected.txt
@@ -12,8 +12,8 @@
 PASS Animation interface: attribute currentTime
 PASS Animation interface: attribute playbackRate
 PASS Animation interface: attribute playState
-FAIL Animation interface: attribute ready Illegal invocation
-FAIL Animation interface: attribute finished Illegal invocation
+PASS Animation interface: attribute ready
+PASS Animation interface: attribute finished
 PASS Animation interface: attribute onfinish
 PASS Animation interface: attribute oncancel
 PASS Animation interface: operation cancel()
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webvr/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/webvr/idlharness.html
index b715811..ecb89f37 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webvr/idlharness.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webvr/idlharness.html
@@ -87,11 +87,11 @@
 
   /**
    * Begin presenting to the VRDisplay. Must be called in response to a user gesture.
-   * Repeat calls while already presenting will update the VRLayers being displayed.
+   * Repeat calls while already presenting will update the layers being displayed.
    * If the number of values in the leftBounds/rightBounds arrays is not 0 or 4 for any of the passed layers the promise is rejected
    * If the source of any of the layers is not present (null), the promise is rejected.
    */
-  Promise<void> requestPresent(sequence<VRLayer> layers);
+  Promise<void> requestPresent(sequence<VRLayerInit> layers);
 
   /**
    * Stops presenting to the VRDisplay.
@@ -101,10 +101,10 @@
   /**
    * Get the layers currently being presented.
    */
-  sequence<VRLayer> getLayers();
+  sequence<VRLayerInit> getLayers();
 
   /**
-   * The VRLayer provided to the VRDisplay will be captured and presented
+   * The layer provided to the VRDisplay will be captured and presented
    * in the HMD. Calling this function has the same effect on the source
    * canvas as any other operation that uses its source image, and canvases
    * created without preserveDrawingBuffer set to true will be cleared.
@@ -115,7 +115,7 @@
 typedef (HTMLCanvasElement or
          OffscreenCanvas) VRSource;
 
-dictionary VRLayer {
+dictionary VRLayerInit {
   VRSource? source = null;
 
   sequence<float> leftBounds = [];
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webvtt/parsing/file-parsing/signature-invalid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webvtt/parsing/file-parsing/signature-invalid-expected.txt
deleted file mode 100644
index 6c9fc3d..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/webvtt/parsing/file-parsing/signature-invalid-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This is a testharness.js-based test.
-FAIL signature, empty assert_unreached: track should fail to load Reached unreachable code
-PASS signature, formfeed
-PASS signature, invalid whitespace
-PASS signature, invalid
-PASS signature, lowercase
-PASS signature, missing whitespace
-PASS signature, missing
-PASS signature, null
-PASS signature, partial
-PASS signature, two boms
-PASS signature, websrt
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-with-box-shadow-01-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-01-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-with-box-shadow-01-expected.png
rename to third_party/WebKit/LayoutTests/fast/borders/border-radius-with-box-shadow-01-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-clipped-slices-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-clipped-slices-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-clipped-slices-expected.png
rename to third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-clipped-slices-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-radius-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/box-shadow-radius-expected.png
rename to third_party/WebKit/LayoutTests/fast/box-shadow/box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/spread-multiple-normal-expected.png b/third_party/WebKit/LayoutTests/fast/box-shadow/spread-multiple-normal-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/spread-multiple-normal-expected.png
rename to third_party/WebKit/LayoutTests/fast/box-shadow/spread-multiple-normal-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt
index 704ff37..512c2bcc 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt
@@ -331,11 +331,11 @@
 PASS getComputedStyle(element, '').getPropertyValue('grid-auto-rows') is "auto"
 PASS element.style.gridAutoRows is "initial"
 
-Test the inherit value on reset-only subproperties (grid-*-gap)
+Test the inherit value does not affect gutter properties (grid-*-gap)
 PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap') is "0px"
 PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap') is "0px"
-PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap') is "20px"
-PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap') is "100px"
+PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap') is "0px"
+PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap') is "0px"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html
index 0258300..cd1bffd 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html
@@ -205,7 +205,7 @@
     testGridDefinitionsSetJSValues("none", "none", "none", "none", "row", "auto", "auto", "none", "none", "none", "initial", "initial", "initial");
 
     debug("");
-    debug("Test the inherit value on reset-only subproperties (grid-*-gap)");
+    debug("Test the inherit value does not affect gutter properties (grid-*-gap)");
     document.body.style.gridRowGap = "100px";
     document.body.style.gridColumnGap = "20px";
     var anotherElement = document.createElement("div");
@@ -213,8 +213,8 @@
     shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap')", "0px");
     shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap')", "0px");
     anotherElement.style.grid = "inherit";
-    shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap')", "20px");
-    shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap')", "100px");
+    shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap')", "0px");
+    shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap')", "0px");
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/harness/test-expectations.html b/third_party/WebKit/LayoutTests/fast/harness/test-expectations.html
index 86b5769..275a8ce 100644
--- a/third_party/WebKit/LayoutTests/fast/harness/test-expectations.html
+++ b/third_party/WebKit/LayoutTests/fast/harness/test-expectations.html
@@ -261,6 +261,7 @@
       <option value="plain" selected>Plain text</option>
       <option value="expectation">TestExpectations</option>
       <option value="crashsite">Crash site</option>
+      <option value="textmismatch">Text mismatch</option>
     </select>
 </div>
 
@@ -406,6 +407,8 @@
         return {print: Report.printExpectation, summarize: Report.renderResultList};
       case "crashsite":
        return {print: Report.printCrashSite, summarize: Report.renderGroupCrashSite};
+      case "textmismatch":
+       return {print: Report.printTextMismatch, summarize: Report.renderGroupTextMismatch};
       case "plain":
       default:
         return {print: Report.printPlainTest, summarize: Report.renderResultList};
@@ -472,9 +475,9 @@
     traversal.html.push(html);
   },
 
-  printCrashSite: (test, path, traversal) => {
+  printWithKey: (test, path, traversal, key_title) => {
     let pathParser = new PathParser(path);
-    let key = test["crash_site"];
+    let key = test[key_title];
     let html = ""
       + "<input type='checkbox' class='rebaseline-checkbox' style='display:none'>"
       + pathParser.dir + "/"
@@ -484,6 +487,14 @@
     traversal.html.push({key: key, html: html});
   },
 
+  printCrashSite: (test, path, traversal) => {
+    Report.printWithKey(test, path, traversal, "crash_site");
+  },
+
+  printTextMismatch: (test, path, traversal) => {
+    Report.printWithKey(test, path, traversal, "text_mismatch");
+  },
+
   indicateNone: function(report) {
     let pre = document.createElement("div");
     pre.innerHTML = "<i>None</i>";
@@ -502,37 +513,65 @@
     report.appendChild(pre);
   },
 
-  createContainerForCrashSite: function(report, key) {
+  createContainerForGroup: function(report, key, keyed_title, null_title) {
     let container = document.createElement("div");
     container.setAttribute("key", key);
     container.innerHTML = ""
       + "<br><b>"
-      + (key !== 'null' ? "### Crash site: " + key
-                        : "### Didn't crash")
+      + (key !== 'null' ? `### ${keyed_title}: ${key}`
+                        : `### ${null_title}`)
       + "</b>";
 
-    // Ensure that the "didn't crash" container appears last.
-    if (report.lastChild && report.lastChild.getAttribute("key") == 'null')
-      report.insertBefore(container, report.lastChild);
-    else
+    // The containers are sorted by key (except the "null" key) alphabetically.
+    // The "null" container always appears at the last.
+    if (key == "null") {
       report.appendChild(container);
+    } else {
+      let inserted = false;
+      report.childNodes.forEach(sibling => {
+        if (inserted)
+          return;
+        let siblingKey = sibling.getAttribute("key");
+        if (siblingKey == "null" || siblingKey > key) {
+          report.insertBefore(container, sibling);
+          inserted = true;
+        }
+      });
+      if (!inserted)
+        report.appendChild(container);
+    }
     return container;
   },
 
-  renderGroupCrashSite: function(html) {
+  renderGroup: function(html, keyed_title, null_title) {
     let report = document.querySelector("#report");
     if (report.childNodes.length === 0 && html.length === 0) {
       Report.indicateNone(report);
       return;
     }
 
+    let renderMap = {};
     html.forEach(result => {
-      let key = result.key || 'null';
-      let container = report.querySelector(`div[key="${key}"]`) || Report.createContainerForCrashSite(report, key);
-      let pre = document.createElement("div");
-      pre.innerHTML = result.html;
-      container.appendChild(pre);
+      let key = result.key || "null";
+      if (!(key in renderMap)) {
+        let container =
+            report.querySelector(`div[key="${key}"]`) ||
+            Report.createContainerForGroup(report, key, keyed_title, null_title);
+        renderMap[key] = {container: container, html: ""};
+      }
+      renderMap[key].html += result.html;
     });
+
+    for (let key in renderMap)
+      renderMap[key].container.insertAdjacentHTML('beforeend', renderMap[key].html);
+  },
+
+  renderGroupCrashSite: function(html) {
+    Report.renderGroup(html, "Crash site", "Didn't crash");
+  },
+
+  renderGroupTextMismatch: function(html) {
+    Report.renderGroup(html, "Text mismatch failure", "Didn't find text mismatch");
   },
 
   getTestById: function(testId) {
@@ -568,6 +607,8 @@
         case "TIMEOUT":
           links.push({text: "Test timed out. "
             + ("time" in test ? `(${test.time}s)` : "")});
+          if (test.text_mismatch)
+            links.push({text: "actual text", link: pathParser.resultLink('-actual.txt')});
           break;
         case "TEXT":
           links.push({text: "actual text", link: pathParser.resultLink('-actual.txt')});
diff --git a/third_party/WebKit/LayoutTests/fast/imagecapture/OWNERS b/third_party/WebKit/LayoutTests/fast/imagecapture/OWNERS
index 57a9132d..d58b08f 100644
--- a/third_party/WebKit/LayoutTests/fast/imagecapture/OWNERS
+++ b/third_party/WebKit/LayoutTests/fast/imagecapture/OWNERS
@@ -1,2 +1,2 @@
-# TEAM: device-dev@chromium.org
+# TEAM: media-dev@chromium.org
 # COMPONENT: Blink>ImageCapture
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/background-image-paint-invalidation-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/background-image-paint-invalidation-expected.txt
deleted file mode 100644
index 0eeaaaa..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/background-image-paint-invalidation-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [808, 2016],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutView #document",
-          "rect": [0, 0, 808, 2016],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutBlockFlow HTML",
-          "rect": [8, 8, 800, 2000],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutView #document",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
deleted file mode 100644
index 7de4778..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/caret-invalidation-in-overflow-scroll-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "Caret",
-          "rect": [399, 11, 1, 16],
-          "reason": "caret"
-        },
-        {
-          "object": "Caret",
-          "rect": [396, 11, 1, 16],
-          "reason": "caret"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "Caret",
-      "reason": "caret"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/child-of-sub-pixel-offset-composited-layer-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/child-of-sub-pixel-offset-composited-layer-expected.txt
new file mode 100644
index 0000000..bd458b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/child-of-sub-pixel-offset-composited-layer-expected.txt
@@ -0,0 +1,45 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='target' class='green'",
+      "position": [-1, 0],
+      "bounds": [15, 14],
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (positioned) DIV id='target' class='green'",
+          "rect": [0, 0, 15, 14],
+          "reason": "style change"
+        }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [101, 100, 0, 1]
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) DIV class='container'",
+      "reason": "appeared"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='target' class='green'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
deleted file mode 100644
index eb5ff27..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='composited-box'",
-      "bounds": [102, 102],
-      "transform": 2
-    }
-  ],
-  "transforms": [
-    {
-      "id": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 2,
-      "parent": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [100, 100, 0, 1]
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/text-color-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/text-color-change-expected.txt
deleted file mode 100644
index d43a134..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/text-color-change-expected.txt
+++ /dev/null
@@ -1,757 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '\n'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox '  Text'",
-          "rect": [8, 61, 48, 185],
-          "reason": "style change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '  Text'",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox '\n'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/text-match-highlight-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/text-match-highlight-expected.txt
deleted file mode 100644
index 4b30e34..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/text-match-highlight-expected.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Can you findme in this boring text?'",
-          "rect": [10, 135, 223, 19],
-          "reason": "DocumentMarker change"
-        },
-        {
-          "object": "InlineTextBox 'Findme on a path! Did you findme?'",
-          "rect": [20, 224, 206, 72],
-          "reason": "DocumentMarker change"
-        },
-        {
-          "object": "InlineTextBox 'Findme in a typewriter!'",
-          "rect": [10, 191, 138, 12],
-          "reason": "DocumentMarker change"
-        },
-        {
-          "object": "InlineTextBox 'findme'",
-          "rect": [278, 40, 44, 19],
-          "reason": "DocumentMarker change"
-        },
-        {
-          "object": "InlineTextBox 'findme'",
-          "rect": [264, 60, 44, 19],
-          "reason": "DocumentMarker change"
-        },
-        {
-          "object": "InlineTextBox 'findme'",
-          "rect": [220, 60, 44, 19],
-          "reason": "DocumentMarker change"
-        },
-        {
-          "object": "InlineTextBox 'findme'",
-          "rect": [89, 60, 44, 19],
-          "reason": "DocumentMarker change"
-        },
-        {
-          "object": "InlineTextBox 'findme'",
-          "rect": [51, 80, 44, 19],
-          "reason": "DocumentMarker change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'findme'",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'findme'",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'findme'",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'findme'",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'findme'",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'Can you findme in this boring text?'",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'Findme in a typewriter!'",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "DocumentMarker change"
-    },
-    {
-      "object": "InlineTextBox 'Findme on a path! Did you findme?'",
-      "reason": "DocumentMarker change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/updating-scrolling-container-and-content-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/updating-scrolling-container-and-content-expected.txt
deleted file mode 100644
index 0113aac..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/updating-scrolling-container-and-content-expected.txt
+++ /dev/null
@@ -1,169 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 258, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 238, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 218, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 198, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 178, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 158, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 138, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 118, 77, 19],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 278, 77, 15],
-          "reason": "style change"
-        },
-        {
-          "object": "InlineTextBox 'CONTENT'",
-          "rect": [8, 108, 77, 9],
-          "reason": "style change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'CONTENT'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/updating-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/updating-scrolling-container-expected.txt
deleted file mode 100644
index 82b5c97a..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/compositing/updating-scrolling-container-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='container'",
-          "rect": [8, 108, 210, 210],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='container'",
-          "rect": [8, 108, 210, 210],
-          "reason": "style change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='container'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/destroy-overlay-scrollbar-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/destroy-overlay-scrollbar-expected.txt
deleted file mode 100644
index d8a9ce2..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/destroy-overlay-scrollbar-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow (positioned) DIV",
-          "rect": [193, 100, 7, 200],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/destroy-scrollbar-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/destroy-scrollbar-expected.txt
deleted file mode 100644
index c22897313..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/destroy-scrollbar-expected.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow (positioned) DIV",
-          "rect": [185, 100, 15, 200],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/dynamic-table-vertical-alignment-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/dynamic-table-vertical-alignment-change-expected.txt
deleted file mode 100644
index 4e521bb..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/dynamic-table-vertical-alignment-change-expected.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [808, 585],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow (floating) DIV id='target'",
-          "rect": [11, 75, 100, 100],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) DIV id='target'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/flexbox/scrollbars-changed-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/flexbox/scrollbars-changed-expected.txt
deleted file mode 100644
index ed4a5c3..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/flexbox/scrollbars-changed-expected.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "VerticalScrollbar",
-          "rect": [185, 0, 15, 100],
-          "reason": "scroll control"
-        },
-        {
-          "object": "InlineTextBox 'a'",
-          "rect": [0, 5, 15, 15],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'z'",
-          "rect": [0, 5, 15, 15],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='dynamic' class='content'",
-      "reason": "full"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "full"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'z'",
-      "reason": "appeared"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
deleted file mode 100644
index c48f2f5e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [2000, 2000],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Text Text Text Text Text Text Text Text Text Text Text Text Text'",
-          "rect": [0, 320, 411, 19],
-          "reason": "style change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'Text Text Text Text Text Text Text Text Text Text Text Text Text'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/japanese-rl-selection-clear-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/japanese-rl-selection-clear-expected.txt
deleted file mode 100644
index 21a86590..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/japanese-rl-selection-clear-expected.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox '\u3042\u3063\u305F\u304B\u5FD8\u308C\u3066\u3057\u307E\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B\u3089\u3082\u691C\u7D22'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u3059\u3002\u8A2A\u554F\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B \u306A\u3089\u30BF\u30A4\u30C8\u30EB\u3068\u30A2'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u306A\u3089\u30BF\u30A4\u30C8\u30EB\u3068\u30A2\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8\u308C\u3066\u3057\u307E'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u308C\u3066\u3057\u307E\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B \u306A\u3089\u30BF\u30A4'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u30C8\u30EB\u3068\u30A2\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8'",
-          "rect": [441, 123, 336, 404],
-          "reason": "geometry"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3042\u3063\u305F\u304B\u5FD8\u308C\u3066\u3057\u307E\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u306A\u3089\u30BF\u30A4\u30C8\u30EB\u3068\u30A2\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B\u3089\u3082\u691C\u7D22'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B\u3064\u3051\u305F\u3059'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8\u308C\u3066\u3057\u307E'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B \u306A\u3089\u30BF\u30A4\u30C8\u30EB\u3068\u30A2'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3059\u3002\u8A2A\u554F\u3057\u305F\u30A6\u30A7\u30D6\u30DA\u30FC\u30B8\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u304B'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3089\u3082\u691C\u7D22\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002\u305B\u3063\u304B\u304F\u898B'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u3064\u3051\u305F\u3059\u3070\u3089\u3057\u3044\u8A18\u4E8B\u304C\u3069\u3053\u306B\u3042\u3063\u305F\u304B\u5FD8'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u308C\u3066\u3057\u307E\u3063\u305F\u7D4C\u9A13\u306F\u3042\u308A\u307E\u3059\u304B \u306A\u3089\u30BF\u30A4'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u30C8\u30EB\u3068\u30A2\u30C9\u30EC\u30B9\u3060\u3051\u3067\u306A\u304F\u3001\u8A2A\u554F'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-1-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-1-expected.txt
deleted file mode 100644
index 737163d..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-1-expected.txt
+++ /dev/null
@@ -1,148 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 406, 119],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'away,\n'",
-          "rect": [14, 80, 406, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'but generally, just as she had got its'",
-          "rect": [14, 80, 406, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-          "rect": [14, 80, 406, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 80, 406, 119],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'hanging down,\n'",
-          "rect": [14, 80, 406, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-          "rect": [14, 80, 406, 119],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'her\n'",
-          "rect": [14, 80, 406, 119],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'neck nicely straightened\n'",
-          "rect": [14, 80, 406, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'out, and was going to give the'",
-          "rect": [14, 80, 406, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'away,\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'but generally, just as she had got its'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'hanging down,\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'neck nicely straightened\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'out, and was going to give the'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) DIV id='pinkFloat'",
-          "rect": [378, 138, 70, 30],
-          "reason": "incremental"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow (floating) DIV id='pinkFloat'",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The chief difficulty Alice found at first was in managing'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'flamingo: she succeeded in getting its body tucked'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'away,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hanging down,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'but generally, just as she had got its'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'neck nicely straightened\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'out, and was going to give the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-10-expected.txt
deleted file mode 100644
index 9023441..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-10-expected.txt
+++ /dev/null
@@ -1,484 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox ' was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019 about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'Queen'",
-          "rect": [14, 440, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the'",
-          "rect": [14, 440, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 363, 48, 65],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 374, 48, 64],
-          "reason": "geometry"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself, and was'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this, there was generally'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she wanted to send the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers were always'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the ground, Alice'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'game indeed.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The players all played at once without waiting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for turns,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Queen'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' was in a furious passion, and went\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'stamping'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her head!\u2019 about once in a minute.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'yet'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'become of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'here; the great\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-2-expected.txt
deleted file mode 100644
index df8feeb..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-2-expected.txt
+++ /dev/null
@@ -1,778 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow P",
-          "rect": [8, 74, 418, 526],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 521, 408, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 241, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox ' twist itself round and'",
-          "rect": [14, 181, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'could not help bursting out\n'",
-          "rect": [14, 181, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'head down, and was going to\n'",
-          "rect": [14, 181, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'laughing: and when she had got its'",
-          "rect": [14, 181, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'look up in her face, with\n'",
-          "rect": [14, 181, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'such a puzzled expression that she'",
-          "rect": [14, 181, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox ' twist itself round and'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'could not help bursting out\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'head down, and was going to\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'laughing: and when she had got its'",
-          "rect": [14, 180, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'look up in her face, with\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'such a puzzled expression that she'",
-          "rect": [14, 180, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 361, 356, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 361, 356, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 355, 120],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'away,\n'",
-          "rect": [14, 80, 355, 120],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'but generally, just as she had got its'",
-          "rect": [14, 80, 355, 120],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-          "rect": [14, 80, 355, 120],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 80, 355, 120],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'hanging down,\n'",
-          "rect": [14, 80, 355, 120],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-          "rect": [14, 80, 355, 120],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her\n'",
-          "rect": [14, 80, 355, 120],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'neck nicely straightened\n'",
-          "rect": [14, 80, 355, 120],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'out, and was going to give the'",
-          "rect": [14, 80, 355, 120],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'neck nicely straightened\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'out, and was going to give the'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 461, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 461, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 461, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 461, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 461, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 460, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 421, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 421, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 421, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 421, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 401, 304, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 441, 66, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-          "rect": [372, 404, 48, 81],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-          "rect": [372, 403, 48, 81],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 364, 48, 65],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 363, 48, 65],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'would'",
-          "rect": [235, 180, 45, 20],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'would'",
-          "rect": [238, 180, 40, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [485, 0, 15, 600],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutBlockFlow P",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The chief difficulty Alice found at first was in managing'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'flamingo: she succeeded in getting its body tucked'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'away,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hanging down,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'but generally, just as she had got its'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'neck nicely straightened\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'out, and was going to give the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutInline I id='would'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'would'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' twist itself round and'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'look up in her face, with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'such a puzzled expression that she'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'could not help bursting out\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'laughing: and when she had got its'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'head down, and was going to\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself, and was'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this, there was generally'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she wanted to send the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers were always'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the ground, Alice'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'game indeed.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The players all played at once without waiting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for turns,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the Queen'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'was in a furious passion, and went\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'stamping about, and'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her head!\u2019'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'about once in a minute.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'yet'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'become of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'here; the great\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-3-expected.txt
deleted file mode 100644
index fb563f0e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-3-expected.txt
+++ /dev/null
@@ -1,473 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 400, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,'",
-          "rect": [14, 400, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehogs; and in\n'",
-          "rect": [14, 400, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting for the'",
-          "rect": [14, 400, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox ' was in'",
-          "rect": [14, 440, 339, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'a furious passion, and went\n'",
-          "rect": [14, 440, 339, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 440, 339, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 440, 339, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 440, 339, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 440, 339, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting\n'",
-          "rect": [65, 400, 298, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [242, 440, 65, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-          "rect": [356, 423, 64, 81],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-          "rect": [372, 403, 48, 81],
-          "reason": "geometry"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself, and was'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this, there was generally'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she wanted to send the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers were always'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the ground, Alice'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'game indeed.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The players all played at once without waiting\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for turns,'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting for the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehogs; and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the Queen'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' was in'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a furious passion, and went\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'stamping about, and'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her head!\u2019'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'about once in a minute.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'yet'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'become of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'here; the great\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-4-expected.txt
deleted file mode 100644
index b129a12..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-4-expected.txt
+++ /dev/null
@@ -1,459 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019 about once'",
-          "rect": [14, 460, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'in a minute.\n'",
-          "rect": [14, 460, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 406, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-          "rect": [372, 403, 48, 81],
-          "reason": "geometry"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself, and was'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this, there was generally'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she wanted to send the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers were always'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the ground, Alice'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'game indeed.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The players all played at once without waiting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for turns,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the Queen'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'was in a furious passion, and went\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'stamping about, and'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her head!\u2019 about once'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in a minute.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'yet'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'become of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'here; the great\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-5-expected.txt
deleted file mode 100644
index 5051fe67..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-5-expected.txt
+++ /dev/null
@@ -1,497 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [49, 360, 372, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [49, 360, 372, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 400, 356, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for'",
-          "rect": [14, 400, 356, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehogs; and in\n'",
-          "rect": [14, 400, 356, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting for the'",
-          "rect": [14, 400, 356, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'turns,\n'",
-          "rect": [14, 400, 356, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox ' was in a'",
-          "rect": [14, 440, 355, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'furious passion, and went\n'",
-          "rect": [14, 440, 355, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019 about once'",
-          "rect": [14, 440, 355, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'in a minute.\n'",
-          "rect": [14, 440, 355, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and shouting'",
-          "rect": [14, 440, 355, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox '\u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 440, 355, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting\n'",
-          "rect": [49, 400, 302, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [245, 440, 65, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 363, 48, 65],
-          "reason": "geometry"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself, and was'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this, there was generally'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she wanted to send the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers were always'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the ground, Alice'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'game indeed.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The players all played at once without waiting\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'turns,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting for the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehogs; and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the Queen'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' was in a'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'furious passion, and went\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'stamping about, and shouting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '\u2018Off with his head!\u2019 or \u2018Off with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her head!\u2019 about once'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in a minute.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'yet'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'become of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'here; the great\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-6-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-6-expected.txt
deleted file mode 100644
index 76cccca3..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-6-expected.txt
+++ /dev/null
@@ -1,210 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 363, 48, 65],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'foo'",
-          "rect": [27, 363, 22, 20],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself, and was'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this, there was generally'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she wanted to send the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers were always'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the ground, Alice'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'foo'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'game indeed.\n'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-7-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-7-expected.txt
deleted file mode 100644
index cf5eca5b..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-7-expected.txt
+++ /dev/null
@@ -1,97 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [298, 440, 70, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for turns,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutInline SPAN id='theQueen'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "style change"
-    },
-    {
-      "object": "InlineTextBox 'the Queen'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-8-expected.txt
deleted file mode 100644
index 0ddeb010..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ /dev/null
@@ -1,666 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow P",
-          "rect": [8, 74, 418, 526],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox ' twist itself round and'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox ' twist itself round and'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'could not help bursting out\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'could not help bursting out\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'head down, and was going to\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'head down, and was going to\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'laughing: and when she had got its'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'laughing: and when she had got its'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'look up in her face, with\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'look up in her face, with\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'such a puzzled expression that she'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'such a puzzled expression that she'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult game'",
-          "rect": [14, 360, 406, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'indeed.\n'",
-          "rect": [14, 360, 406, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox ' was in a furious'",
-          "rect": [13, 440, 358, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019 about once in a'",
-          "rect": [13, 440, 358, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'minute.\n'",
-          "rect": [13, 440, 358, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'passion, and went\n'",
-          "rect": [13, 440, 358, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and shouting \u2018Off'",
-          "rect": [13, 440, 358, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'with his head!\u2019 or \u2018Off with\n'",
-          "rect": [13, 440, 358, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'away,\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'away,\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'but generally, just as she had got its'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'but generally, just as she had got its'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'hanging down,\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hanging down,\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'her\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'neck nicely straightened\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'neck nicely straightened\n'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'out, and was going to give the'",
-          "rect": [14, 80, 355, 119],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'out, and was going to give the'",
-          "rect": [14, 80, 355, 119],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 400, 354, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'and in\n'",
-          "rect": [14, 400, 354, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,'",
-          "rect": [14, 400, 354, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting for the hedgehogs;'",
-          "rect": [14, 400, 354, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting\n'",
-          "rect": [14, 400, 297, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [184, 440, 68, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 363, 48, 65],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'would'",
-          "rect": [238, 180, 40, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'would'",
-          "rect": [238, 180, 40, 19],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow P",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The chief difficulty Alice found at first was in managing'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'flamingo: she succeeded in getting its body tucked'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'away,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'comfortably enough, under her arm, with its legs'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hanging down,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'but generally, just as she had got its'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'neck nicely straightened\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'out, and was going to give the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog a blow with its head, it\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'would'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' twist itself round and'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'look up in her face, with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'such a puzzled expression that she'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'could not help bursting out\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'laughing: and when she had got its'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'head down, and was going to\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself, and was'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this, there was generally'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she wanted to send the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers were always'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the ground, Alice'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult game'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'indeed.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The players all played at once without waiting\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for turns,'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting for the hedgehogs;'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the Queen'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' was in a furious'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'passion, and went\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'stamping about, and shouting \u2018Off'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'with his head!\u2019 or \u2018Off with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her head!\u2019 about once in a'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'minute.\n'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-9-expected.txt
deleted file mode 100644
index 14686e05..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ /dev/null
@@ -1,602 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'become of\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'here; the great\n'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'yet'",
-          "rect": [13, 520, 408, 80],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'and was in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'begin again, it was very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'ground, Alice soon came to the conclusion that it was a very'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'in the act of crawling away: besides all\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'she wanted to send the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'she'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soldiers were always'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'soldiers'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'soon came to the conclusion that it was a very\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the ground, Alice'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'the'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'there was generally a ridge or furrow in the way wherever\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'this, there was generally'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'this,'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself, and was'",
-          "rect": [13, 240, 407, 139],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'unrolled itself,'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'wanted to send the hedgehog to, and, as the doubled-up\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'were always getting up and walking off to other parts of\n'",
-          "rect": [13, 240, 407, 139],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox ' twist itself round and'",
-          "rect": [14, 180, 407, 79],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox 'could not help bursting out\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'could not help bursting out\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'head down, and was going to\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'head down, and was going to\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'laughing: and when she had got its'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'laughing: and when she had got its'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'look up in her face, with\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'look up in her face, with\n'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'such a puzzled expression that she'",
-          "rect": [14, 180, 407, 79],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'such a puzzled expression that she'",
-          "rect": [14, 180, 407, 79],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'game indeed.\n'",
-          "rect": [65, 360, 356, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox ' was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019 about once in a minute.\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'her head!\u2019'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping about, and'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'stamping'",
-          "rect": [14, 460, 355, 59],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'was in a furious passion, and went\n'",
-          "rect": [14, 460, 355, 59],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'Queen'",
-          "rect": [14, 440, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the'",
-          "rect": [14, 440, 355, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [14, 420, 355, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'a very short time '",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'for turns,\n'",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-          "rect": [65, 420, 304, 39],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'The players all played at once without waiting'",
-          "rect": [65, 400, 304, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'difficult game indeed.\n'",
-          "rect": [65, 380, 141, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'the Queen'",
-          "rect": [302, 440, 66, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 383, 48, 65],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-          "rect": [14, 363, 48, 65],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (floating) SPAN id='yellowFloat'",
-          "rect": [372, 243, 48, 49],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' twist itself round and'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'look up in her face, with\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'such a puzzled expression that she'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'could not help bursting out\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'laughing: and when she had got its'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'head down, and was going to\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='yellowFloat'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'begin again, it was very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'provoking to find that the hedgehog had\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'unrolled itself,'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'and was in the act of crawling away: besides all\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'this,'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'there was generally a ridge or furrow in the way wherever\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'she'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'wanted to send the hedgehog to, and, as the doubled-up\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'soldiers'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'were always getting up and walking off to other parts of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'ground, Alice soon came to the conclusion that it was a very'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'difficult game indeed.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'The players all played at once without waiting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for turns,\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'quarrelling all the while, and fighting'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'for the hedgehogs; and in\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'a very short time '",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'the'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Queen'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox ' was in a furious passion, and went\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'stamping'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'her head!\u2019 about once in a minute.\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'yet'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'become of\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'here; the great\n'",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multiple-backgrounds-style-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multiple-backgrounds-style-change-expected.txt
deleted file mode 100644
index daa2563..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/multiple-backgrounds-style-change-expected.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='test' class='composited box changed'",
-      "bounds": [202, 202],
-      "transform": 2
-    }
-  ],
-  "transforms": [
-    {
-      "id": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [8, 8, 0, 1]
-      ]
-    },
-    {
-      "id": 2,
-      "parent": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [50, 50, 0, 1]
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-auto-in-overflow-auto-scrolled-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-auto-in-overflow-auto-scrolled-expected.txt
deleted file mode 100644
index 628a84d..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-auto-in-overflow-auto-scrolled-expected.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='innerDiv'",
-          "rect": [8, 8, 300, 300],
-          "reason": "paint property change"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [762, 8, 15, 300],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "subtree"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-composited-non-stacking-child-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-composited-non-stacking-child-expected.txt
deleted file mode 100644
index 4d98c005..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-composited-non-stacking-child-expected.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV class='scroller'",
-          "rect": [18, 60, 310, 200],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow DIV class='scroller'",
-          "rect": [18, 60, 310, 200],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV class='back'",
-          "rect": [93, 125, 180, 100],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV class='back'",
-          "rect": [93, 75, 180, 100],
-          "reason": "paint property change"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [308, 65, 15, 175],
-          "reason": "scroll control"
-        }
-      ]
-    },
-    {
-      "name": "LayoutBlockFlow (positioned) DIV class='icon'",
-      "bounds": [40, 40],
-      "contentsOpaque": false,
-      "drawsContent": true
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV class='scroller'",
-      "reason": "subtree"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='list'",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='commit'",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='back'",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-delete-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-delete-expected.txt
deleted file mode 100644
index f3f2f20d..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-delete-expected.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Passed'",
-          "rect": [8, 136, 44, 17],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'Test'",
-          "rect": [8, 136, 44, 17],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'Failed'",
-          "rect": [8, 136, 40, 17],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'Test'",
-          "rect": [8, 136, 40, 17],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutText #text",
-      "reason": "full"
-    },
-    {
-      "object": "InlineTextBox 'Passed'",
-      "reason": "full"
-    },
-    {
-      "object": "InlineTextBox 'Test'",
-      "reason": "full"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-in-overflow-scroll-scrolled-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-in-overflow-scroll-scrolled-expected.txt
deleted file mode 100644
index 628a84d..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/overflow-scroll-in-overflow-scroll-scrolled-expected.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='innerDiv'",
-          "rect": [8, 8, 300, 300],
-          "reason": "paint property change"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [762, 8, 15, 300],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "subtree"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
deleted file mode 100644
index 73b0ac11..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [2011, 2081],
-      "contentsOpaque": false,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutView #document",
-          "rect": [3, 65, 2008, 2016],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow HTML",
-          "rect": [3, 65, 235, 235],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutView #document",
-          "rect": [3, 65, 235, 235],
-          "reason": "paint property change"
-        },
-        {
-          "object": "HorizontalScrollbar",
-          "rect": [3, 300, 235, 15],
-          "reason": "scroll control"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [238, 65, 15, 235],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow HTML",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "subtree"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "subtree"
-    },
-    {
-      "object": "InlineTextBox 'scroll me'",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-overlay/layers-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-overlay/layers-expected.txt
new file mode 100644
index 0000000..1576397
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-overlay/layers-expected.txt
@@ -0,0 +1,100 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 2016],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='container'",
+      "position": [40, 50],
+      "bounds": [100, 100],
+      "backgroundColor": "#0000FF80",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='scrollable'",
+      "position": [104, 103],
+      "bounds": [302, 302],
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='transform'",
+      "bounds": [200, 200],
+      "backgroundColor": "#FFFF00",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 4
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -20, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -30, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [193, 181, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [3.53553390593274, 3.53553390593274, 0, 0],
+        [-3.53553390593274, 3.53553390593274, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0],
+      "flattenInheritedTransform": false
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/requestAnimation-translation-leave-traces-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/requestAnimation-translation-leave-traces-expected.txt
deleted file mode 100644
index 993db15..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/requestAnimation-translation-leave-traces-expected.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-This test checks that changing the transform on an element triggers a correct invalidation.
-The paint invalidations below should match the transformed element's coordinates.
-Tested locations: 1200,1500
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [1600, 585],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutView #document",
-          "rect": [1300, 0, 300, 585],
-          "reason": "incremental"
-        },
-        {
-          "object": "LayoutView #document",
-          "rect": [1000, 0, 300, 585],
-          "reason": "incremental"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='box'",
-          "rect": [1500, 0, 100, 100],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='box'",
-          "rect": [1200, 0, 100, 100],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='box'",
-          "rect": [1200, 0, 100, 100],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='box'",
-          "rect": [900, 0, 100, 100],
-          "reason": "paint property change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/resize-scrollable-iframe-expected.txt
deleted file mode 100644
index 83d9bce..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/resize-scrollable-iframe-expected.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [1016, 1124],
-      "contentsOpaque": false,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutView #document",
-          "rect": [8, 108, 1008, 1016],
-          "reason": "geometry"
-        },
-        {
-          "object": "HorizontalScrollbar",
-          "rect": [8, 393, 285, 15],
-          "reason": "scroll control"
-        },
-        {
-          "object": "HorizontalScrollbar",
-          "rect": [8, 193, 85, 15],
-          "reason": "scroll control"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [293, 108, 15, 285],
-          "reason": "scroll control"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [93, 108, 15, 85],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow (anonymous)",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutIFrame IFRAME id='iframe'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "geometry"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "geometry"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scroll-inside-table-cell-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scroll-inside-table-cell-expected.txt
deleted file mode 100644
index f713bf1..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scroll-inside-table-cell-expected.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-          "rect": [312, 112, 454, 469],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-          "rect": [312, 112, 454, 469],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
-          "rect": [314, 114, 435, 450],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutBlockFlow (relative positioned) DIV class='relative red'",
-          "rect": [314, 114, 435, 450],
-          "reason": "disappeared"
-        },
-        {
-          "object": "HorizontalScrollbar",
-          "rect": [314, 564, 435, 15],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-      "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='relative red'",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scroll-relative-table-inside-table-cell-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scroll-relative-table-inside-table-cell-expected.txt
deleted file mode 100644
index b4a6f34..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scroll-relative-table-inside-table-cell-expected.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [1566, 1781],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-          "rect": [1112, 1312, 454, 469],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-          "rect": [1112, 1312, 454, 469],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
-          "rect": [1114, 1314, 435, 450],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutBlockFlow (relative positioned) DIV class='relative red'",
-          "rect": [1114, 1314, 435, 450],
-          "reason": "disappeared"
-        },
-        {
-          "object": "HorizontalScrollbar",
-          "rect": [1114, 1764, 435, 15],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutTableCell (relative positioned) TD id='cellToScroll' class='relative'",
-      "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='relative red'",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='absolute green'",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scrollbar-damage-and-full-viewport-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scrollbar-damage-and-full-viewport-repaint-expected.txt
deleted file mode 100644
index 469e87c..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scrollbar-damage-and-full-viewport-repaint-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [1000, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "HorizontalScrollbar",
-          "rect": [1, 236, 185, 15],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scrollbar-parts-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scrollbar-parts-expected.txt
deleted file mode 100644
index 11d1451f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/scrollbar-parts-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "HorizontalScrollbar",
-          "rect": [8, 93, 85, 15],
-          "reason": "scroll control"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [93, 8, 15, 85],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
deleted file mode 100644
index 0822fe5f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl INPUT id='target'",
-          "rect": [7, 7, 66, 24],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='inner-editor'",
-          "rect": [10, 11, 60, 16],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='inner-editor'",
-          "rect": [10, 11, 59, 16],
-          "reason": "paint property change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow HTML",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutTextControl INPUT id='target'",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='inner-editor'",
-      "reason": "subtree"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "subtree"
-    },
-    {
-      "object": "InlineTextBox 'test test test'",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
deleted file mode 100644
index 9839700d..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl INPUT id='target'",
-          "rect": [7, 7, 66, 24],
-          "reason": "subtree"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='inner-editor'",
-          "rect": [10, 11, 60, 16],
-          "reason": "paint property change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow HTML",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "selection"
-    },
-    {
-      "object": "LayoutTextControl INPUT id='target'",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='inner-editor'",
-      "reason": "subtree"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "subtree"
-    },
-    {
-      "object": "InlineTextBox 'test test test'",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
deleted file mode 100644
index d63a9ef84..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
+++ /dev/null
@@ -1,79 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 836],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutView #document",
-          "rect": [0, 742, 785, 94],
-          "reason": "incremental"
-        },
-        {
-          "object": "LayoutIFrame IFRAME id='iframe'",
-          "rect": [8, 92, 732, 94],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'",
-          "rect": [58, 236, 489, 537],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutImage IMG",
-          "rect": [58, 142, 489, 537],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutIFrame IFRAME id='iframe'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='relative'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutImage IMG",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutBlockFlow HTML",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "appeared"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt
deleted file mode 100644
index 067d529..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/shift-relative-positioned-container-with-image-removal-expected.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 742],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutView #document",
-          "rect": [0, 742, 785, 99],
-          "reason": "incremental"
-        },
-        {
-          "object": "LayoutIFrame IFRAME id='iframe'",
-          "rect": [8, 92, 732, 94],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'",
-          "rect": [58, 241, 489, 537],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutImage IMG",
-          "rect": [58, 142, 489, 537],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='relative'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutImage IMG",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt
deleted file mode 100644
index dabffbf..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [-1, -1, 578, 434],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [-1, -1, 482, 362],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGRoot svg",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGRect rect",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
deleted file mode 100644
index 050c21cd..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/animated-path-inside-transformed-html-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
deleted file mode 100644
index b417048..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
+++ /dev/null
@@ -1,73 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'This is some text'",
-          "rect": [246, 89, 127, 46],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'This is some text'",
-          "rect": [203, 336, 126, 45],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGRect rect id='rect'",
-          "rect": [108, 84, 105, 102],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutSVGRect rect id='rect'",
-          "rect": [355, 125, 104, 104],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutSVGImage image id='image'",
-          "rect": [352, 398, 99, 98],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutSVGImage image id='image'",
-          "rect": [90, 207, 98, 99],
-          "reason": "full"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGRect rect id='rect'",
-      "reason": "full"
-    },
-    {
-      "object": "LayoutSVGText text id='text'",
-      "reason": "full"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "full"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox 'This is some text'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutSVGImage image id='image'",
-      "reason": "full"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "appeared"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/deep-dynamic-updates-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/deep-dynamic-updates-expected.txt
deleted file mode 100644
index 21846ddc..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/deep-dynamic-updates-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutSVGRect rect",
-          "rect": [23, 23, 404, 404],
-          "reason": "SVG resource change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGRect rect",
-      "reason": "SVG resource change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
deleted file mode 100644
index 20d8b3de..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
+++ /dev/null
@@ -1,85 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow HTML",
-          "rect": [0, 0, 402, 202],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutView #document",
-          "rect": [0, 0, 400, 200],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutSVGRect rect",
-          "rect": [211, 11, 180, 180],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [11, 11, 180, 180],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [10, 10, 180, 125],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutSVGRect rect",
-          "rect": [210, 10, 75, 125],
-          "reason": "paint property change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutEmbeddedObject OBJECT",
-      "reason": "style change"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutEmbeddedObject OBJECT",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
deleted file mode 100644
index 20d8b3de..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
+++ /dev/null
@@ -1,85 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow HTML",
-          "rect": [0, 0, 402, 202],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutView #document",
-          "rect": [0, 0, 400, 200],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutSVGRect rect",
-          "rect": [211, 11, 180, 180],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [11, 11, 180, 180],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [10, 10, 180, 125],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutSVGRect rect",
-          "rect": [210, 10, 75, 125],
-          "reason": "paint property change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutEmbeddedObject OBJECT",
-      "reason": "style change"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow BODY",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutEmbeddedObject OBJECT",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/relative-sized-document-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/relative-sized-document-scrollbars-expected.txt
deleted file mode 100644
index 937546dd..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/relative-sized-document-scrollbars-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [6, 2, 788, 595],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [6, 4, 788, 592],
-          "reason": "disappeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGRoot svg",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGRect rect",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/repaint-paintorder-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/repaint-paintorder-expected.txt
deleted file mode 100644
index f33c38b..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/repaint-paintorder-expected.txt
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [456, 165, 134, 134],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon id='t3'",
-          "rect": [319, 165, 134, 134],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [183, 165, 134, 134],
-          "reason": "style change"
-        },
-        {
-          "object": "LayoutSVGPath polygon",
-          "rect": [47, 165, 134, 134],
-          "reason": "style change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGContainer use id='t1'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGViewportContainer svg id='poly'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGPath polygon",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGContainer use id='t2'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGViewportContainer svg id='poly'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGPath polygon",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGPath polygon id='t3'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutSVGPath polygon",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/resize-svg-invalidate-children-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/resize-svg-invalidate-children-2-expected.txt
deleted file mode 100644
index 71e6c2f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/resize-svg-invalidate-children-2-expected.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutSVGRoot svg",
-      "bounds": [500, 400],
-      "transform": 1
-    }
-  ],
-  "transforms": [
-    {
-      "id": 1,
-      "transform": [
-        [1, 0, 0, 0],
-        [0, 1, 0, 0],
-        [0, 0, 1, 0],
-        [50, 0, 0, 1]
-      ],
-      "flattenInheritedTransform": false
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='target'",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutSVGRoot svg",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/resize-svg-invalidate-children-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/resize-svg-invalidate-children-expected.txt
deleted file mode 100644
index f6e3176..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/resize-svg-invalidate-children-expected.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [58, 58, 100, 100],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutSVGRoot svg",
-          "rect": [33, 33, 50, 50],
-          "reason": "paint property change"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='target'",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutSVGRoot svg",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/tabgroup-expected.txt
deleted file mode 100644
index 2e23193..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/tabgroup-expected.txt
+++ /dev/null
@@ -1,1020 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutSVGContainer g",
-          "rect": [389, 37, 316, 82],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGContainer g",
-          "rect": [262, 278, 303, 303],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGContainer g",
-          "rect": [6, 256, 238, 160],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGPath path",
-          "rect": [6, 256, 238, 160],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGPath path",
-          "rect": [6, 256, 238, 160],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGPath path",
-          "rect": [6, 256, 238, 160],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGContainer g",
-          "rect": [506, 233, 238, 159],
-          "reason": "appeared"
-        },
-        {
-          "object": "InlineTextBox 'This is a tabgroup with triangular tab corners'",
-          "rect": [15, 291, 211, 37],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGContainer g id='tabgroupRect'",
-          "rect": [37, 6, 160, 238],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [66, 257, 57, 29],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [10, 257, 50, 29],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [130, 257, 47, 29],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [184, 257, 32, 29],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRect'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRect__0'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Biography'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRect__0_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRect__2'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Events'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRect__2_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRect__3'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Portrait'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRect__3_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRect__1'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Relations'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRect__1_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupTriangle'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupTriangle__1'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Download'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Folder'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupTriangle__2'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Your'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Account'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupTriangle__3'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Help'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox '& Info'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupTriangle__0'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Geodata'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Browser'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text id='contentTabGroupTriangle0'",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'This is a tabgroup with triangular tab corners'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'and a double line tab. (use \"\\n\" as a line separator)'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Click on the second tab to see oversize content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectTriangle'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectTriangle__0'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Biography'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectTriangle__0_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectTriangle__1'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Relations'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectTriangle__1_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectTriangle__3'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Portrait'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectTriangle__3_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectTriangle__2'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Events'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectTriangle__2_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRound'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRound__0'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Biography'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRound__0_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRound__2'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Events'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRound__2_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRound__3'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Portrait'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRound__3_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRound__1'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Relations'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRound__1_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectRound'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectRound__1'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Relations'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectRound__1_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectRound__2'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Events'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectRound__2_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectRound__3'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Portrait'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectRound__3_content'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGPath path id='tabgroupRectRound__0'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGText text",
-      "reason": "appeared"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGTSpan tspan",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineFlowBox",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGInlineText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'Biography'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutSVGContainer g id='tabgroupRectRound__0_content'",
-      "reason": "appeared"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-overflow-auto-in-overflow-auto-scrolled-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-overflow-auto-in-overflow-auto-scrolled-expected.txt
deleted file mode 100644
index 01f5ced..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-overflow-auto-in-overflow-auto-scrolled-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='innerDiv'",
-          "rect": [10, 8, 302, 300],
-          "reason": "paint property change"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [762, 8, 15, 300],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "subtree"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutTable TABLE",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableSection TBODY",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-overflow-scroll-in-overflow-scroll-scrolled-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-overflow-scroll-in-overflow-scroll-scrolled-expected.txt
deleted file mode 100644
index 01f5ced..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-overflow-scroll-in-overflow-scroll-scrolled-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV id='innerDiv'",
-          "rect": [10, 8, 302, 300],
-          "reason": "paint property change"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [762, 8, 15, 300],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV id='innerDiv'",
-      "reason": "subtree"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutTable TABLE",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableSection TBODY",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-shrink-row-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-shrink-row-repaint-expected.txt
deleted file mode 100644
index 9441ca19..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table-shrink-row-repaint-expected.txt
+++ /dev/null
@@ -1,513 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [785, 850],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutView #document",
-          "rect": [0, 850, 785, 200],
-          "reason": "incremental"
-        },
-        {
-          "object": "LayoutTableCell TD id='resizeMe'",
-          "rect": [8, 112, 769, 210],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 982, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 922, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 862, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 802, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 782, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 742, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 722, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 682, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 662, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 622, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 602, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 562, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 542, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 502, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 482, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 442, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 422, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 382, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 362, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 322, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 302, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 242, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 182, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [8, 122, 769, 60],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '13'",
-          "rect": [13, 1002, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '12'",
-          "rect": [13, 942, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '11'",
-          "rect": [13, 882, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '10'",
-          "rect": [13, 822, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '13'",
-          "rect": [13, 802, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '12'",
-          "rect": [13, 742, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '11'",
-          "rect": [13, 682, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '10'",
-          "rect": [13, 622, 16, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '9'",
-          "rect": [13, 762, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '8'",
-          "rect": [13, 702, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '7'",
-          "rect": [13, 642, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '6'",
-          "rect": [13, 582, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '9'",
-          "rect": [13, 562, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '5'",
-          "rect": [13, 522, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '8'",
-          "rect": [13, 502, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '4'",
-          "rect": [13, 462, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '7'",
-          "rect": [13, 442, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '3'",
-          "rect": [13, 402, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '6'",
-          "rect": [13, 382, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '2'",
-          "rect": [13, 342, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '5'",
-          "rect": [13, 322, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '4'",
-          "rect": [13, 262, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '3'",
-          "rect": [13, 202, 8, 19],
-          "reason": "geometry"
-        },
-        {
-          "object": "InlineTextBox '2'",
-          "rect": [13, 142, 8, 19],
-          "reason": "geometry"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutTableCell TD id='resizeMe'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '2'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '3'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '4'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '5'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '6'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '7'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '8'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '9'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '10'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '11'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '12'",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableRow TR",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "geometry"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "geometry"
-    },
-    {
-      "object": "InlineTextBox '13'",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/text-match-document-change-expected.txt
deleted file mode 100644
index 205fd07..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/text-match-document-change-expected.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "InlineTextBox 'Find-in-page 'findme', then click here)'",
-          "rect": [18, 130, 251, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'To be changed: findme (Manual testing:'",
-          "rect": [18, 130, 251, 39],
-          "reason": "disappeared"
-        },
-        {
-          "object": "InlineTextBox 'After change'",
-          "rect": [18, 130, 82, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "VerticalScrollbar",
-          "rect": [295, 102, 15, 400],
-          "reason": "scroll control"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='to-be-changed'",
-      "reason": "full"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "full"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "appeared"
-    },
-    {
-      "object": "InlineTextBox 'After change'",
-      "reason": "appeared"
-    },
-    {
-      "object": "LayoutBlockFlow DIV",
-      "reason": "geometry"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/textarea-caret-expected.txt
deleted file mode 100644
index 6ea8f41f..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/textarea-caret-expected.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [7, 7, 183, 40],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [7, 7, 183, 40],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [7, 7, 183, 40],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutBlockFlow HTML",
-          "rect": [8, 8, 181, 38],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [9, 11, 179, 16],
-          "reason": "appeared"
-        },
-        {
-          "object": "LayoutTextControl TEXTAREA id='editor'",
-          "rect": [9, 30, 164, 15],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutTextControl TEXTAREA id='editor'",
-      "reason": "subtree"
-    },
-    {
-      "object": "LayoutTextControl TEXTAREA id='editor'",
-      "reason": "geometry"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll control"
-    },
-    {
-      "object": "LayoutBlockFlow DIV id='inner-editor'",
-      "reason": "subtree"
-    },
-    {
-      "object": "RootInlineBox",
-      "reason": "subtree"
-    },
-    {
-      "object": "Caret",
-      "reason": "caret"
-    },
-    {
-      "object": "LayoutText #text",
-      "reason": "subtree"
-    },
-    {
-      "object": "InlineTextBox '------------------------------------------------------------'",
-      "reason": "subtree"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/transform-absolute-in-positioned-container-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/transform-absolute-in-positioned-container-expected.txt
deleted file mode 100644
index 35c0f29e..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/transform-absolute-in-positioned-container-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [802, 585],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow (relative positioned) DIV id='box' class='rotated'",
-          "rect": [76, 190, 286, 286],
-          "reason": "paint property change"
-        },
-        {
-          "object": "LayoutBlockFlow (relative positioned) DIV id='box'",
-          "rect": [118, 232, 202, 202],
-          "reason": "paint property change"
-        }
-      ]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-child-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-child-expected.txt
deleted file mode 100644
index 2a4f07cb..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-child-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV class='container'",
-          "rect": [214, 21, 100, 100],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV class='target'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-parent-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-parent-expected.txt
deleted file mode 100644
index f86e7d3..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-parent-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV class='container'",
-          "rect": [29, 29, 100, 100],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV class='target'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-same-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-same-expected.txt
deleted file mode 100644
index 1d40c08..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/vertical-overflow-same-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow DIV class='vertical-rl container'",
-          "rect": [29, 21, 100, 100],
-          "reason": "appeared"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutBlockFlow DIV class='target'",
-      "reason": "style change"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-live-update-list.html b/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-live-update-list.html
index d56d0db0..9030841 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-live-update-list.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-live-update-list.html
@@ -1,34 +1,35 @@
 <html>
 <head>
+<meta name="timeout" content="long">
 <script src="../inspector-test.js"></script>
 <script src="cache-storage-test.js"></script>
 <script>
 
-function test() {
-  var cacheStorageModel = TestRunner.mainTarget.model(SDK.ServiceWorkerCacheModel);
+async function test() {
+  var cacheStorageModel = InspectorTest.mainTarget.model(SDK.ServiceWorkerCacheModel);
   cacheStorageModel.enable();
+  cacheStorageModel._throttler._timeout = 0;
 
-  function errorAndExit(error) {
-    if (error)
-      TestRunner.addResult(error);
-    TestRunner.completeTest();
-  }
+  await InspectorTest.clearAllCaches();
+  await InspectorTest.dumpCacheTree();
 
-  function main() {
-    ApplicationTestRunner.clearAllCaches()
-        .then(ApplicationTestRunner.dumpCacheTree)
-        .then(ApplicationTestRunner.createCache.bind(this, 'testCache1'))
-        .then(ApplicationTestRunner.dumpCacheTree)
-        .then(ApplicationTestRunner.createCache.bind(this, 'testCache2'))
-        .then(ApplicationTestRunner.dumpCacheTree)
-        .then(ApplicationTestRunner.deleteCache.bind(this, 'testCache1'))
-        .then(ApplicationTestRunner.dumpCacheTree)
-        .then(ApplicationTestRunner.clearAllCaches)
-        .then(TestRunner.completeTest)
-        .catch(errorAndExit);
-  }
+  var promise = InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, '_cacheAdded');
+  InspectorTest.createCache('testCache1');
+  await promise;
+  await InspectorTest.dumpCacheTreeNoRefresh();
 
-  ApplicationTestRunner.waitForCacheRefresh(main);
+  promise = InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, '_cacheAdded');
+  InspectorTest.createCache('testCache2');
+  await promise;
+  await InspectorTest.dumpCacheTreeNoRefresh();
+
+  promise = InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, '_cacheRemoved');
+  InspectorTest.deleteCache('testCache1');
+  await promise;
+  await InspectorTest.dumpCacheTreeNoRefresh();
+
+  await InspectorTest.clearAllCaches();
+  InspectorTest.completeTest();
 }
 </script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js
index 6952408..48bbe24 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/isolated-filesystem-test.js
@@ -62,7 +62,7 @@
     addFileMapping: function(urlPrefix, pathPrefix)
     {
         var fileSystemMapping = new Persistence.FileSystemMapping(Persistence.isolatedFileSystemManager);
-        fileSystemMapping.addFileSystem(this.fileSystemPath);
+        fileSystemMapping._addFileSystemPath(this.fileSystemPath);
         fileSystemMapping.addFileMapping(this.fileSystemPath, urlPrefix, pathPrefix);
         fileSystemMapping.dispose();
         Persistence.fileSystemMapping._loadFromSettings();
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/blob-url-in-iframe.html b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/blob-url-in-iframe.html
index 62c1df15..cad7467 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/blob-url-in-iframe.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/blob-url-in-iframe.html
@@ -9,22 +9,24 @@
 </p>
 
 <script>
-if (location.protocol != 'https:')
-    location = 'https://127.0.0.1:8443/security/mixedContent/blob-url-in-iframe.html';
-
 if (window.testRunner) {
     testRunner.dumpAsText();
     testRunner.dumpChildFramesAsText();
     testRunner.waitUntilDone();
 }
-var iframe = document.querySelector('iframe');
-iframe.onload = function () {
-    if (window.testRunner)
-        testRunner.notifyDone();
-};
 
-var b = new Blob(['<h1>PASS (1/1)</h1>'], { type: 'text/html' });
-iframe.src = URL.createObjectURL(b);
+if (location.protocol != 'https:') {
+    location = 'https://127.0.0.1:8443/security/mixedContent/blob-url-in-iframe.html';
+} else {
+    var iframe = document.querySelector('iframe');
+    iframe.onload = function () {
+        if (window.testRunner)
+            testRunner.notifyDone();
+    };
+
+    var b = new Blob(['<h1>PASS (1/1)</h1>'], { type: 'text/html' });
+    iframe.src = URL.createObjectURL(b);
+}
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-method-denied-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-method-denied-expected.txt
deleted file mode 100644
index 6014db6..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-method-denied-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 19: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=method: Method DELETE is not allowed by Access-Control-Allow-Methods in preflight response.
-PASS: Request successfully blocked.
-
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-method-denied.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-method-denied.html
deleted file mode 100644
index 5ec4539e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-method-denied.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<html>
-<body>
-<pre id='console'></pre>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
-}
-
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-(function() {
-    var xhr = new XMLHttpRequest();
-
-    try {
-        xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=reset", false);
-        xhr.send(null);
-    } catch(e) {
-        log("FAIL: Unable to reset server state: [" + e.message + "].");
-        return;
-    }
-
-    xhr = new XMLHttpRequest();
-
-    try {
-        xhr.open("DELETE", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=method", true);
-    } catch(e) {
-        log("FAIL: Exception thrown. Cross-domain access is not allowed in first 'open'. [" + e.message + "].");
-        return;
-    }
-
-    xhr.onerror = function() {
-        xhr = new XMLHttpRequest();
-
-        try {
-            xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=complete", false);
-            try {
-                xhr.send(null);
-            } catch(e) {
-                log("FAIL: Exception thrown. Cross-domain access is not allowed in second 'send'. [" + e.message + "].");
-            }
-        } catch(e) {
-            log("FAIL: Exception thrown. Cross-domain access is not allowed in second 'open'. [" + e.message + "].");
-        }
-
-        log(xhr.responseText);
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-
-    xhr.onreadystatechange = function() {
-        if (xhr.readyState == 4 && xhr.status == 200)
-            log("FAIL: Cross-domain access allowed in first send without throwing an exception");
-    }
-
-    xhr.send(null);
-})();
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-data-saver.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-data-saver.html
deleted file mode 100644
index e8cbda9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-data-saver.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<html>
-<body>
-<p>Test that 'Save-Data' header is treated as a simple header and preflight request is not created. Should print PASS.</p>
-<div id="log"></div>
-<script>
-window.internals.settings.setDataSaverEnabled(true);
-
-function log(message) {
-    document.getElementById("log").innerHTML += message + "<br>";
-}
-
-if (window.layoutTestController) {
-    layoutTestController.dumpAsText();
-    layoutTestController.waitUntilDone();
-}
-
-var xhr = new XMLHttpRequest();
-xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-request-invalid-status.php?code=400");
-xhr.onerror = function () {
-    log("FAIL");
-    if (window.layoutTestController)
-        layoutTestController.notifyDone();
-};
-xhr.onload = function () {
-    log("PASS");
-    if (window.layoutTestController)
-        layoutTestController.notifyDone();
-};
-xhr.send();
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-sync-header-denied-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-sync-header-denied-expected.txt
deleted file mode 100644
index dfb79e2..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-sync-header-denied-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 17: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 35: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=header: Request header field X-NON-STANDARD is not allowed by Access-Control-Allow-Headers in preflight response.
-PASS: Request successfully blocked.
-
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-sync-header-denied.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-sync-header-denied.html
deleted file mode 100644
index f143da7..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-sync-header-denied.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<html>
-<body>
-<pre id='console'></pre>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
-}
-
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-(function() {
-    var xhr = new XMLHttpRequest();
-
-    try {
-        xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=reset", false);
-        xhr.send(null);
-    } catch(e) {
-        log("FAIL: Unable to reset server state: [" + e.message + "].");
-        return;
-    }
-
-    xhr = new XMLHttpRequest();
-
-    try {
-        xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=header", false);
-        xhr.setRequestHeader("X-NON-STANDARD", "filler");
-    } catch(e) {
-        log("FAIL: Exception thrown. Cross-domain access is not allowed in first 'open'. [" + e.message + "].");
-        return;
-    }
-
-    try {
-        xhr.send(null);
-        log("FAIL: Cross-domain access allowed in first send without throwing an exception");
-        return;
-    } catch(e) {
-        // Eat the exception.
-    }
-
-    xhr = new XMLHttpRequest();
-
-    try {
-        xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=complete", false);
-    } catch(e) {
-        log("FAIL: Exception thrown. Cross-domain access is not allowed in second 'open'. [" + e.message + "].");
-        return;
-    }
-
-    try {
-        xhr.send(null);
-    } catch(e) {
-        log("FAIL: Exception thrown. Cross-domain access is not allowed in second 'send'. [" + e.message + "].");
-        return;
-    }
-
-    log(xhr.responseText);
-})();
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-data-saver-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/chromium/access-control-preflight-data-saver-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-data-saver-expected.txt
rename to third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/chromium/access-control-preflight-data-saver-expected.txt
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/chromium/access-control-preflight-data-saver.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/chromium/access-control-preflight-data-saver.html
new file mode 100644
index 0000000..de47367
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/chromium/access-control-preflight-data-saver.html
@@ -0,0 +1,33 @@
+<html>
+<body>
+<!--This test is specific to Chromium, so it will not be ported to WPT.-->
+<p>Test that 'Save-Data' header is treated as a simple header and preflight request is not created. Should print PASS.</p>
+<div id="log"></div>
+<script>
+window.internals.settings.setDataSaverEnabled(true);
+
+function log(message) {
+    document.getElementById("log").innerHTML += message + "<br>";
+}
+
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+var xhr = new XMLHttpRequest();
+xhr.open("GET", "http://localhost:8000/xmlhttprequest/chromium/resources/access-control-preflight-request-invalid-status.php?code=400");
+xhr.onerror = function () {
+    log("FAIL");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+};
+xhr.onload = function () {
+    log("PASS");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+};
+xhr.send();
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-preflight-request-invalid-status.php b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/chromium/resources/access-control-preflight-request-invalid-status.php
similarity index 100%
rename from third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/access-control-preflight-request-invalid-status.php
rename to third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/chromium/resources/access-control-preflight-request-invalid-status.php
diff --git a/third_party/WebKit/LayoutTests/imagecapture/OWNERS b/third_party/WebKit/LayoutTests/imagecapture/OWNERS
index 57a9132d..d58b08f 100644
--- a/third_party/WebKit/LayoutTests/imagecapture/OWNERS
+++ b/third_party/WebKit/LayoutTests/imagecapture/OWNERS
@@ -1,2 +1,2 @@
-# TEAM: device-dev@chromium.org
+# TEAM: media-dev@chromium.org
 # COMPONENT: Blink>ImageCapture
diff --git a/third_party/WebKit/LayoutTests/inspector/file-system-mapping.html b/third_party/WebKit/LayoutTests/inspector/file-system-mapping.html
index d5d598b..2076dc6 100644
--- a/third_party/WebKit/LayoutTests/inspector/file-system-mapping.html
+++ b/third_party/WebKit/LayoutTests/inspector/file-system-mapping.html
@@ -12,13 +12,13 @@
 
   function addFileSystem(fileSystemMapping, path) {
     TestRunner.addResult('Adding file system ' + path);
-    fileSystemMapping.addFileSystem(path);
+    fileSystemMapping._addFileSystemPath(path);
     checkAndDumpFileSystemMapping(fileSystemMapping);
   }
 
   function removeFileSystem(fileSystemMapping, path) {
     TestRunner.addResult('Removing file system ' + path);
-    fileSystemMapping.removeFileSystem(path);
+    fileSystemMapping._removeFileSystemPath(path);
     checkAndDumpFileSystemMapping(fileSystemMapping);
   }
 
@@ -80,7 +80,7 @@
   var fileSystemMapping = new Persistence.FileSystemMapping(Persistence.isolatedFileSystemManager);
   var fileSystemPaths = Object.keys(fileSystemMapping._fileSystemMappings);
   for (var i = 0; i < fileSystemPaths.length; ++i)
-    fileSystemMapping.removeFileSystem(fileSystemPaths[i]);
+    fileSystemMapping._removeFileSystemPath(fileSystemPaths[i]);
 
   // Now fill it with file systems.
   checkAndDumpFileSystemMapping(fileSystemMapping);
diff --git a/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps-empty.html b/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps-empty.html
index 51f2244..e0a02e8 100644
--- a/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps-empty.html
+++ b/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps-empty.html
@@ -1,7 +1,8 @@
 <!DOCTYPE html>
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/installedapp/installed_app_provider.mojom.js"></script>
 <script src="resources/installedapp-test-helper.js"></script>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps.html b/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps.html
index 66fedf26..012a288 100644
--- a/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps.html
+++ b/third_party/WebKit/LayoutTests/installedapp/getinstalledrelatedapps.html
@@ -2,7 +2,8 @@
 <link rel="manifest" href="resources/manifest.json">
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/WebKit/public/platform/modules/installedapp/installed_app_provider.mojom.js"></script>
 <script src="resources/installedapp-test-helper.js"></script>
 <script>
 
diff --git a/third_party/WebKit/LayoutTests/installedapp/resources/installedapp-test-helper.js b/third_party/WebKit/LayoutTests/installedapp/resources/installedapp-test-helper.js
index 309fc11..ab1872c 100644
--- a/third_party/WebKit/LayoutTests/installedapp/resources/installedapp-test-helper.js
+++ b/third_party/WebKit/LayoutTests/installedapp/resources/installedapp-test-helper.js
@@ -14,59 +14,48 @@
     assert_relatedapplication_equals(actual[i], expected[i], description);
 }
 
-let mockInstalledAppProvider = loadMojoModules(
-    'mockInstalledAppProvider',
-    ['mojo/public/js/bindings',
-     'third_party/WebKit/public/platform/modules/installedapp/installed_app_provider.mojom',
-    ]).then(mojo => {
-  let [bindings, installedAppProvider] = mojo.modules;
+class MockInstalledAppProvider {
+  constructor(interfaceProvider) {
+    this.bindingSet_ = new mojo.BindingSet(blink.mojom.InstalledAppProvider);
 
-  class MockInstalledAppProvider {
-    constructor(interfaceProvider) {
-      this.bindingSet_ =
-          new bindings.BindingSet(installedAppProvider.InstalledAppProvider);
-
-      interfaceProvider.addInterfaceOverrideForTesting(
-          installedAppProvider.InstalledAppProvider.name,
-          handle => this.bindingSet_.addBinding(this, handle));
-    }
-
-    // Returns a Promise that gets rejected if the test should fail.
-    init_() {
-      // sequence of [expectedRelatedApps, installedApps].
-      this.callQueue_ = [];
-
-      return new Promise((resolve, reject) => {this.reject_ = reject});
-    }
-
-    filterInstalledApps(relatedApps) {
-      let callback = null;
-      let result = new Promise(resolve => {callback = resolve;});
-
-      if (!this.callQueue_.length) {
-        this.reject_('Unexpected call to mojo FilterInstalledApps method');
-        return result;
-      }
-
-      let [expectedRelatedApps, installedApps] = this.callQueue_.shift();
-      try {
-        assert_array_relatedapplication_equals(
-            relatedApps, expectedRelatedApps);
-      } catch (e) {
-        this.reject_(e);
-        return result;
-      }
-      callback({installedApps: installedApps});
-
-      return result;
-    }
-
-    pushExpectedCall(expectedRelatedApps, installedApps) {
-      this.callQueue_.push([expectedRelatedApps, installedApps]);
-    }
+    this.interceptor_ = new MojoInterfaceInterceptor(
+        blink.mojom.InstalledAppProvider.name);
+    this.interceptor_.oninterfacerequest =
+        e => this.bindingSet_.addBinding(this, e.handle);
+    this.interceptor_.start();
   }
-  return new MockInstalledAppProvider(mojo.frameInterfaces);
-});
+
+  // Returns a Promise that gets rejected if the test should fail.
+  init_() {
+    // sequence of [expectedRelatedApps, installedApps].
+    this.callQueue_ = [];
+
+    return new Promise((resolve, reject) => { this.reject_ = reject });
+  }
+
+  async filterInstalledApps(relatedApps) {
+    if (!this.callQueue_.length) {
+      this.reject_('Unexpected call to mojo FilterInstalledApps method');
+      return;
+    }
+
+    let [expectedRelatedApps, installedApps] = this.callQueue_.shift();
+    try {
+      assert_array_relatedapplication_equals(relatedApps, expectedRelatedApps);
+    } catch (e) {
+      this.reject_(e);
+      return;
+    }
+
+    return { installedApps: installedApps };
+  }
+
+  pushExpectedCall(expectedRelatedApps, installedApps) {
+    this.callQueue_.push([expectedRelatedApps, installedApps]);
+  }
+}
+
+let mockInstalledAppProvider = new MockInstalledAppProvider();
 
 // Creates a test case that uses a mock InstalledAppProvider.
 // |func| is a function that takes (t, mock), where |mock| is a
@@ -75,8 +64,8 @@
 // getInstalledRelatedApps().
 // |name| and |properties| are standard testharness arguments.
 function installedapp_test(func, name, properties) {
-  promise_test(t => mockInstalledAppProvider.then(mock => {
-    let mockPromise = mock.init_();
-    return Promise.race([func(t, mock), mockPromise]);
-  }), name, properties);
+  promise_test(t => {
+    let mockPromise = mockInstalledAppProvider.init_();
+    return Promise.race([func(t, mockInstalledAppProvider), mockPromise]);
+  }, name, properties);
 }
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc000-empty.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc000-empty.vtt
deleted file mode 100644
index e69de29..0000000
--- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc000-empty.vtt
+++ /dev/null
diff --git a/third_party/WebKit/LayoutTests/media/track/track-webvtt-tc000-empty.html b/third_party/WebKit/LayoutTests/media/track/track-webvtt-tc000-empty.html
deleted file mode 100644
index c115253..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-webvtt-tc000-empty.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<title>Tests that an empty file is not recognized as a WebVTT file.</title>
-<video>
-    <track src="captions-webvtt/tc000-empty.vtt" default>
-</video>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-async_test(function(t) {
-    var track = document.querySelector("track");
-
-    track.onload = t.step_func_done(function() {
-        assert_equals(track.track.cues.length, 0);
-    });
-});
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/mojo/bind-intercepted-interface-in-worker.html b/third_party/WebKit/LayoutTests/mojo/bind-intercepted-interface-in-worker.html
index 50d4293..6158ef1d 100644
--- a/third_party/WebKit/LayoutTests/mojo/bind-intercepted-interface-in-worker.html
+++ b/third_party/WebKit/LayoutTests/mojo/bind-intercepted-interface-in-worker.html
@@ -4,12 +4,6 @@
 <script>
 'use strict';
 
-async_test(t => {
-  let worker = new Worker('resources/bind-intercepted-interface-in-worker.js');
-  worker.postMessage({});
-  worker.onmessage = e => {
-    if (e.data == 'PASS')
-      t.done();
-  };
-}, 'Can implement a Mojo service and intercept it from a worker');
+let worker = new Worker('resources/bind-intercepted-interface-in-worker.js');
+fetch_tests_from_worker(worker);
 </script>
diff --git a/third_party/WebKit/LayoutTests/mojo/bind-interface.html b/third_party/WebKit/LayoutTests/mojo/bind-interface.html
index 08298c63..a4bfbcc88 100644
--- a/third_party/WebKit/LayoutTests/mojo/bind-interface.html
+++ b/third_party/WebKit/LayoutTests/mojo/bind-interface.html
@@ -3,23 +3,9 @@
 <script src="../resources/testharnessreport.js"></script>
 <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
 <script src="file:///gen/content/test/data/mojo_layouttest_test.mojom.js"></script>
+<script src="resources/helpers.js"></script>
 <script>
 
-const kTestReply = "hehe got ya";
-
-// An impl of the test interface which replies to reverse() with a fixed
-// message rather than the normally expected value.
-class TestHelperImpl {
-  constructor() {
-    this.binding_ =
-        new mojo.Binding(content.mojom.MojoLayoutTestHelper, this);
-  }
-  bindRequest(request) { this.binding_.bind(request); }
-  reverse(message) {
-    return Promise.resolve({ reversed: kTestReply });
-  }
-}
-
 promise_test(() => {
   let helper = new content.mojom.MojoLayoutTestHelperPtr;
   Mojo.bindInterface(content.mojom.MojoLayoutTestHelper.name,
@@ -84,22 +70,47 @@
 }, "can request interfaces at process scope");
 
 promise_test(() => {
+  let helperImpl = new TestHelperImpl;
+  let interceptor = new MojoInterfaceInterceptor(
+      content.mojom.MojoLayoutTestHelper.name, "process");
+  interceptor.oninterfacerequest = e => {
+    helperImpl.bindRequest(e.handle);
+  };
+  interceptor.start();
+
+  let helper = new content.mojom.MojoLayoutTestHelperPtr;
+  Mojo.bindInterface(content.mojom.MojoLayoutTestHelper.name,
+                     mojo.makeRequest(helper).handle,
+                     "process");
+  interceptor.stop();
+
+  return helper.reverse("doesn't matter").then(reply => {
+    assert_equals(reply.reversed, kTestReply);
+  });
+}, "can intercept interfaces at process scope");
+
+test(() => {
   const kTestInterfaceName = "foo::mojom::Ba1r";
   let a = new MojoInterfaceInterceptor(kTestInterfaceName);
   let b = new MojoInterfaceInterceptor(kTestInterfaceName);
   a.oninterfacerequest = () => {};
   b.oninterfacerequest = () => {};
   a.start();
-  try {
-    b.start();
-  } catch (e) {
-    return Promise.resolve();
-  } finally {
-    a.stop();
-  }
-  return Promise.reject();
+  assert_throws('InvalidModificationError', () => { b.start(); });
+  a.stop();
 }, "interface interceptors are mutually exclusive");
 
+test(() => {
+  const kTestInterfaceName = "foo::mojom::Ba1r";
+  let a = new MojoInterfaceInterceptor(kTestInterfaceName, "process");
+  let b = new MojoInterfaceInterceptor(kTestInterfaceName, "process");
+  a.oninterfacerequest = () => {};
+  b.oninterfacerequest = () => {};
+  a.start();
+  assert_throws('InvalidModificationError', () => { b.start(); });
+  a.stop();
+}, "process scope interface interceptors are mutually exclusive");
+
 test(async t => {
   const kTestInterfaceName = "foo::mojom::Bar";
 
diff --git a/third_party/WebKit/LayoutTests/mojo/intercept-interface-for-worker.html b/third_party/WebKit/LayoutTests/mojo/intercept-interface-for-worker.html
new file mode 100644
index 0000000..341cbe4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/mojo/intercept-interface-for-worker.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/content/test/data/mojo_layouttest_test.mojom.js"></script>
+<script src="resources/helpers.js"></script>
+<script>
+'use strict';
+
+// TODO(reillyg): This test currently expects the behavior that interfaces
+// intercepted at process scope will override requests made from workers at
+// context scope. This intentional and will be fixed when it is possible for
+// workers to distinguish between the two.
+let helperImpl = new TestHelperImpl;
+let interceptor = new MojoInterfaceInterceptor(
+    content.mojom.MojoLayoutTestHelper.name, "process");
+interceptor.oninterfacerequest = e => {
+  helperImpl.bindRequest(e.handle);
+};
+interceptor.start();
+
+fetch_tests_from_worker(new Worker('resources/expect-test-reply.js'));
+
+add_completion_callback(() => {
+  interceptor.stop();
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/mojo/resources/bind-intercepted-interface-in-worker.js b/third_party/WebKit/LayoutTests/mojo/resources/bind-intercepted-interface-in-worker.js
index 5b15920..3b1340a 100644
--- a/third_party/WebKit/LayoutTests/mojo/resources/bind-intercepted-interface-in-worker.js
+++ b/third_party/WebKit/LayoutTests/mojo/resources/bind-intercepted-interface-in-worker.js
@@ -1,37 +1,35 @@
 importScripts('../../resources/testharness.js');
 importScripts('file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js');
 importScripts('file:///gen/content/test/data/mojo_layouttest_test.mojom.js');
+importScripts('helpers.js');
 
-class MojoLayoutTestHelper {
-  constructor() {
-    this.bindingSet_ = new mojo.BindingSet(
-        content.mojom.MojoLayoutTestHelper);
-    this.interceptor_ = new MojoInterfaceInterceptor(
-        content.mojom.MojoLayoutTestHelper.name);
-    this.interceptor_.oninterfacerequest =
-        e => this.bindingSet_.addBinding(this, e.handle);
-    this.interceptor_.start();
-  }
+promise_test(async () => {
+  let helperImpl = new TestHelperImpl;
+  let interceptor =
+      new MojoInterfaceInterceptor(content.mojom.MojoLayoutTestHelper.name);
+  interceptor.oninterfacerequest = e => {
+    helperImpl.bindRequest(e.handle);
+  };
+  interceptor.start();
 
-  getLastString() {
-    return this.lastString_;
-  }
-
-  reverse(message) {
-    this.lastString_ = message;
-    return Promise.resolve({ reversed: message.split('').reverse().join('') });
-  }
-}
-
-let mojoLayoutTestHelperImpl = new MojoLayoutTestHelper;
-
-onmessage = async () => {
   let helper = new content.mojom.MojoLayoutTestHelperPtr;
   Mojo.bindInterface(content.mojom.MojoLayoutTestHelper.name,
                      mojo.makeRequest(helper).handle);
 
   let response = await helper.reverse('the string');
-  assert_equals(response.reversed, 'gnirts eht');
-  assert_equals(mojoLayoutTestHelperImpl.getLastString(), 'the string');
-  postMessage('PASS');
-};
+  assert_equals(response.reversed, kTestReply);
+  assert_equals(helperImpl.getLastString(), 'the string');
+}, 'Can implement a Mojo service and intercept it from a worker');
+
+test(t => {
+  assert_throws(
+      'NotSupportedError',
+      () => {
+        new MojoInterfaceInterceptor(content.mojom.MojoLayoutTestHelper.name,
+                                     "process");
+      });
+}, 'Cannot create a MojoInterfaceInterceptor with process scope');
+
+// done() is needed because the testharness is running as if explicit_done
+// was specified.
+done();
diff --git a/third_party/WebKit/LayoutTests/mojo/resources/expect-test-reply.js b/third_party/WebKit/LayoutTests/mojo/resources/expect-test-reply.js
new file mode 100644
index 0000000..a4e91b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/mojo/resources/expect-test-reply.js
@@ -0,0 +1,15 @@
+importScripts('../../resources/testharness.js');
+importScripts('file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js');
+importScripts('file:///gen/content/test/data/mojo_layouttest_test.mojom.js');
+importScripts('helpers.js');
+
+promise_test(async () => {
+  let helper = new content.mojom.MojoLayoutTestHelperPtr;
+  Mojo.bindInterface(content.mojom.MojoLayoutTestHelper.name,
+                     mojo.makeRequest(helper).handle);
+
+  let response = await helper.reverse('the string');
+  assert_equals(response.reversed, kTestReply);
+}, 'Expect test interface to be overridden in worker');
+
+done();
diff --git a/third_party/WebKit/LayoutTests/mojo/resources/helpers.js b/third_party/WebKit/LayoutTests/mojo/resources/helpers.js
new file mode 100644
index 0000000..31178fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/mojo/resources/helpers.js
@@ -0,0 +1,16 @@
+const kTestReply = "hehe got ya";
+
+// An impl of the test interface which replies to reverse() with a fixed
+// message rather than the normally expected value.
+class TestHelperImpl {
+  constructor() {
+    this.binding_ =
+        new mojo.Binding(content.mojom.MojoLayoutTestHelper, this);
+  }
+  bindRequest(request) { this.binding_.bind(request); }
+  getLastString() { return this.lastString_; }
+  reverse(message) {
+    this.lastString_ = message;
+    return Promise.resolve({ reversed: kTestReply });
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/absolute-position-changed-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/absolute-position-changed-expected.txt
index 8b05801..9503fa4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/absolute-position-changed-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/absolute-position-changed-expected.txt
@@ -16,6 +16,18 @@
           "rect": [100, 500, 100, 100],
           "reason": "geometry"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -500, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-expected.txt
index 94ea085..cb194e1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-expected.txt
@@ -4,7 +4,19 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-firstline-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-firstline-expected.txt
index 94ea085..cb194e1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-firstline-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-background-offscreen-firstline-expected.txt
@@ -4,7 +4,19 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-offscreen-expected.txt
index 94ea085..cb194e1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-offscreen-expected.txt
@@ -4,7 +4,19 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt
index cc36b23..53b306d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/animated-gif-transformed-offscreen-expected.txt
@@ -8,9 +8,8 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='targetDiv'",
-      "position": [8, 8],
       "bounds": [2000, 2000],
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -20,6 +19,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, -1000, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/animated-png-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/animated-png-offscreen-expected.txt
index 94ea085..cb194e1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/animated-png-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/animated-png-offscreen-expected.txt
@@ -4,7 +4,19 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/animated-webp-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/animated-webp-offscreen-expected.txt
index 94ea085..cb194e1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/animated-webp-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/animated-webp-offscreen-expected.txt
@@ -4,7 +4,19 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt
index d305ecae..efd92f1d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/clip-path-constant-repaint-expected.txt
@@ -8,11 +8,10 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='clip'",
-      "position": [8, 8],
       "bounds": [800, 300],
       "backfaceVisibility": "hidden",
       "backgroundColor": "#FF0000E6",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -22,6 +21,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 100, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/composited-iframe-scroll-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/composited-iframe-scroll-repaint-expected.txt
index ebe7413..42d373c9 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/composited-iframe-scroll-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/composited-iframe-scroll-repaint-expected.txt
@@ -3,12 +3,25 @@
     {
       "name": "LayoutView #document",
       "bounds": [300, 516],
-      "backgroundColor": "#EEEEEE"
+      "backgroundColor": "#EEEEEE",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow BODY",
       "position": [8, 8],
-      "bounds": [284, 500]
+      "bounds": [284, 500],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -20, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
index b56ee46..b8a9f40 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
@@ -30,7 +30,8 @@
           "rect": [0, 500, 400, 1500],
           "reason": "background on scrolling contents layer"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -49,6 +50,18 @@
       "bounds": [0, 400]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1600, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "Scrolling Contents Layer",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
index b56ee46..b8a9f40 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
@@ -30,7 +30,8 @@
           "rect": [0, 500, 400, 1500],
           "reason": "background on scrolling contents layer"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -49,6 +50,18 @@
       "bounds": [0, 400]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1600, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "Scrolling Contents Layer",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
index b45dc22..6d18f80 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
@@ -4,18 +4,21 @@
       "name": "LayoutView #document",
       "bounds": [785, 30020],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "Squashing Containment Layer",
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow DIV class='compositedBehind'",
       "position": [8, 8],
       "bounds": [500, 500],
       "contentsOpaque": true,
-      "backgroundColor": "#00FFFF"
+      "backgroundColor": "#00FFFF",
+      "transform": 1
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV class='containerOverlapsComposited')",
@@ -32,6 +35,18 @@
           "rect": [25, 25, 50, 50],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt
index c0a8d80..cf3826f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt
@@ -5,7 +5,8 @@
       "bounds": [785, 2016],
       "contentsOpaque": true,
       "drawsContent": false,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow HTML",
@@ -21,7 +22,8 @@
           "rect": [0, 50, 100, 100],
           "reason": "subtree"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
@@ -29,7 +31,8 @@
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backfaceVisibility": "hidden",
-      "backgroundColor": "#FF0000"
+      "backgroundColor": "#FF0000",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow HTML (foreground) Layer",
@@ -45,6 +48,18 @@
           "rect": [0, 50, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-no-content-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-no-content-expected.txt
index 499288f7..bb0762418 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-no-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-no-content-expected.txt
@@ -4,13 +4,26 @@
       "name": "LayoutView #document",
       "bounds": [785, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
       "position": [100, 200],
       "bounds": [200, 200],
-      "drawsContent": false
+      "drawsContent": false,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-out-of-view-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-out-of-view-expected.txt
index ff74252..743a9e9f5 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-out-of-view-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-layer-out-of-view-expected.txt
@@ -4,21 +4,35 @@
       "name": "LayoutView #document",
       "bounds": [785, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
       "position": [100, -200],
       "bounds": [88, 88],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
       "position": [100, 1100],
       "bounds": [99, 99],
       "contentsOpaque": true,
-      "backgroundColor": "#C0C0C0"
+      "backgroundColor": "#C0C0C0",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-squahed-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-squahed-layer-expected.txt
index 7b401a8..407f521 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-squahed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scroll-fixed-squahed-layer-expected.txt
@@ -4,21 +4,35 @@
       "name": "LayoutView #document",
       "bounds": [785, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='main'",
       "position": [100, 200],
       "bounds": [200, 200],
       "contentsOpaque": true,
-      "backgroundColor": "#ADD8E6"
+      "backgroundColor": "#ADD8E6",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV class='squahed'",
       "position": [100, 250],
       "bounds": [200, 200],
       "contentsOpaque": true,
-      "backgroundColor": "#90EE90"
+      "backgroundColor": "#90EE90",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt
index 943e838e..5d244c1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/scrolling-without-painting-expected.txt
@@ -20,7 +20,8 @@
     {
       "name": "Scrolling Contents Layer",
       "position": [9, 9],
-      "bounds": [185, 1025]
+      "bounds": [185, 1025],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -52,6 +53,18 @@
       "position": [194, 194],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -25, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
index b5d76b5..b8460bee 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -27,7 +27,8 @@
           "rect": [0, 0, 1000, 1000],
           "reason": "style change"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -67,6 +68,18 @@
       "bounds": [15, 15]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-500, -400, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow DIV id='content'",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-viewport-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-viewport-scrolling-layer-expected.txt
index f3a009c9..05b4a291 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-viewport-scrolling-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-clip-composited-viewport-scrolling-layer-expected.txt
@@ -11,6 +11,18 @@
           "rect": [8, 8, 2000, 1500],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-900, -700, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
index 63ce703..eb5ff27 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
@@ -8,9 +8,8 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='composited-box'",
-      "position": [8, 8],
       "bounds": [102, 102],
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -20,6 +19,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [100, 100, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
index 4c76dd3..68a7058f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
@@ -12,15 +12,13 @@
     },
     {
       "name": "LayoutBlockFlow DIV",
-      "position": [8, 8],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#D3D3D3",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV id='target')",
-      "position": [28, 28],
       "bounds": [100, 100],
       "paintInvalidations": [
         {
@@ -29,16 +27,40 @@
           "reason": "style change"
         }
       ],
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
     {
       "id": 1,
-      "renderingContext": 1
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ],
+      "flattenInheritedTransform": false
     },
     {
       "id": 2,
+      "parent": 1,
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [28, 28, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/filter-on-html-element-with-fixed-position-child-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/filter-on-html-element-with-fixed-position-child-expected.txt
index c714e0b..7432a6d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/filter-on-html-element-with-fixed-position-child-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/filter-on-html-element-with-fixed-position-child-expected.txt
@@ -36,6 +36,18 @@
           "rect": [8, 8, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -10, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-after-scroll-expected.txt
index 0bfcb62a..0a7d3e9 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-after-scroll-expected.txt
@@ -16,6 +16,18 @@
           "rect": [8, 200, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -500, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt
index 3220ada..61452dd2b 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-and-absolute-position-scrolled-expected.txt
@@ -31,6 +31,18 @@
           "rect": [8, 8, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -500, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-move-after-scroll-expected.txt
index d017c13..6cc4e3f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-move-after-scroll-expected.txt
@@ -16,6 +16,18 @@
           "rect": [10, 270, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-fixed-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-fixed-move-after-scroll-expected.txt
index d017c13..6cc4e3f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-fixed-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-fixed-move-after-scroll-expected.txt
@@ -16,6 +16,18 @@
           "rect": [10, 270, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-transformed-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-transformed-move-after-scroll-expected.txt
index 4f4db09..b0031f2 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-transformed-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-child-of-transformed-move-after-scroll-expected.txt
@@ -16,6 +16,18 @@
           "rect": [18, 278, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-img-src-change-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-img-src-change-after-scroll-expected.txt
index 7a1f236..b3d94e0e 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-img-src-change-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-img-src-change-after-scroll-expected.txt
@@ -16,6 +16,18 @@
           "rect": [0, 50, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-move-after-scroll-expected.txt
index d017c13..6cc4e3f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-move-after-scroll-expected.txt
@@ -16,6 +16,18 @@
           "rect": [10, 270, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scale-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scale-expected.txt
index 9eb612c..07488b69 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scale-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scale-expected.txt
@@ -11,6 +11,18 @@
           "rect": [100, 300, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scroll-simple-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scroll-simple-expected.txt
index af53f600..2a3281d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scroll-simple-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-scroll-simple-expected.txt
@@ -16,6 +16,18 @@
           "rect": [8, 100, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-cell-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-cell-expected.txt
index 4b71291..786af4c5 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-cell-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-cell-expected.txt
@@ -31,6 +31,18 @@
           "rect": [50, 200, 100, 100],
           "reason": "appeared"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-expected.txt
index 27a72a55..273a16f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-expected.txt
@@ -41,6 +41,18 @@
           "rect": [0, 100, 100, 100],
           "reason": "disappeared"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-zindex-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-zindex-expected.txt
index f6d0f72..64f8cc72 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-zindex-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-table-overflow-zindex-expected.txt
@@ -31,6 +31,18 @@
           "rect": [0, 100, 100, 100],
           "reason": "disappeared"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-tranformed-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-tranformed-expected.txt
index 985e1632..5f47125 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-tranformed-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-tranformed-expected.txt
@@ -11,6 +11,18 @@
           "rect": [60, 110, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-absolute-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-absolute-scrolled-expected.txt
index afcec2a..bd70323 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-absolute-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-absolute-scrolled-expected.txt
@@ -4,7 +4,8 @@
       "name": "LayoutView #document",
       "bounds": [785, 2001],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='absolute'",
@@ -18,6 +19,18 @@
           "rect": [0, 100, 100, 100],
           "reason": "incremental"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -400, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-fixed-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-fixed-scrolled-expected.txt
index 4a5987f..c80ed2f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-fixed-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-under-composited-fixed-scrolled-expected.txt
@@ -4,7 +4,8 @@
       "name": "LayoutView #document",
       "bounds": [785, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='fixed-container'",
@@ -19,6 +20,18 @@
           "rect": [100, 100, 200, 200],
           "reason": "disappeared"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -400, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-with-border-under-composited-absolute-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-with-border-under-composited-absolute-scrolled-expected.txt
index 4130fca..1a4c2dc 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/fixed-with-border-under-composited-absolute-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/fixed-with-border-under-composited-absolute-scrolled-expected.txt
@@ -4,7 +4,8 @@
       "name": "LayoutView #document",
       "bounds": [785, 2001],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV id='absolute'",
@@ -18,6 +19,18 @@
           "rect": [0, 110, 120, 110],
           "reason": "incremental"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -400, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/full-viewport-repaint-for-background-attachment-fixed-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/full-viewport-repaint-for-background-attachment-fixed-expected.txt
index c79b4e56..82d7a73 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/full-viewport-repaint-for-background-attachment-fixed-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/full-viewport-repaint-for-background-attachment-fixed-expected.txt
@@ -11,6 +11,18 @@
           "rect": [0, 0, 785, 5000],
           "reason": "background"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
index 08af6ff..135e503a 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidate-after-composited-scroll-expected.txt
@@ -27,7 +27,8 @@
           "rect": [0, 2400, 100, 100],
           "reason": "style change"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -49,6 +50,18 @@
       ]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -2350, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow DIV id='target'",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt
index 305db14..daa2563 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/multiple-backgrounds-style-change-expected.txt
@@ -8,9 +8,8 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='test' class='composited box changed'",
-      "position": [8, 8],
       "bounds": [202, 202],
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -20,6 +19,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [50, 50, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/nested-fixed-iframe-scrolled-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/nested-fixed-iframe-scrolled-expected.txt
index 5c5f864..3ff28422 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/nested-fixed-iframe-scrolled-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/nested-fixed-iframe-scrolled-expected.txt
@@ -11,6 +11,18 @@
           "rect": [22, 522, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -400, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt
index 0c3d8363..cf3eb03 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-move-after-scroll-expected.txt
@@ -32,7 +32,8 @@
           "rect": [50, 200, 120, 50],
           "reason": "geometry"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -65,6 +66,18 @@
       "bounds": [15, 15]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -100, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV id='block'",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt
index eaf0b9b9..7c763eb4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/overflow-scroll-after-move-expected.txt
@@ -32,7 +32,8 @@
           "rect": [50, 200, 200, 50],
           "reason": "geometry"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -65,6 +66,18 @@
       "bounds": [15, 15]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV id='block'",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-expected.txt
new file mode 100644
index 0000000..c28aada
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-expected.txt
@@ -0,0 +1,132 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 2016],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='container'",
+      "position": [40, 50],
+      "bounds": [100, 100],
+      "backgroundColor": "#0000FF80",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='scrollable'",
+      "position": [104, 103],
+      "bounds": [302, 302],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Layer",
+      "position": [105, 104],
+      "bounds": [300, 300],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [105, 104],
+      "bounds": [795, 1491],
+      "drawsContent": false,
+      "transform": 2
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='transform'",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 4
+    },
+    {
+      "name": "Overflow Controls Host Layer",
+      "position": [104, 103],
+      "bounds": [302, 302],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [105, 404],
+      "bounds": [300, 0],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [405, 104],
+      "bounds": [0, 300],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -20, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -30, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [193, 181, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [3.53553390593274, 3.53553390593274, 0, 0],
+        [-3.53553390593274, 3.53553390593274, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-overlay-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-overlay-expected.html
new file mode 100644
index 0000000..796017bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-overlay-expected.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<body style="margin: 0">
+<label><input type="checkbox" checked>Show test</label>
+<label><input type="checkbox">Use solid colors</label>
+<br>
+<span>Expected Invalidations</span>
+<canvas id="canvas" width="2000" height="2000" style="border: 1px solid black">
+<script>
+  var context = canvas.getContext("2d");
+  context.fillStyle = 'rgba(255, 0, 0, 0.25)';
+  context.fillRect(60, 50, 10, 10);
+  context.translate(193, 131);
+  context.scale(5, 5);
+  context.rotate(Math.PI/4);
+  context.fillRect(20, 20, 10, 10);
+</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-overlay.html b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-overlay.html
new file mode 100644
index 0000000..4cddf98a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers-overlay.html
@@ -0,0 +1,402 @@
+<!-- Generated by Tools/Scripts/test-webkitpy
+ test case: TestRepaintOverlay.test_generate_repaint_overlay_html. -->
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>paint/invalidation/repaint-overlay/layers.html</title>
+<style>
+    body {
+        margin: 0;
+        padding: 0;
+    }
+    #overlay {
+        width: 2000px;
+        height: 2000px;
+        border: 1px solid black;
+    }
+    #test_frame {
+        position: absolute;
+        width: 800px;
+        height: 600px;
+        border: 0;
+    }
+    canvas {
+        position: absolute;
+    }
+    #actual_canvas {
+        display: none;
+    }
+</style>
+</head>
+<body>
+<label><input id="show-test" type="checkbox" checked onchange="toggle_test(this.checked)">Show test</label>
+<label><input id="use-solid-colors" type="checkbox" onchange="toggle_solid_color(this.checked)">Use solid colors</label>
+<br>
+<span id="overlay_type">Expected Invalidations</span>
+<div id="overlay">
+    <iframe id="test_frame"></iframe>
+    <canvas id="expected_canvas" width="2000" height="2000"></canvas>
+    <canvas id="actual_canvas" width="2000" height="2000"></canvas>
+</div>
+<script>
+var overlay_opacity = 0.25;
+
+function toggle_test(show_test) {
+    test_frame.style.display = show_test ? 'block' : 'none';
+}
+
+function toggle_solid_color(use_solid_color) {
+    overlay_opacity = use_solid_color ? 1 : 0.25;
+    draw_repaint_rects();
+}
+
+var expected = {
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 2016],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='container'",
+      "position": [40, 50],
+      "bounds": [100, 100],
+      "backgroundColor": "#0000FF80",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='scrollable'",
+      "position": [104, 103],
+      "bounds": [302, 302],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Layer",
+      "position": [105, 104],
+      "bounds": [300, 300],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [105, 104],
+      "bounds": [795, 1491],
+      "drawsContent": false,
+      "transform": 2
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='transform'",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 4
+    },
+    {
+      "name": "Overflow Controls Host Layer",
+      "position": [104, 103],
+      "bounds": [302, 302],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [105, 404],
+      "bounds": [300, 0],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [405, 104],
+      "bounds": [0, 300],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -20, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -30, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [193, 181, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [3.53553390593274, 3.53553390593274, 0, 0],
+        [-3.53553390593274, 3.53553390593274, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+      "reason": "style change"
+    }
+  ]
+}
+;
+var actual = {
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 2016],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV id='container'",
+      "position": [40, 50],
+      "bounds": [100, 100],
+      "backgroundColor": "#0000FF80",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='scrollable'",
+      "position": [104, 103],
+      "bounds": [302, 302],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Layer",
+      "position": [105, 104],
+      "bounds": [300, 300],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [105, 104],
+      "bounds": [795, 1491],
+      "drawsContent": false,
+      "transform": 2
+    },
+    {
+      "name": "LayoutBlockFlow (relative positioned) DIV id='transform'",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+          "rect": [20, 20, 10, 10],
+          "reason": "style change"
+        }
+      ],
+      "transform": 4
+    },
+    {
+      "name": "Overflow Controls Host Layer",
+      "position": [104, 103],
+      "bounds": [302, 302],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [105, 404],
+      "bounds": [300, 0],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [405, 104],
+      "bounds": [0, 300],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -20, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -30, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [193, 181, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [3.53553390593274, 3.53553390593274, 0, 0],
+        [-3.53553390593274, 3.53553390593274, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child1'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV id='child2'",
+      "reason": "style change"
+    }
+  ]
+}
+;
+
+function draw_rects(context, rects) {
+    for (var i = 0; i < rects.length; ++i) {
+        var rect = rects[i];
+        context.fillRect(rect[0], rect[1], rect[2], rect[3]);
+    }
+}
+
+function draw_layer_rects(context, transforms, layer) {
+    context.save();
+    var transform_path = [];
+    for (var id = layer.transform; id; id = transforms[id].parent)
+      transform_path.push(transforms[id]);
+
+    for (var i = transform_path.length - 1; i >= 0; i--) {
+        var m = transform_path[i].transform;
+        if (!m)
+          continue;
+        var origin = transform_path[i].origin;
+        if (origin)
+            context.translate(origin[0], origin[1]);
+        context.transform(m[0][0], m[0][1], m[1][0], m[1][1], m[3][0], m[3][1]);
+        if (origin)
+            context.translate(-origin[0], -origin[1]);
+    }
+    if (layer.position)
+        context.translate(layer.position[0], layer.position[1]);
+
+    if (layer.paintInvalidations) {
+        var rects = [];
+        for (var i = 0; i < layer.paintInvalidations.length; ++i) {
+            if (layer.paintInvalidations[i].rect)
+                rects.push(layer.paintInvalidations[i].rect);
+        }
+        draw_rects(context, rects);
+    }
+    context.restore();
+}
+
+function draw_result_rects(context, result) {
+    var transforms = {};
+    if (result.transforms) {
+        for (var i = 0; i < result.transforms.length; ++i) {
+            var transform = result.transforms[i];
+            transforms[transform.id] = transform;
+        }
+    }
+    if (result.layers) {
+        for (var i = 0; i < result.layers.length; ++i)
+            draw_layer_rects(context, transforms, result.layers[i]);
+    }
+}
+
+function draw_repaint_rects() {
+    var expected_ctx = expected_canvas.getContext("2d");
+    expected_ctx.clearRect(0, 0, 2000, 2000);
+    expected_ctx.fillStyle = 'rgba(255, 0, 0, ' + overlay_opacity + ')';
+    draw_result_rects(expected_ctx, expected);
+
+    var actual_ctx = actual_canvas.getContext("2d");
+    actual_ctx.clearRect(0, 0, 2000, 2000);
+    actual_ctx.fillStyle = 'rgba(0, 255, 0, ' + overlay_opacity + ')';
+    draw_result_rects(actual_ctx, actual);
+}
+
+draw_repaint_rects();
+
+test_frame.src = decodeURIComponent(location.search).substr(1);
+
+var expected_showing = true;
+function flip() {
+    if (expected_showing) {
+        overlay_type.textContent = 'Actual Invalidations';
+        expected_canvas.style.display = 'none';
+        actual_canvas.style.display = 'block';
+    } else {
+        overlay_type.textContent = 'Expected Invalidations';
+        actual_canvas.style.display = 'none';
+        expected_canvas.style.display = 'block';
+    }
+    expected_showing = !expected_showing
+}
+setInterval(flip, 3000);
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers.html b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers.html
new file mode 100644
index 0000000..2aa49c83
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/repaint-overlay/layers.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<style>
+  ::-webkit-scrollbar { display: none }
+</style>
+<div style="height: 2000px"></div>
+<div id="container"
+     style="position: absolute; will-change: transform;
+            top: 50px; left: 40px;
+            width: 100px; height: 100px; background-color: rgba(0, 0, 255, 0.5)">
+  <div id="child1"
+       style="position: relative; top: 20px; left: 20px;
+              width: 10px; height: 10px; background-color: red">
+  <div id="scrollable"
+       style="overflow: scroll; will-change: transform;
+              position: relative; top: 33px; left: 44px;
+              width: 300px; height: 300px; border: 1px solid black">
+    <div id="transform"
+         style="position: relative; will-change: transform;
+                top: 77px; left: 88px;
+                transform: scale(5) rotate(45deg); transform-origin: 0 0;
+                width: 200px; height: 200px; background: yellow">
+      <div id="child2"
+           style="position: relative; top: 20px; left: 20px;
+                  width: 10px; height: 10px; background-color: red">
+      </div>
+    </div>
+  </div>
+</div>
+<script src="../resources/text-based-repaint.js"></script>
+<script>
+onload = function() {
+  window.scrollTo(0, 20);
+  scrollable.scrollTop = 30;
+  runRepaintTest();
+};
+function repaintTest() {
+  child1.style.backgroundColor = 'green';
+  child2.style.backgroundColor = 'green';
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-absolute-layer-with-reflection-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-absolute-layer-with-reflection-expected.txt
index 89c7f40..274fd6819 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-absolute-layer-with-reflection-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-absolute-layer-with-reflection-expected.txt
@@ -26,6 +26,18 @@
           "rect": [250, 230, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -180, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-no-visible-content-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-no-visible-content-expected.txt
index d5db435..102720d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-no-visible-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-no-visible-content-expected.txt
@@ -16,6 +16,18 @@
           "rect": [100, 1150, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-reflection-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-reflection-expected.txt
index 5a6be28..5951c3c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-reflection-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-reflection-expected.txt
@@ -21,6 +21,18 @@
           "rect": [250, 280, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -180, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-transformed-parent-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
index 6ff36df..18c48585 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
@@ -21,6 +21,18 @@
           "rect": [93, 234, 142, 143],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -180, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-reflected-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-reflected-layer-expected.txt
index 5f7c02d..c177c7b 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-reflected-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-fixed-reflected-layer-expected.txt
@@ -16,6 +16,18 @@
           "rect": [250, 280, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -180, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-in-fixed-layer-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-in-fixed-layer-expected.txt
index 121ab92..65379f13 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-in-fixed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-in-fixed-layer-expected.txt
@@ -21,6 +21,18 @@
           "rect": [100, 1150, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-relative-table-inside-table-cell-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-relative-table-inside-table-cell-expected.txt
index ed72334..15930d1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scroll-relative-table-inside-table-cell-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scroll-relative-table-inside-table-cell-expected.txt
@@ -26,6 +26,18 @@
           "rect": [1114, 1764, 435, 15],
           "reason": "scroll control"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-766, -1181, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-background-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-background-offscreen-expected.txt
index 94ea085..cb194e1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-background-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-background-offscreen-expected.txt
@@ -4,7 +4,19 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-offscreen-expected.txt
index 94ea085..cb194e1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-offscreen-expected.txt
@@ -4,7 +4,19 @@
       "name": "LayoutView #document",
       "bounds": [2008, 2016],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1000, 0, 1]
+      ]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
index cc36b23..53b306d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
@@ -8,9 +8,8 @@
     },
     {
       "name": "LayoutBlockFlow DIV id='targetDiv'",
-      "position": [8, 8],
       "bounds": [2000, 2000],
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -20,6 +19,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, -1000, 0, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-in-scrolled-view-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-in-scrolled-view-expected.txt
index c3fb50e..c0c7402 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-in-scrolled-view-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/repaint-in-scrolled-view-expected.txt
@@ -11,6 +11,18 @@
           "rect": [400, 400, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-400, -400, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/printing/print-box-shadow-expected.png b/third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/paint/printing/print-box-shadow-expected.png
rename to third_party/WebKit/LayoutTests/paint/printing/print-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/scrolled-within-boxshadow-expected.png
deleted file mode 100644
index 35d9b26..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/scrolled-within-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/translated-boxshadow-expected.png
deleted file mode 100644
index 0b7ed078..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/translated-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/unscrolled-within-boxshadow-expected.png
deleted file mode 100644
index 35d9b26..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/culling/unscrolled-within-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/scrollbar-layer-placement-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/scrollbar-layer-placement-expected.png
deleted file mode 100644
index 27dc9907..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/scrollbar-layer-placement-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
deleted file mode 100644
index df51df84..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-with-box-shadow-01-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-with-box-shadow-01-expected.png
deleted file mode 100644
index 94e76aa..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-with-box-shadow-01-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadow-radius-expected.png
deleted file mode 100644
index a03d72dd..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadow-radius-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadows-expected.png
deleted file mode 100644
index a64f2e6..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/box-shadow/inset-box-shadows-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/checkbox/checkbox-appearance-basic-expected.png
deleted file mode 100644
index 9089d55c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/radio/radio-appearance-basic-expected.png
deleted file mode 100644
index 83daa7c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/radio/radio-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/range/range-appearance-basic-expected.png
deleted file mode 100644
index e7187cf..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/range/range-appearance-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/cross-fade-background-size-expected.png
deleted file mode 100644
index 43b3580..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/images/cross-fade-background-size-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
index 67ddd4c9..337156e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
@@ -11,6 +11,18 @@
           "rect": [0, 320, 412, 19],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-200, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
index adf9bec..e03869c2 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
@@ -56,6 +56,18 @@
           "rect": [8, 2196, 655, 107],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1750, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index a2073ede..ecc9b5f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -41,6 +41,18 @@
           "rect": [380, 1012, 7, 19],
           "reason": "geometry"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -451, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index 860a925..07beef0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -56,6 +56,18 @@
           "rect": [507, 8, 423, 482],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-339, 0, 0, 1]
       ]
     }
   ],
@@ -201,6 +213,18 @@
           "rect": [539, 235, 400, 15],
           "reason": "scroll control"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-539, 0, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/printing/print-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/printing/print-box-shadow-expected.png
deleted file mode 100644
index 380250a9..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/printing/print-box-shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
deleted file mode 100644
index 949a43c9..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/linux/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index bb4bacd..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
deleted file mode 100644
index 8e316cc..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
deleted file mode 100644
index 8e316cc..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feDropShadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feDropShadow-expected.png
deleted file mode 100644
index 6dcf50f..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feDropShadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
deleted file mode 100644
index 0feb23c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3
-Tests quota reporting.
-
-Tree element found: true
-Clear storage view is visible: true
-0 B storage quota used out of 5.0 MB
-
-Running: Now with data
-9.5 MB storage quota used out of 5.0 MB
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png
deleted file mode 100644
index 27dc9907..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index bb4bacd..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index bb4bacd..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-ctor-pmi-handling.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-ctor-pmi-handling.https-expected.txt
deleted file mode 100644
index 98958a6..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-ctor-pmi-handling.https-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-PASS Must support valid standard URL PMIs
-PASS Must not throw on syntactically valid standardized payment method identifiers, even if they are not supported
-FAIL Test for validity of payment method identifiers during construction assert_throws: expected RangeError processing invalid standardized PMI "basic-💳" function "() => {
-        const methods = [{ supportedMethods: invalidMethod }];
-        new PaymentRequest(methods, defaultDetails);
-      }" did not throw
-FAIL Constructor MUST throw if given an invalid URL-based payment method identifier assert_throws: expected RangeError processing invalid URL PMI "https://username@example.com/pay" function "() => {
-        const methods = [{ supportedMethods: invalidMethod }];
-        new PaymentRequest(methods, defaultDetails);
-      }" did not throw
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
deleted file mode 100644
index 0feb23c..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3
-Tests quota reporting.
-
-Tree element found: true
-Clear storage view is visible: true
-0 B storage quota used out of 5.0 MB
-
-Running: Now with data
-9.5 MB storage quota used out of 5.0 MB
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-ctor-pmi-handling.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-ctor-pmi-handling.https-expected.txt
deleted file mode 100644
index b8f69eb..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-ctor-pmi-handling.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL Constructor MUST throw if given an invalid payment method identifier assert_throws: expected RangeError processing invalid PMI "[object Object]" function "() => {
-        new PaymentRequest([invalidMethod], defaultDetails);
-      }" did not throw
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
deleted file mode 100644
index b2222f9..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3
-Tests quota reporting.
-
-Tree element found: true
-Clear storage view is visible: true
-0 B storage quota used out of -
-
-Running: Now with data
-9.5 MB storage quota used out of -
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
index 6775f55..0da8fe848 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -24,7 +24,8 @@
       "position": [19, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -60,7 +61,8 @@
       "position": [249, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 2
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -79,6 +81,28 @@
       "position": [438, 128],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
deleted file mode 100644
index b2222f9..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3
-Tests quota reporting.
-
-Tree element found: true
-Clear storage view is visible: true
-0 B storage quota used out of -
-
-Running: Now with data
-9.5 MB storage quota used out of -
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index 6775f55..0da8fe848 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -24,7 +24,8 @@
       "position": [19, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -60,7 +61,8 @@
       "position": [249, 19],
       "bounds": [189, 308],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 2
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -79,6 +81,28 @@
       "position": [438, 128],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
deleted file mode 100644
index b2222f9..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3
-Tests quota reporting.
-
-Tree element found: true
-Clear storage view is visible: true
-0 B storage quota used out of -
-
-Running: Now with data
-9.5 MB storage quota used out of -
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
index 62d826c..219f6a1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
@@ -1,5 +1,3 @@
-This content is in the parent
-Box should switch between perspective and flat
 
 First dump layer tree:
 {
@@ -36,25 +34,33 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='grandchild'",
-      "position": [10, 10],
       "bounds": [200, 200],
       "contentsOpaque": true,
       "backgroundColor": "#FFFF00",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='greatgrandchild'",
-      "position": [100, 0],
       "bounds": [250, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [49, 57, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.866025403784439, 0.5, 0, 0],
         [-0.5, 0.866025403784439, 0, 0],
         [0, 0, 1, 0],
@@ -63,8 +69,18 @@
       "origin": [100, 100]
     },
     {
-      "id": 2,
-      "parent": 1,
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [100, 0, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
       "transform": [
         [0.5, 0, -0.866025403784439, 0.0021650635094611],
         [0, 1, 0, 0],
@@ -81,7 +97,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 1451],
+      "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF"
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
index 8308a966..81f44be 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
@@ -1,5 +1,3 @@
-This content is in the parent
-Box should switch between perspective and flat
 
 First dump layer tree:
 {
@@ -29,17 +27,26 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='child' class='child'",
-      "position": [121, 39],
       "bounds": [250, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [129, 47, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0, -0.707106781186548, 0.00117851130197758],
         [0, 1, 0, 0],
         [0.707106781186548, 0, 0.707106781186548, -0.00117851130197758],
@@ -55,7 +62,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 961],
+      "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF"
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt
index a420cf2..38539375 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/preserve-3d-switching-expected.txt
@@ -18,24 +18,22 @@
       "name": "Child Transform Layer",
       "bounds": [304, 304],
       "drawsContent": false,
-      "transform": 1
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='parent'",
-      "position": [12, 12],
-      "bounds": [280, 280],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFF00",
       "transform": 2
     },
     {
+      "name": "LayoutBlockFlow DIV id='parent'",
+      "bounds": [280, 280],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "transform": 4
+    },
+    {
       "name": "LayoutBlockFlow (positioned) DIV",
-      "position": [40, 40],
       "bounds": [200, 200],
       "opacity": 0.699999988079071,
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 3
+      "transform": 6
     }
   ],
   "transforms": [
@@ -44,16 +42,36 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
-        [0, 0, 1, -0.002],
-        [0, 0, 0, 1]
-      ],
-      "origin": [152, 152],
-      "flattenInheritedTransform": false
+        [0, 0, 1, 0],
+        [108, 73, 0, 1]
+      ]
     },
     {
       "id": 2,
       "parent": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.002],
+        [0, 0, 0, 1]
+      ],
+      "origin": [152, 152]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
         [0.766044443118978, -0.556670399226419, -0.32139380484327, 0],
         [0, 0.5, -0.866025403784439, 0],
         [0.642787609686539, 0.663413948168938, 0.383022221559489, 0],
@@ -64,8 +82,19 @@
       "renderingContext": 1
     },
     {
-      "id": 3,
-      "parent": 2,
+      "id": 5,
+      "parent": 4,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [40, 40, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 6,
+      "parent": 5,
       "transform": [
         [0.766044443118978, 0, 0.642787609686539, 0],
         [0, 1, 0, 0],
@@ -73,6 +102,7 @@
         [0, 0, 50, 1]
       ],
       "origin": [100, 100],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
index 2b66f32cd..25dcd60 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -89,11 +89,10 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
-      "position": [18, 202],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -103,6 +102,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [18, 202, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
index 031f02e..e4565b0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
@@ -11,28 +11,46 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='preserve3d'",
-      "position": [18, 390],
       "bounds": [342, 180],
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
-      "position": [31, 49],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
     {
       "id": 1,
-      "flattenInheritedTransform": false,
-      "renderingContext": 1
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [18, 390, 0, 1]
+      ]
     },
     {
       "id": 2,
       "parent": 1,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [31, 49, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
       "transform": [
         [0.984807753012208, 0, -0.17364817766693, 0],
         [0, 1, 0, 0],
@@ -40,6 +58,7 @@
         [0, 0, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
index 1d8ba0a4..e782816 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -24,7 +24,8 @@
       "position": [19, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -60,7 +61,8 @@
       "position": [249, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 2
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -79,6 +81,28 @@
       "position": [438, 128],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png
deleted file mode 100644
index 88451f9b..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
deleted file mode 100644
index df51df84..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/svg-blend-multiply-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/blending/svg-blend-multiply-alpha-expected.png
deleted file mode 100644
index a0779e8..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/blending/svg-blend-multiply-alpha-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-clipped-slices-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-clipped-slices-expected.png
deleted file mode 100644
index d3f585a..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-clipped-slices-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-radius-expected.png
deleted file mode 100644
index 030e70ec..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/box-shadow-radius-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/spread-multiple-normal-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/spread-multiple-normal-expected.png
deleted file mode 100644
index 9d307e0..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/box-shadow/spread-multiple-normal-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
index 37e7011..e55063f0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,7 +32,8 @@
           "rect": [3, 1003, 200, 13],
           "reason": "subtree"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -51,6 +52,18 @@
       "bounds": [0, 100]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -919, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutTextControl INPUT id='text'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/fixed-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/fixed-expected.txt
index 87d543e..7ff53b43 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/fixed-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/fixed-expected.txt
@@ -11,6 +11,18 @@
           "rect": [8, 80, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -20, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
index 787f0ab..6c3b86a7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
@@ -11,6 +11,18 @@
           "rect": [0, 288, 415, 18],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-200, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt
index fd9a3c9..85163f0f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt
@@ -11,6 +11,18 @@
           "rect": [8, 2408, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -2350, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
index 606c7541..18fbc9b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
@@ -56,6 +56,18 @@
           "rect": [8, 2195, 653, 109],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1750, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
index 7dc270e..bd9d01c0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
@@ -37,7 +37,8 @@
           "rect": [0, 0, 185, 550],
           "reason": "background on scrolling contents layer"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -82,6 +83,18 @@
       "bounds": [15, 15]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -365, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "Scrolling Contents Layer",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt
index 9cf60ee1..fbf43023 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt
@@ -46,6 +46,18 @@
           "rect": [677, 50, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
index 388fe20..f9f7c22a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
@@ -4,7 +4,8 @@
       "name": "LayoutView #document",
       "bounds": [785, 5054],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) HEADER",
@@ -32,6 +33,18 @@
           "rect": [10, 1424, 150, 150],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1400, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
index fbc3396..a0db333 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
@@ -30,7 +30,8 @@
           "rect": [0, 610, 23, 18],
           "reason": "selection"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -56,6 +57,18 @@
       "bounds": [15, 15]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -450, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index d23fe4f..b2de6a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -41,6 +41,18 @@
           "rect": [378, 991, 6, 21],
           "reason": "geometry"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -431, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
index 673f26e..bb737bd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
@@ -27,16 +27,25 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
-      "position": [108, 158],
       "bounds": [440, 300],
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [108, 158, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0, 1, 0, 0],
         [-1, 0, 0, 0],
         [0, 0, 1, 0],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index 67e6e503..01b2f7b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -56,6 +56,18 @@
           "rect": [491, 8, 414, 484],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-313, 0, 0, 1]
       ]
     }
   ],
@@ -201,6 +213,18 @@
           "rect": [513, 235, 400, 15],
           "reason": "scroll control"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-513, 0, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png
deleted file mode 100644
index 27dc9907..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
index 1d8ba0a4..e782816 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -24,7 +24,8 @@
       "position": [19, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -60,7 +61,8 @@
       "position": [249, 19],
       "bounds": [189, 270],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 2
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -79,6 +81,28 @@
       "position": [438, 128],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index bb4bacd..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index bb4bacd..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/culling/scrolled-within-boxshadow-expected.png
deleted file mode 100644
index 317fef7d7..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/scrolled-within-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/culling/translated-boxshadow-expected.png
deleted file mode 100644
index 6e3f377..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/translated-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/culling/unscrolled-within-boxshadow-expected.png
deleted file mode 100644
index 317fef7d7..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/culling/unscrolled-within-boxshadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
index ff4d4dd6..7bf0fdf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-deep-switch-expected.txt
@@ -1,5 +1,3 @@
-This content is in the parent
-Box should switch between perspective and flat
 
 First dump layer tree:
 {
@@ -36,25 +34,33 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='grandchild'",
-      "position": [10, 10],
       "bounds": [200, 200],
       "contentsOpaque": true,
       "backgroundColor": "#FFFF00",
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='greatgrandchild'",
-      "position": [100, 0],
       "bounds": [250, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [49, 59, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.866025403784439, 0.5, 0, 0],
         [-0.5, 0.866025403784439, 0, 0],
         [0, 0, 1, 0],
@@ -63,8 +69,18 @@
       "origin": [100, 100]
     },
     {
-      "id": 2,
-      "parent": 1,
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [100, 0, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
       "transform": [
         [0.5, 0, -0.866025403784439, 0.0021650635094611],
         [0, 1, 0, 0],
@@ -81,7 +97,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 1526],
+      "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF"
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
index 6ef54bd..272ce15 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/layer-due-to-layer-children-switch-expected.txt
@@ -1,5 +1,3 @@
-This content is in the parent
-Box should switch between perspective and flat
 
 First dump layer tree:
 {
@@ -29,17 +27,26 @@
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV id='child' class='child'",
-      "position": [121, 41],
       "bounds": [250, 100],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [129, 49, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0.707106781186548, 0, -0.707106781186548, 0.00117851130197758],
         [0, 1, 0, 0],
         [0.707106781186548, 0, 0.707106781186548, -0.00117851130197758],
@@ -55,7 +62,7 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [785, 1010],
+      "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF"
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt
index 5f9ed72..ecf70787 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/preserve-3d-switching-expected.txt
@@ -18,24 +18,22 @@
       "name": "Child Transform Layer",
       "bounds": [304, 304],
       "drawsContent": false,
-      "transform": 1
-    },
-    {
-      "name": "LayoutBlockFlow DIV id='parent'",
-      "position": [12, 12],
-      "bounds": [280, 280],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFF00",
       "transform": 2
     },
     {
+      "name": "LayoutBlockFlow DIV id='parent'",
+      "bounds": [280, 280],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "transform": 4
+    },
+    {
       "name": "LayoutBlockFlow (positioned) DIV",
-      "position": [40, 40],
       "bounds": [200, 200],
       "opacity": 0.699999988079071,
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "transform": 3
+      "transform": 6
     }
   ],
   "transforms": [
@@ -44,16 +42,36 @@
       "transform": [
         [1, 0, 0, 0],
         [0, 1, 0, 0],
-        [0, 0, 1, -0.002],
-        [0, 0, 0, 1]
-      ],
-      "origin": [152, 152],
-      "flattenInheritedTransform": false
+        [0, 0, 1, 0],
+        [108, 72, 0, 1]
+      ]
     },
     {
       "id": 2,
       "parent": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.002],
+        [0, 0, 0, 1]
+      ],
+      "origin": [152, 152]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
         [0.766044443118978, -0.556670399226419, -0.32139380484327, 0],
         [0, 0.5, -0.866025403784439, 0],
         [0.642787609686539, 0.663413948168938, 0.383022221559489, 0],
@@ -64,8 +82,19 @@
       "renderingContext": 1
     },
     {
-      "id": 3,
-      "parent": 2,
+      "id": 5,
+      "parent": 4,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [40, 40, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 6,
+      "parent": 5,
       "transform": [
         [0.766044443118978, 0, 0.642787609686539, 0],
         [0, 1, 0, 0],
@@ -73,6 +102,7 @@
         [0, 0, 50, 1]
       ],
       "origin": [100, 100],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
index acfc168..ae51178 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/gestures/gesture-tapHighlight-with-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
index d66478e92..e29a9465 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -89,11 +89,10 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='box'",
-      "position": [18, 203],
       "bounds": [210, 210],
       "contentsOpaque": true,
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
@@ -103,6 +102,16 @@
         [1, 0, 0, 0],
         [0, 1, 0, 0],
         [0, 0, 1, 0],
+        [18, 203, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
         [0, 0, 1, 1]
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
index 86446d4..616bfbea 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/layer-creation/no-compositing-for-preserve-3d-expected.txt
@@ -11,28 +11,46 @@
     },
     {
       "name": "LayoutBlockFlow DIV class='preserve3d'",
-      "position": [18, 394],
       "bounds": [342, 182],
-      "transform": 1
+      "transform": 2
     },
     {
       "name": "LayoutBlockFlow (relative positioned) DIV class='box'",
-      "position": [31, 51],
       "bounds": [100, 100],
       "contentsOpaque": true,
       "backgroundColor": "#C0C0C0",
-      "transform": 2
+      "transform": 4
     }
   ],
   "transforms": [
     {
       "id": 1,
-      "flattenInheritedTransform": false,
-      "renderingContext": 1
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [18, 394, 0, 1]
+      ]
     },
     {
       "id": 2,
       "parent": 1,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [31, 51, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
       "transform": [
         [0.984807753012208, 0, -0.17364817766693, 0],
         [0, 1, 0, 0],
@@ -40,6 +58,7 @@
         [0, 0, 0, 1]
       ],
       "origin": [50, 50],
+      "flattenInheritedTransform": false,
       "renderingContext": 1
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/scrollbar-layer-placement-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/scrollbar-layer-placement-expected.png
deleted file mode 100644
index 125c5fc..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/scrollbar-layer-placement-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
index f2b419e..85fea04 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/overflow/textarea-scroll-touch-expected.txt
@@ -24,7 +24,8 @@
       "position": [19, 19],
       "bounds": [189, 328],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -60,7 +61,8 @@
       "position": [249, 19],
       "bounds": [189, 328],
       "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
+      "backgroundColor": "#CCCCCC",
+      "transform": 2
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -79,6 +81,28 @@
       "position": [438, 128],
       "bounds": [15, 15]
     }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -50, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
   ]
 }
 
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png
deleted file mode 100644
index cf23535..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/rtl/rtl-fixed-overflow-scrolled-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png
index e34c9d5..11e3a46 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-multiply-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-multiply-alpha-expected.png
deleted file mode 100644
index 180fdc3..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/css3/blending/svg-blend-multiply-alpha-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/html/semantics/embedded-content/the-object-element/object-events-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/html/semantics/embedded-content/the-object-element/object-events-expected.txt
new file mode 100644
index 0000000..4f1c063
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/html/semantics/embedded-content/the-object-element/object-events-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL error event (using 'file:' protocol) assert_unreached: The load event should not be fired. Reached unreachable code
+FAIL error event (using 'http:' protocol) assert_unreached: The load event should not be fired. Reached unreachable code
+PASS load event
+FAIL load event of about:blank assert_true: The object element should represent a nested browsing context. expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
index aa4ec0d6..bacb80b3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-canvas-with-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-with-box-shadow-01-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-with-box-shadow-01-expected.png
deleted file mode 100644
index de11d7b..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-with-box-shadow-01-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png
index 42bd214..bdb0fcd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/basic-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-clipped-slices-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-clipped-slices-expected.png
deleted file mode 100644
index fc1c49b..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-clipped-slices-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-radius-expected.png
deleted file mode 100644
index 1b6c1bb..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/box-shadow-radius-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadow-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadow-radius-expected.png
index 87f411c..a03d72dd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadow-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadow-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadows-expected.png
index 38dc53e..a64f2e6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-box-shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png
index 83ed37a..f6cb6f7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png
index a2db537c2..dcafbb9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/inset-subpixel-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/spread-multiple-inset-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/spread-multiple-inset-expected.png
index 5350025..5c99a86 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/spread-multiple-inset-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/spread-multiple-inset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/spread-multiple-normal-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/spread-multiple-normal-expected.png
deleted file mode 100644
index 90c36a7..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/fast/box-shadow/spread-multiple-normal-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
index 712a5cf..6895ab7e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png
index 23ae772..4186c7ec 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-box-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png
index 6f4b775c..a2b4bf8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png
index 999dc92..99bfdd2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png
index c626241c..2987660a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/dom/HTMLMeterElement/meter-styles-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index c9729dc..8a9b3313 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png
index 593be72..924978b6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index 771f93d..8442538 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index d302649..60c8236 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index c1fa459..c80ee4c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index d003b07a..f268978 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
index db67eeb..89463aa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-ru-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index b54ffaf9..2defeb1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index eeb3235..7aa7904d0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index 1f2b5da7..0c1a926a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png
index b331914..a7f95d7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index 5b81a69..f8b60a9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png
index 7c5954f..eebf49b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 4e82579..1d724f7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
index bc129dd..9089d55c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/checkbox/checkbox-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
index a2155dd..70ac398 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 7898152..a4544b18 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index e80cbe9d..e856e05 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index d94d8c6..a2fd0002 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
index 9760ae8..83daa7c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/radio/radio-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png
index fe4c680..e7187cf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/range/range-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png
index ffaffd3b..a59b565 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/submit/submit-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png
index d4676c3..17a8f61 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-edge-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png
index 3c6c991..d0f20403 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
index c00ae4e..f4e8b49 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/validation-bubble-appearance-rtl-ui-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-decorations-expected.png
index 2f6ac858..31c7b60 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-decorations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-expected.png
index a22db2d..d378efa 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png
index 570862ef..bbd2e39 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/english-lr-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png
index d7f46e07..054540d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-002-expected.png
index 79d23e1..2955099 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png
index cb42ee9..390713a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-010-expected.png
index cb7a60f1..b19a7bde 100644
--- a/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-010-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
index 11fcc98..43b3580 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
index 07557bc7..a5a1d71e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -32,7 +32,8 @@
           "rect": [3, 1003, 200, 16],
           "reason": "subtree"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -51,6 +52,18 @@
       "bounds": [0, 100]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -922, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutTextControl INPUT id='text'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/fixed-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/fixed-expected.txt
index 63d6ef1..27bed42 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/fixed-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/fixed-expected.txt
@@ -11,6 +11,18 @@
           "rect": [8, 84, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -20, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
index ae1fc3f..2045fc2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-style-change-in-scrolled-view-expected.txt
@@ -11,6 +11,18 @@
           "rect": [0, 320, 385, 19],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-200, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt
index 6ad99df..ed6443a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-after-composited-scroll-of-window-expected.txt
@@ -11,6 +11,18 @@
           "rect": [8, 2408, 100, 100],
           "reason": "style change"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -2350, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
index 90121f6..9e3df5b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidation-after-opacity-change-subtree-expected.txt
@@ -56,6 +56,18 @@
           "rect": [8, 2196, 639, 108],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1750, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
index 5dfc8b62..462c0e45 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-local-background-text-color-change-expected.txt
@@ -37,7 +37,8 @@
           "rect": [0, 0, 185, 552],
           "reason": "background on scrolling contents layer"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -82,6 +83,18 @@
       "bounds": [15, 15]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -367, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "Scrolling Contents Layer",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt
index 52e0900fd..5f792a8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-descendant-with-cached-cliprects-expected.txt
@@ -46,6 +46,18 @@
           "rect": [677, 52, 100, 100],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -200, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
index 7b56d346..696f3de 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
@@ -4,7 +4,8 @@
       "name": "LayoutView #document",
       "bounds": [785, 5056],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
     },
     {
       "name": "LayoutBlockFlow (relative positioned) HEADER",
@@ -32,6 +33,18 @@
           "rect": [10, 1422, 150, 150],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1400, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
index 704e151..ecdc117 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
@@ -30,7 +30,8 @@
           "rect": [0, 610, 21, 19],
           "reason": "selection"
         }
-      ]
+      ],
+      "transform": 1
     },
     {
       "name": "Overflow Controls Host Layer",
@@ -56,6 +57,18 @@
       "bounds": [15, 15]
     }
   ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -450, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ],
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/shadow-multiple-expected.png
index 5e53f36..f639239 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index b4dcd4e..44f98488 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -41,6 +41,18 @@
           "rect": [379, 1012, 7, 19],
           "reason": "geometry"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -451, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
index be749ed..39c9c80 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/transform-focus-ring-repaint-expected.txt
@@ -27,16 +27,25 @@
     },
     {
       "name": "LayoutBlockFlow (positioned) DIV",
-      "position": [108, 158],
       "bounds": [440, 300],
       "backgroundColor": "#0000FF",
-      "transform": 1
+      "transform": 2
     }
   ],
   "transforms": [
     {
       "id": 1,
       "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [108, 158, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
         [0, 1, 0, 0],
         [-1, 0, 0, 0],
         [0, 0, 1, 0],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index bbe68f6..889e064d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -56,6 +56,18 @@
           "rect": [506, 8, 424, 470],
           "reason": "subtree"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-339, 0, 0, 1]
       ]
     }
   ],
@@ -201,6 +213,18 @@
           "rect": [539, 235, 400, 15],
           "reason": "scroll control"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-539, 0, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/printing/print-box-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/printing/print-box-shadow-expected.png
deleted file mode 100644
index 2e24bc09..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/paint/printing/print-box-shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
index 51ac3cb..949a43c9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/roundedrects/input-with-rounded-rect-and-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/win/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index cece9be..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.png
index b920ba36..b343749b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
deleted file mode 100644
index d6e03f3..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
deleted file mode 100644
index d6e03f3..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feDropShadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feDropShadow-expected.png
deleted file mode 100644
index 85355b0..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feDropShadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win/transforms/shadows-expected.png
index 86fd2c8..4423315 100644
--- a/third_party/WebKit/LayoutTests/platform/win/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
index 712a5cf..6895ab7e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
index 12fad47..e2fb5179 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
deleted file mode 100644
index b2222f9..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3
-Tests quota reporting.
-
-Tree element found: true
-Clear storage view is visible: true
-0 B storage quota used out of -
-
-Running: Now with data
-9.5 MB storage quota used out of -
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png
deleted file mode 100644
index 125c5fc..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
deleted file mode 100644
index f2b419e..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/compositing/overflow/textarea-scroll-touch-expected.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-  
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [19, 19],
-      "bounds": [189, 124],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "position": [19, 19],
-      "bounds": [189, 328],
-      "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [18, 18],
-      "bounds": [206, 126],
-      "drawsContent": false
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [208, 19],
-      "bounds": [15, 109],
-      "drawsContent": false
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [208, 128],
-      "bounds": [15, 15]
-    },
-    {
-      "name": "LayoutTextControl TEXTAREA",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Scrolling Layer",
-      "position": [249, 19],
-      "bounds": [189, 124],
-      "drawsContent": false
-    },
-    {
-      "name": "Scrolling Contents Layer",
-      "position": [249, 19],
-      "bounds": [189, 328],
-      "contentsOpaque": true,
-      "backgroundColor": "#CCCCCC"
-    },
-    {
-      "name": "Overflow Controls Host Layer",
-      "position": [248, 18],
-      "bounds": [206, 126],
-      "drawsContent": false
-    },
-    {
-      "name": "Vertical Scrollbar Layer",
-      "position": [438, 19],
-      "bounds": [15, 109],
-      "drawsContent": false
-    },
-    {
-      "name": "Scroll Corner Layer",
-      "position": [438, 128],
-      "bounds": [15, 15]
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index cece9be..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png
deleted file mode 100644
index cece9be..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index 934208e..48d6bf6c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index 5ede782e..0aec8ce 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
index e78dd41..ae58a1f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index f97404be..fe02fb86a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
index e78dd41..ae58a1f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
index f97404be..fe02fb86a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/compositing/shadows/shadow-drawing-expected.png b/third_party/WebKit/LayoutTests/platform/win7/compositing/shadows/shadow-drawing-expected.png
index 19d94c2..6e555d2 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/compositing/shadows/shadow-drawing-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/compositing/shadows/shadow-drawing-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/css/color-correction-on-text-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/css/color-correction-on-text-shadow-expected.png
index 42348af..46f1cd33 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/css/color-correction-on-text-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/css/color-correction-on-text-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/css/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/css/shadow-multiple-expected.png
index da68cb5..b032104 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/css/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
index 09ac85c..bf4d093 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png
index 212a38a6..b1733ca7 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-coarse-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
index 986dff04..ce45527 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
index 6eaf4fb..2d60999 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-minimum-date-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
index a791fe6..fcd166e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-ar-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
index 3d73de9..ebc93d1 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-required-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
index fd2ecc52..bc1fb52e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
index bbe4d483..d6e8dd4 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
index e6f45c0..f207989 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/calendar-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png
index f67dc0af..4e83ec3 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
index cd48cc6..7c8f6a9 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/month-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png
index 4b87cf7..ee7c485 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
index 4b8e007..72e1b98 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/calendar-picker/week-picker-appearance-step-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png
index 16a3cb0..8165c077 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-decorations-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png
index 3db1477..3161d3d 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/stroking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/text-shadow-no-default-color-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/text-shadow-no-default-color-expected.png
index a8421aae..703ea0d1 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/text-shadow-no-default-color-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/text-shadow-no-default-color-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-001-expected.png b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-001-expected.png
index 927f4a1..b92ff41 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png
index 64e0a51..25c6bbd5 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-002-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-003-expected.png b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-003-expected.png
index af8f6a84..a8a6b61d 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-003-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-003-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png
index b111a6e..a50c15a 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/ietestcenter/css3/text/textshadow-010-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/shadow-multiple-expected.png
index a1b9068..7c11db1c 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index d869917..32453743 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win7/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -41,6 +41,18 @@
           "rect": [379, 1012, 6, 19],
           "reason": "geometry"
         }
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -451, 0, 1]
       ]
     }
   ],
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png
index 92a0e5ce..b7d076d 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/css/text-shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/transforms/shadows-expected.png b/third_party/WebKit/LayoutTests/platform/win7/transforms/shadows-expected.png
index 5eb695a54..2763a4df 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/transforms/shadows-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/transforms/shadows-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
deleted file mode 100644
index 0feb23c..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/inspector/application-panel/storage-view-reports-quota-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2
-CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3
-Tests quota reporting.
-
-Tree element found: true
-Clear storage view is visible: true
-0 B storage quota used out of 5.0 MB
-
-Running: Now with data
-9.5 MB storage quota used out of 5.0 MB
-
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index ee572ee89..d86103e 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
index 13bd4f1..760ecf4 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
index 13bd4f1..760ecf4 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/scrollbars/custom-scrollbar-display-expected.png b/third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-display-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/scrollbars/custom-scrollbar-display-expected.png
rename to third_party/WebKit/LayoutTests/scrollbars/custom-scrollbar-display-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
rename to third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
rename to third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feDropShadow-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feDropShadow-expected.png
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/svg/filters/feDropShadow-expected.png
rename to third_party/WebKit/LayoutTests/svg/filters/feDropShadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-linear-rgb.html b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-linear-rgb.html
new file mode 100644
index 0000000..6583e3d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-linear-rgb.html
@@ -0,0 +1,625 @@
+<!DOCTYPE HTML>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script>
+
+// The reference values are generated by calling SkImage::makeColorSpace()
+// in a Skia fiddle as this is the API used in ImageBitmap for color conversion.
+// SkColorSpaceXform() may generate slightly different results.
+// Please see: https://fiddle.skia.org/c/94578944d9d52c2b4c2cadda88a4e204
+
+var linearRgbRed =   [1, 0, 0, 1]; // SRGB(255,0,0,255)
+var linearRgbGreen = [0, 1, 0, 1]; // SRGB(0,255,0,255)
+var linearRgbBlue =  [0, 0, 1, 1]; // SRGB(0,0,255,255)
+var linearRgbBlack = [0, 0, 0, 1]; // SRGB(0,0,0,255)
+
+// SRGB(155,27,27,255)
+var linearRgbOpaqueRed = [0.329346, 0.011765, 0.011765, 1];
+// SRGB(27,155,27,255)
+var linearRgbOpaqueGreen = [0.011765, 0.329346, 0.011765, 1];
+// SRGB(27,27,155,255)
+var linearRgbOpaqueBlue = [0.011765, 0.011765, 0.329346, 1];
+// SRGB(27,27,27,255)
+var linearRgbOpaqueBlack = [0.011765, 0.011765, 0.011765, 1];
+
+// SRGB(155,27,27,128)
+var linearRgbTransparentRed = [0.329346, 0.011765, 0.011765, 0.501953];
+// SRGB(27,155,27,128)
+var linearRgbTransparentGreen = [0.011765, 0.329346, 0.011765, 0.501953];
+// SRGB(27,27,155,128)
+var linearRgbTransparentBlue = [0.011765, 0.011765, 0.329346, 0.501953];
+// SRGB(27,27,27,128)
+var linearRgbTransparentBlack = [0.011765, 0.011765, 0.011765, 0.501953];
+
+function testPixels(ctx, tests, sourceType)
+{
+    var actual, expected, tolerance = 0.01;
+    if (sourceType === 'video')
+        tolerance = 0.02;
+    for (var i = 0; i < tests.length; i++) {
+        actual = ctx.getImageData(tests[i][0], tests[i][1], 1, 1).dataUnion;
+        expected = tests[i][2];
+        assert_true(actual.length === expected.length);
+       for (var i = 0; i < actual.length; i++)
+           assert_approx_equals(actual[i], expected[i], tolerance, tests[i][3]);
+    }
+}
+
+function checkNoCrop(imageBitmap, colorInfo, sourceType)
+{
+    var canvas = document.createElement('canvas');
+    canvas.width = 50;
+    canvas.height = 50;
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(imageBitmap, 0, 0);
+    var tests;
+    if (colorInfo == 'fullColor')
+        tests = [[0, 0, linearRgbRed, "This pixel should be linear RGB red."],
+                 [39, 0, linearRgbGreen, "This pixel should be linear RGB green."],
+                 [0, 39, linearRgbBlue, "This pixel should be linear RGB blue."],
+                 [39, 39, linearRgbBlack, "This pixel should be linear RGB black."],
+                 [41, 41, linearRgbBlack, "This pixel should be linear RGB black."]];
+    else if (colorInfo == 'opaque')
+        tests = [[0, 0, linearRgbOpaqueRed,
+                     "This pixel should be linear RGB like red."],
+                 [39, 0, linearRgbOpaqueGreen,
+                     "This pixel should be linear RGB like green."],
+                 [0, 39, linearRgbOpaqueBlue,
+                     "This pixel should be linear RGB like blue."],
+                 [39, 39, linearRgbOpaqueBlack,
+                     "This pixel should be linear RGB like black."],
+                 [41, 41, linearRgbBlack,
+                     "This pixel should be linear RGB black."]];
+    else if (colorInfo == 'transparent')
+        tests = [[0, 0, linearRgbTransparentRed,
+                     "This pixel should be linear RGB transparent red."],
+                 [39, 0, linearRgbTransparentGreen,
+                     "This pixel should be linear RGB transparent green."],
+                 [0, 39, linearRgbTransparentBlue,
+                     "This pixel should be linear RGB transparent blue."],
+                 [39, 39, linearRgbTransparentBlack,
+                     "This pixel should be linear RGB transparent black."],
+                 [41, 41, linearRgbBlack, "This pixel should be linear RGB black."]];
+    testPixels(ctx, tests, sourceType);
+}
+
+function checkCrop(imageBitmap, colorInfo, sourceType)
+{
+    var canvas = document.createElement('canvas');
+    canvas.width = 50;
+    canvas.height = 50;
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(imageBitmap, 0, 0);
+    var tests;
+    if (colorInfo === 'fullColor')
+        tests = [[0, 0, linearRgbRed, "This pixel should be linear RGB red."],
+                 [19, 0, linearRgbGreen, "This pixel should be linear RGB green."],
+                 [0, 19, linearRgbBlue, "This pixel should be linear RGB blue."],
+                 [19, 19, linearRgbBlack, "This pixel should be linear RGB black."],
+                 [21, 21, linearRgbBlack, "This pixel should be linear RGB black."]];
+    else if (colorInfo === 'opaque')
+        tests = [[0, 0, linearRgbOpaqueRed,
+                     "This pixel should be linear RGB like red."],
+                 [19, 0, linearRgbOpaqueGreen,
+                     "This pixel should be linear RGB like green."],
+                 [0, 19, linearRgbOpaqueBlue,
+                     "This pixel should be linear RGB like blue."],
+                 [19, 19, linearRgbOpaqueBlack,
+                     "This pixel should be linear RGB like black."],
+                 [21, 21, linearRgbBlack, "This pixel should be linear RGB black."]];
+    else if (colorInfo === 'transparent')
+        tests = [[0, 0, linearRgbTransparentRed,
+                     "This pixel should be linear RGB transparent red."],
+                 [19, 0, linearRgbTransparentGreen,
+                     "This pixel should be linear RGB transparent green."],
+                 [0, 19, linearRgbTransparentBlue,
+                     "This pixel should be linear RGB transparent blue."],
+                 [19, 19, linearRgbTransparentBlack,
+                     "This pixel should be linear RGB transparent black."],
+                 [21, 21, linearRgbBlack, "This pixel should be linear RGB black."]];
+    testPixels(ctx, tests, sourceType);
+}
+
+
+function compareBitmaps(bitmap1, bitmap2)
+{
+    var canvas1 = document.createElement('canvas');
+    var canvas2 = document.createElement('canvas');
+    canvas1.width = 50;
+    canvas1.height = 50;
+    canvas2.width = 50;
+    canvas2.height = 50;
+    var ctx1 = canvas1.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    var ctx2 = canvas2.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
+    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
+    ctx1.drawImage(bitmap1, 0, 0);
+    ctx2.drawImage(bitmap2, 0, 0);
+    var data1 = ctx1.getImageData(0, 0, 50, 50).dataUnion;
+    var data2 = ctx2.getImageData(0, 0, 50, 50).dataUnion;
+    var dataMatched = true;
+    for (var i = 0; i < data1.length; i++) {
+        if (data1[i] != data2[i]) {
+            dataMatched = false;
+            break;
+        }
+    }
+    assert_false(dataMatched);
+}
+
+function testImageBitmap(source, colorInfo, sourceType)
+{
+    return Promise.all([
+        createImageBitmap(source, {colorSpaceConversion: "linear-rgb",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "high"}),
+        createImageBitmap(source, {colorSpaceConversion: "linear-rgb",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "medium"}),
+        createImageBitmap(source, {colorSpaceConversion: "linear-rgb",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "low"}),
+        createImageBitmap(source, {colorSpaceConversion: "linear-rgb",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "pixelated"}),
+        createImageBitmap(source, 5, 5, 10, 10, {
+            colorSpaceConversion: "linear-rgb",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "high"}),
+        createImageBitmap(source, 5, 5, 10, 10, {
+            colorSpaceConversion: "linear-rgb",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "medium"}),
+        createImageBitmap(source, 5, 5, 10, 10, {
+            colorSpaceConversion: "linear-rgb",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "low"}),
+        createImageBitmap(source, 5, 5, 10, 10, {
+            colorSpaceConversion: "linear-rgb",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "pixelated"}),
+    ]).then(([noCropHigh, noCropMedium, noCropLow, noCropPixelated, cropHigh,
+              cropMedium, cropLow, cropPixelated]) => {
+        checkNoCrop(noCropHigh, colorInfo, sourceType);
+        checkNoCrop(noCropMedium, colorInfo, sourceType);
+        checkNoCrop(noCropLow, colorInfo, sourceType);
+        checkNoCrop(noCropPixelated, colorInfo, sourceType);
+        checkCrop(cropHigh, colorInfo, sourceType);
+        checkCrop(cropMedium, colorInfo, sourceType);
+        checkCrop(cropLow, colorInfo, sourceType);
+        checkCrop(cropPixelated, colorInfo, sourceType);
+        // Brute-force comparison among all bitmaps is too expensive.
+        // In case of SVG, resize quality does not affect the images, so all
+        // of them are the same and the tests fail. Since, we ignore this test
+        // set for SVG.
+        if (sourceType != 'svg') {
+            compareBitmaps(noCropHigh, noCropMedium);
+            compareBitmaps(noCropLow, noCropPixelated);
+            compareBitmaps(cropHigh, cropMedium);
+            compareBitmaps(cropLow, cropPixelated);
+        }
+    });
+}
+
+function testImageBitmapTransparent(source)
+{
+    return testImageBitmap(source, 'transparent', 'general');
+}
+
+function testImageBitmapVideoSource(source)
+{
+    return testImageBitmap(source, 'fullColor', 'video');
+}
+
+function testImageBitmapOpaque(source)
+{
+    return testImageBitmap(source, 'opaque', 'general');
+}
+
+function testImageBitmapFromSVG(source)
+{
+    return testImageBitmap(source, 'opaque', 'svg');
+}
+
+function initializeTestCanvas(canvasColorSpace, canvasPixelFormat)
+{
+    var testCanvas = document.createElement("canvas");
+    testCanvas.width = 20;
+    testCanvas.height = 20;
+    var testCtx = testCanvas.getContext('2d',
+        {colorSpace: canvasColorSpace, pixelFormat:canvasPixelFormat});
+    testCtx.fillStyle = "rgba(155, 27, 27, 1)";
+    testCtx.fillRect(0, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 155, 27, 1)";
+    testCtx.fillRect(10, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 155, 1)";
+    testCtx.fillRect(0, 10, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 27, 1)";
+    testCtx.fillRect(10, 10, 10, 10);
+    return testCanvas;
+}
+
+function initializeTestCanvasTransparent(canvasColorSpace, canvasPixelFormat)
+{
+    var testCanvas = document.createElement("canvas");
+    testCanvas.width = 20;
+    testCanvas.height = 20;
+    var testCtx = testCanvas.getContext('2d',
+        {colorSpace: canvasColorSpace, pixelFormat:canvasPixelFormat});
+    testCtx.fillStyle = "rgba(155, 27, 27, 0.5)";
+    testCtx.fillRect(0, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 155, 27, 0.5)";
+    testCtx.fillRect(10, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 155, 0.5)";
+    testCtx.fillRect(0, 10, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 27, 0.5)";
+    testCtx.fillRect(10, 10, 10, 10);
+    return testCanvas;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLImageElement - Opaque SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb.png'
+    }).then(testImageBitmapOpaque);
+}, 'createImageBitmap in linear RGB from an opaque SRGB HTMLImageElement with resize.');
+
+// HTMLImageElement - Transparent SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb-transparent.png'
+    }).then(testImageBitmapTransparent);
+}, 'createImageBitmap in linear RGB from a transparent SRGB HTMLImageElement with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more test scenarios for loading the image element from P3
+// and Rec2020 images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// SVG Image - SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb.svg'
+    }).then(testImageBitmapFromSVG);
+}, 'createImageBitmap in linear RGB from a SRGB SVG image with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the image element from P3 and Rec2020
+// SVG images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLVideoElement - SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var video = document.createElement("video");
+        video.oncanplaythrough = function() {
+            resolve(video);
+        }
+        video.src = 'resources/pattern-srgb-fullcolor.ogv'
+    }).then(testImageBitmapVideoSource);
+}, 'createImageBitmap in linear RGB from a SRGB HTMLVideoElement with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the video element from P3 and Rec2020
+// videos.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLCanvasElement - Opaque SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', '8-8-8-8');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in linear RGB from an opaque SRGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in linear RGB from an opaque linear RGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('rec2020', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in linear RGB from an opaque Rec2020 HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('p3', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in linear RGB from an opaque P3 HTMLCanvasElement with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLCanvasElement - Transparent SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in linear RGB from a transparent SRGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in linear RGB from a transparent linear RGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in linear RGB from a transparent Rec2020 HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('p3', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in linear RGB from a transparent P3 HTMLCanvasElement with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Blob - Opaque SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", 'resources/pattern-srgb.png');
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    }).then(testImageBitmapOpaque);
+}, 'createImageBitmap in linear RGB from an opaque SRGB Blob with resize.');
+
+// Blob - Transparent SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", 'resources/pattern-srgb-transparent.png');
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    }).then(testImageBitmapTransparent);
+}, 'createImageBitmap in linear RGB from a transparent SRGB Blob with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the blob from P3 and Rec2020 images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageData - Opaque SRGB
+promise_test(function() {
+    var canvas = initializeTestCanvas('srgb', '8-8-8-8');
+    var ctx = canvas.getContext('2d');
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in linear RGB from an opaque SRGB ImageData with resize.');
+
+// ImageData - Opaque Linear RGB
+promise_test(function() {
+    var canvas = initializeTestCanvas('srgb', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in linear RGB from an opaque Linear RGB ImageData with resize.');
+
+// ImageData - Opaque Rec2020
+promise_test(function() {
+    var canvas = initializeTestCanvas('rec2020', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in linear RGB from an opaque Rec2020 ImageData with resize.');
+
+// ImageData - Opaque P3
+promise_test(function() {
+    var canvas = initializeTestCanvas('p3', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in linear RGB from an opaque P3 ImageData with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageData - Transparent SRGB
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    var ctx = canvas.getContext('2d');
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in linear RGB from a transparent SRGB ImageData with resize.');
+
+// ImageData - Transparent Linear RGB
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('srgb', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in linear RGB from a transparent Linear RGB ImageData with resize.');
+
+// ImageData - Transparent Rec2020
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in linear RGB from a transparent Rec2020 ImageData with resize.');
+
+// ImageData - Transparent P3
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('p3', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in linear RGB from a transparent P3 ImageData with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageBitmap - Opaque SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', '8-8-8-8');
+    return createImageBitmap(testCanvas).then(testImageBitmapOpaque);
+}, 'createImageBitmap in linear RGB from an opaque SRGB ImageBitmap with resize.');
+
+// ImageBitmap - Opaque Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "linear-rgb"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in linear RGB from an opaque Linear RGB ImageBitmap with resize.');
+
+// ImageBitmap - Opaque Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('rec2020', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "rec2020"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in linear RGB from an opaque Rec2020 ImageBitmap with resize.');
+
+// ImageBitmap - Opaque P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('p3', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "p3"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in linear RGB from an opaque P3 ImageBitmap with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageBitmap - Transparent SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    return createImageBitmap(testCanvas).then(testImageBitmapTransparent);
+}, 'createImageBitmap in linear RGB from a transparent SRGB ImageBitmap with resize.');
+
+// ImageBitmap - Transparent Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "linear-rgb"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in linear RGB from a transparent Linear RGB ImageBitmap with resize.');
+
+// ImageBitmap - Transparent Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "rec2020"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in linear RGB from a transparent Rec2020 ImageBitmap with resize.');
+
+// ImageBitmap - Transparent P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('p3', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "p3"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in linear RGB from a transparent P3 ImageBitmap with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+function initializeOffscreenCanvas(canvasColorSpace, canvasPixelFormat)
+{
+    var canvas = document.createElement("canvas");
+    canvas.width = 20;
+    canvas.height = 20;
+    var offscreen = canvas.transferControlToOffscreen();
+    var ctx = offscreen.getContext('2d');
+    ctx.fillStyle = "rgba(155, 27, 27, 1)";
+    ctx.fillRect(0, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 155, 27, 1)";
+    ctx.fillRect(10, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 155, 1)";
+    ctx.fillRect(0, 10, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 27, 1)";
+    ctx.fillRect(10, 10, 10, 10);
+    return offscreen;
+}
+
+//OffscreenCanvas - Opaque SRGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('srgb', '8-8-8-8');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in linear RGB from an opaque SRGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque Linear RGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('srgb', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in linear RGB from an opaque linear RGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque Rec2020
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('rec2020', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in linear RGB from an opaque Rec2020 OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque P3
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('p3', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in linear RGB from an opaque P3 OffscreenCanvas with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+function initializeOffscreenCanvasTransparent(canvasColorSpace, canvasPixelFormat)
+{
+    var canvas = document.createElement("canvas");
+    canvas.width = 20;
+    canvas.height = 20;
+    var offscreen = canvas.transferControlToOffscreen();
+    var ctx = offscreen.getContext('2d');
+    ctx.fillStyle = "rgba(155, 27, 27, 0.5)";
+    ctx.fillRect(0, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 155, 27, 0.5)";
+    ctx.fillRect(10, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 155, 0.5)";
+    ctx.fillRect(0, 10, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 27, 0.5)";
+    ctx.fillRect(10, 10, 10, 10);
+    return offscreen;
+}
+
+//OffscreenCanvas - Transparent SRGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('srgb', '8-8-8-8');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in linear RGB from a transparent SRGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent Linear RGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('srgb', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in linear RGB from a transparent linear RGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent Rec2020
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('rec2020', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in linear RGB from a transparent Rec2020 OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent P3
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('p3', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in linear RGB from a transparent P3 OffscreenCanvas with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-p3.html b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-p3.html
new file mode 100644
index 0000000..3939bad3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-p3.html
@@ -0,0 +1,607 @@
+<!DOCTYPE HTML>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script>
+
+// The reference values are generated by calling SkImage::makeColorSpace()
+// in a Skia fiddle as this is the API used in ImageBitmap for color conversion.
+// SkColorSpaceXform() may generate slightly different results.
+// Please see: https://fiddle.skia.org/c/94578944d9d52c2b4c2cadda88a4e204
+
+var p3Red =   [0.823242, 0.031372, 0.015686, 1]; // SRGB(255,0,0,255)
+var p3Green = [0.176392, 0.968262, 0.070557, 1]; // SRGB(0,255,0,255)
+var p3Blue =  [0, 0, 0.909668, 1];               // SRGB(0,0,255,255)
+var p3Black = [0, 0, 0, 1];                      // SRGB(0,0,0,255)
+
+var p3OpaqueRed = [0.270508, 0.019608, 0.015686, 1];   // SRGB(155,27,27,255)
+var p3OpaqueGreen = [0.066650, 0.317627, 0.035278, 1]; // SRGB(27,155,27,255)
+var p3OpaqueBlue = [0.011765, 0.011765, 0.297852, 1];  // SRGB(27,27,155,255)
+var p3OpaqueBlack = [0.011765, 0.011765, 0.011765, 1]; // SRGB(27,27,27,255)
+
+// SRGB(155,27,27,128)
+var p3TransparentRed = [0.270508, 0.019608, 0.015686, 0.501953];
+// SRGB(27,155,27,128)
+var p3TransparentGreen = [0.066650, 0.317627, 0.035278, 0.501953];
+// SRGB(27,27,155,128)
+var p3TransparentBlue = [0.011765, 0.011765, 0.297852, 0.501953];
+// SRGB(27,27,27,128)
+var p3TransparentBlack = [0.011765, 0.011765, 0.011765, 0.501953];
+
+function testPixels(ctx, tests, sourceType)
+{
+    var actual, expected, tolerance = 0.01;
+    if (sourceType == 'video')
+        tolerance = 0.02;
+    for (var i = 0; i < tests.length; i++) {
+        actual = ctx.getImageData(tests[i][0], tests[i][1], 1, 1).dataUnion;
+        expected = tests[i][2];
+        assert_true(actual.length === expected.length);
+       for (var i = 0; i < actual.length; i++)
+           assert_approx_equals(actual[i], expected[i], tolerance, tests[i][3]);
+    }
+}
+
+function checkNoCrop(imageBitmap, colorInfo, sourceType)
+{
+    var canvas = document.createElement('canvas');
+    canvas.width = 50;
+    canvas.height = 50;
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(imageBitmap, 0, 0);
+    var tests;
+    if (colorInfo == 'fullColor')
+        tests = [[0, 0, p3Red, "This pixel should be P3 red."],
+                 [39, 0, p3Green, "This pixel should be P3 green."],
+                 [0, 39, p3Blue, "This pixel should be P3 blue."],
+                 [39, 39, p3Black, "This pixel should be P3 black."],
+                 [41, 41, p3Black, "This pixel should be P3 black."]];
+    else if (colorInfo == 'opaque')
+        tests = [[0, 0, p3OpaqueRed, "This pixel should be P3 like red."],
+                 [39, 0, p3OpaqueGreen, "This pixel should be P3 like green."],
+                 [0, 39, p3OpaqueBlue, "This pixel should be P3 like blue."],
+                 [39, 39, p3OpaqueBlack, "This pixel should be P3 like black."],
+                 [41, 41, p3Black, "This pixel should be P3 black."]];
+    else if (colorInfo == 'transparent')
+        tests = [[0, 0, p3TransparentRed,
+                     "This pixel should be P3 transparent red."],
+                 [39, 0, p3TransparentGreen,
+                     "This pixel should be P3 transparent green."],
+                 [0, 39, p3TransparentBlue,
+                     "This pixel should be P3 transparent blue."],
+                 [39, 39, p3TransparentBlack,
+                     "This pixel should be P3 transparent black."],
+                 [41, 41, p3Black, "This pixel should be P3 black."]];
+    testPixels(ctx, tests, sourceType);
+}
+
+function checkCrop(imageBitmap, colorInfo, sourceType)
+{
+    var canvas = document.createElement('canvas');
+    canvas.width = 50;
+    canvas.height = 50;
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(imageBitmap, 0, 0);
+    var tests;
+    if (colorInfo === 'fullColor')
+        tests = [[0, 0, p3Red, "This pixel should be P3 red."],
+                 [19, 0, p3Green, "This pixel should be P3 green."],
+                 [0, 19, p3Blue, "This pixel should be P3 blue."],
+                 [19, 19, p3Black, "This pixel should be P3 black."],
+                 [21, 21, p3Black, "This pixel should be P3 black."]];
+    else if (colorInfo === 'opaque')
+        tests = [[0, 0, p3OpaqueRed, "This pixel should be P3 like red."],
+                 [19, 0, p3OpaqueGreen, "This pixel should be P3 like green."],
+                 [0, 19, p3OpaqueBlue, "This pixel should be P3 like blue."],
+                 [19, 19, p3OpaqueBlack, "This pixel should be P3 like black."],
+                 [21, 21, p3Black, "This pixel should be P3 black."]];
+    else if (colorInfo === 'transparent')
+        tests = [[0, 0, p3TransparentRed,
+                     "This pixel should be P3 transparent red."],
+                 [19, 0, p3TransparentGreen,
+                     "This pixel should be P3 transparent green."],
+                 [0, 19, p3TransparentBlue,
+                     "This pixel should be P3 transparent blue."],
+                 [19, 19, p3TransparentBlack,
+                     "This pixel should be P3 transparent black."],
+                 [21, 21, p3Black, "This pixel should be P3 black."]];
+    testPixels(ctx, tests, sourceType);
+}
+
+function compareBitmaps(bitmap1, bitmap2)
+{
+    var canvas1 = document.createElement('canvas');
+    var canvas2 = document.createElement('canvas');
+    canvas1.width = 50;
+    canvas1.height = 50;
+    canvas2.width = 50;
+    canvas2.height = 50;
+    var ctx1 = canvas1.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    var ctx2 = canvas2.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
+    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
+    ctx1.drawImage(bitmap1, 0, 0);
+    ctx2.drawImage(bitmap2, 0, 0);
+    var data1 = ctx1.getImageData(0, 0, 50, 50).dataUnion;
+    var data2 = ctx2.getImageData(0, 0, 50, 50).dataUnion;
+    var dataMatched = true;
+    for (var i = 0; i < data1.length; i++) {
+        if (data1[i] != data2[i]) {
+            dataMatched = false;
+            break;
+        }
+    }
+    assert_false(dataMatched);
+}
+
+function testImageBitmap(source, colorInfo, sourceType)
+{
+    return Promise.all([
+        createImageBitmap(source, {colorSpaceConversion: "p3", resizeWidth: 40,
+            resizeHeight: 40, resizeQuality: "high"}),
+        createImageBitmap(source, {colorSpaceConversion: "p3", resizeWidth: 40,
+            resizeHeight: 40, resizeQuality: "medium"}),
+        createImageBitmap(source, {colorSpaceConversion: "p3", resizeWidth: 40,
+            resizeHeight: 40, resizeQuality: "low"}),
+        createImageBitmap(source, {colorSpaceConversion: "p3", resizeWidth: 40,
+            resizeHeight: 40, resizeQuality: "pixelated"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "p3",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "high"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "p3",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "medium"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "p3",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "low"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "p3",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "pixelated"}),
+    ]).then(([noCropHigh, noCropMedium, noCropLow, noCropPixelated, cropHigh,
+              cropMedium, cropLow, cropPixelated]) => {
+        checkNoCrop(noCropHigh, colorInfo, sourceType);
+        checkNoCrop(noCropMedium, colorInfo, sourceType);
+        checkNoCrop(noCropLow, colorInfo, sourceType);
+        checkNoCrop(noCropPixelated, colorInfo, sourceType);
+        checkCrop(cropHigh, colorInfo, sourceType);
+        checkCrop(cropMedium, colorInfo, sourceType);
+        checkCrop(cropLow, colorInfo, sourceType);
+        checkCrop(cropPixelated, colorInfo, sourceType);
+        // Brute-force comparison among all bitmaps is too expensive.
+        // In case of SVG, resize quality does not affect the images, so all
+        // of them are the same and the tests fail. Since, we ignore this test
+        // set for SVG.
+        if (sourceType != 'svg') {
+            compareBitmaps(noCropHigh, noCropMedium);
+            compareBitmaps(noCropLow, noCropPixelated);
+            compareBitmaps(cropHigh, cropMedium);
+            compareBitmaps(cropLow, cropPixelated);
+        }
+    });
+}
+
+function testImageBitmapTransparent(source)
+{
+    return testImageBitmap(source, 'transparent', 'general');
+}
+
+function testImageBitmapFromVideo(source)
+{
+    return testImageBitmap(source, 'fullColor', 'video');
+}
+
+function testImageBitmapOpaque(source)
+{
+    return testImageBitmap(source, 'opaque', 'general');
+}
+
+function testImageBitmapFromSVG(source)
+{
+    return testImageBitmap(source, 'opaque', 'svg');
+}
+
+function initializeTestCanvas(canvasColorSpace, canvasPixelFormat)
+{
+    var testCanvas = document.createElement("canvas");
+    testCanvas.width = 20;
+    testCanvas.height = 20;
+    var testCtx = testCanvas.getContext('2d',
+        {colorSpace: canvasColorSpace, pixelFormat:canvasPixelFormat});
+    testCtx.fillStyle = "rgba(155, 27, 27, 1)";
+    testCtx.fillRect(0, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 155, 27, 1)";
+    testCtx.fillRect(10, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 155, 1)";
+    testCtx.fillRect(0, 10, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 27, 1)";
+    testCtx.fillRect(10, 10, 10, 10);
+    return testCanvas;
+}
+
+function initializeTestCanvasTransparent(canvasColorSpace, canvasPixelFormat)
+{
+    var testCanvas = document.createElement("canvas");
+    testCanvas.width = 20;
+    testCanvas.height = 20;
+    var testCtx = testCanvas.getContext('2d',
+        {colorSpace: canvasColorSpace, pixelFormat:canvasPixelFormat});
+    testCtx.fillStyle = "rgba(155, 27, 27, 0.5)";
+    testCtx.fillRect(0, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 155, 27, 0.5)";
+    testCtx.fillRect(10, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 155, 0.5)";
+    testCtx.fillRect(0, 10, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 27, 0.5)";
+    testCtx.fillRect(10, 10, 10, 10);
+    return testCanvas;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLImageElement - Opaque SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb.png'
+    }).then(testImageBitmapOpaque);
+}, 'createImageBitmap in P3 from an opaque SRGB HTMLImageElement with resize.');
+
+// HTMLImageElement - Transparent SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb-transparent.png'
+    }).then(testImageBitmapTransparent);
+}, 'createImageBitmap in P3 from a transparent SRGB HTMLImageElement with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more test scenarios for loading the image element from P3
+// and Rec2020 images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// SVG Image - SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb.svg'
+    }).then(testImageBitmapFromSVG);
+}, 'createImageBitmap in P3 from a SRGB SVG image with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the image element from P3 and Rec2020
+// SVG images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLVideoElement - SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var video = document.createElement("video");
+        video.oncanplaythrough = function() {
+            resolve(video);
+        }
+        video.src = 'resources/pattern-srgb-fullcolor.ogv'
+    }).then(testImageBitmapFromVideo);
+}, 'createImageBitmap in P3 from a SRGB HTMLVideoElement with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the video element from P3 and Rec2020
+// videos.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLCanvasElement - Opaque SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', '8-8-8-8');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in P3 from an opaque SRGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in P3 from an opaque linear RGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('rec2020', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in P3 from an opaque Rec2020 HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('p3', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in P3 from an opaque P3 HTMLCanvasElement with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLCanvasElement - Transparent SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in P3 from a transparent SRGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in P3 from a transparent linear RGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in P3 from a transparent Rec2020 HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('p3', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in P3 from a transparent P3 HTMLCanvasElement with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Blob - Opaque SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", 'resources/pattern-srgb.png');
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    }).then(testImageBitmapOpaque);
+}, 'createImageBitmap in P3 from an opaque SRGB Blob with resize.');
+
+// Blob - Transparent SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", 'resources/pattern-srgb-transparent.png');
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    }).then(testImageBitmapTransparent);
+}, 'createImageBitmap in P3 from a transparent SRGB Blob with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the blob from P3 and Rec2020 images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageData - Opaque SRGB
+promise_test(function() {
+    var canvas = initializeTestCanvas('srgb', '8-8-8-8');
+    var ctx = canvas.getContext('2d');
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in P3 from an opaque SRGB ImageData with resize.');
+
+// ImageData - Opaque Linear RGB
+promise_test(function() {
+    var canvas = initializeTestCanvas('srgb', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in P3 from an opaque Linear RGB ImageData with resize.');
+
+// ImageData - Opaque Rec2020
+promise_test(function() {
+    var canvas = initializeTestCanvas('rec2020', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in P3 from an opaque Rec2020 ImageData with resize.');
+
+// ImageData - Opaque P3
+promise_test(function() {
+    var canvas = initializeTestCanvas('p3', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in P3 from an opaque P3 ImageData with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageData - Transparent SRGB
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    var ctx = canvas.getContext('2d');
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in P3 from a transparent SRGB ImageData with resize.');
+
+// ImageData - Transparent Linear RGB
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('srgb', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in P3 from a transparent Linear RGB ImageData with resize.');
+
+// ImageData - Transparent Rec2020
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in P3 from a transparent Rec2020 ImageData with resize.');
+
+// ImageData - Transparent P3
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('p3', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in P3 from a transparent P3 ImageData with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageBitmap - Opaque SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', '8-8-8-8');
+    return createImageBitmap(testCanvas).then(testImageBitmapOpaque);
+}, 'createImageBitmap in P3 from an opaque SRGB ImageBitmap with resize.');
+
+// ImageBitmap - Opaque Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "linear-rgb"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in P3 from an opaque Linear RGB ImageBitmap with resize.');
+
+// ImageBitmap - Opaque Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('rec2020', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "rec2020"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in P3 from an opaque Rec2020 ImageBitmap with resize.');
+
+// ImageBitmap - Opaque P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('p3', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "p3"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in P3 from an opaque P3 ImageBitmap with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageBitmap - Transparent SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    return createImageBitmap(testCanvas).then(testImageBitmapTransparent);
+}, 'createImageBitmap in P3 from a transparent SRGB ImageBitmap with resize.');
+
+// ImageBitmap - Transparent Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "linear-rgb"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in P3 from a transparent Linear RGB ImageBitmap with resize.');
+
+// ImageBitmap - Transparent Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "rec2020"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in P3 from a transparent Rec2020 ImageBitmap with resize.');
+
+// ImageBitmap - Transparent P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('p3', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "p3"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in P3 from a transparent P3 ImageBitmap with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+function initializeOffscreenCanvas(canvasColorSpace, canvasPixelFormat)
+{
+    var canvas = document.createElement("canvas");
+    canvas.width = 20;
+    canvas.height = 20;
+    var offscreen = canvas.transferControlToOffscreen();
+    var ctx = offscreen.getContext('2d');
+    ctx.fillStyle = "rgba(155, 27, 27, 1)";
+    ctx.fillRect(0, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 155, 27, 1)";
+    ctx.fillRect(10, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 155, 1)";
+    ctx.fillRect(0, 10, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 27, 1)";
+    ctx.fillRect(10, 10, 10, 10);
+    return offscreen;
+}
+
+//OffscreenCanvas - Opaque SRGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('srgb', '8-8-8-8');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in P3 from an opaque SRGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque Linear RGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('srgb', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in P3 from an opaque linear RGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque Rec2020
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('rec2020', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in P3 from an opaque Rec2020 OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque P3
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('p3', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in P3 from an opaque P3 OffscreenCanvas with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+function initializeOffscreenCanvasTransparent(canvasColorSpace, canvasPixelFormat)
+{
+    var canvas = document.createElement("canvas");
+    canvas.width = 20;
+    canvas.height = 20;
+    var offscreen = canvas.transferControlToOffscreen();
+    var ctx = offscreen.getContext('2d');
+    ctx.fillStyle = "rgba(155, 27, 27, 0.5)";
+    ctx.fillRect(0, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 155, 27, 0.5)";
+    ctx.fillRect(10, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 155, 0.5)";
+    ctx.fillRect(0, 10, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 27, 0.5)";
+    ctx.fillRect(10, 10, 10, 10);
+    return offscreen;
+}
+
+//OffscreenCanvas - Transparent SRGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('srgb', '8-8-8-8');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in P3 from a transparent SRGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent Linear RGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('srgb', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in P3 from a transparent linear RGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent Rec2020
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('rec2020', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in P3 from a transparent Rec2020 OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent P3
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('p3', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in P3 from a transparent P3 OffscreenCanvas with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html
new file mode 100644
index 0000000..cb368fb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html
@@ -0,0 +1,621 @@
+<!DOCTYPE HTML>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script>
+
+// The reference values are generated by calling SkImage::makeColorSpace()
+// in a Skia fiddle as this is the API used in ImageBitmap for color conversion.
+// SkColorSpaceXform() may generate slightly different results.
+// Please see: https://fiddle.skia.org/c/94578944d9d52c2b4c2cadda88a4e204
+
+var rec2020Red =   [0.627441, 0.070557, 0.015686, 1]; // SRGB(255,0,0,255)
+var rec2020Green = [0.329346, 0.917480, 0.086243, 1]; // SRGB(0,255,0,255)
+var rec2020Blue =  [0.043121, 0.011765, 0.894043, 1]; // SRGB(0,0,255,255)
+var rec2020Black = [0, 0, 0, 1];                      // SRGB(0,0,0,255)
+
+// SRGB(155,27,27,255)
+var rec2020OpaqueRed = [0.207764, 0.031372, 0.015686, 1];
+// SRGB(27,155,27,255)
+var rec2020OpaqueGreen = [0.113708, 0.301758, 0.039215, 1];
+// SRGB(27,27,155,255)
+var rec2020OpaqueBlue = [0.023529, 0.015686, 0.293945, 1];
+// SRGB(27,27,27,255)
+var rec2020OpaqueBlack = [0.011765, 0.011765, 0.011765, 1];
+
+// SRGB(155,27,27,128)
+var rec2020TransparentRed = [0.207764, 0.031372, 0.015686, 0.501953];
+// SRGB(27,155,27,128)
+var rec2020TransparentGreen = [0.113708, 0.301758, 0.039215, 0.501953];
+// SRGB(27,27,155,128)
+var rec2020TransparentBlue = [0.023529, 0.015686, 0.293945, 0.501953];
+// SRGB(27,27,27,128)
+var rec2020TransparentBlack = [0.011765, 0.011765, 0.011765, 0.501953];
+
+function testPixels(ctx, tests, sourceType)
+{
+    var actual, expected, tolerance = 0.01;
+    if (sourceType === 'video')
+        tolerance = 0.02;
+    for (var i = 0; i < tests.length; i++) {
+        actual = ctx.getImageData(tests[i][0], tests[i][1], 1, 1).dataUnion;
+        expected = tests[i][2];
+        assert_true(actual.length === expected.length);
+       for (var i = 0; i < actual.length; i++)
+           assert_approx_equals(actual[i], expected[i], tolerance, tests[i][3]);
+    }
+}
+
+function checkNoCrop(imageBitmap, colorInfo, sourceType)
+{
+    var canvas = document.createElement('canvas');
+    canvas.width = 50;
+    canvas.height = 50;
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(imageBitmap, 0, 0);
+    var tests;
+    if (colorInfo == 'fullColor')
+        tests = [[0, 0, rec2020Red, "This pixel should be Rec2020 red."],
+                 [39, 0, rec2020Green, "This pixel should be Rec2020 green."],
+                 [0, 39, rec2020Blue, "This pixel should be Rec2020 blue."],
+                 [39, 39, rec2020Black, "This pixel should be Rec2020 black."],
+                 [41, 41, rec2020Black, "This pixel should be Rec2020 black."]];
+    else if (colorInfo == 'opaque')
+        tests = [[0, 0, rec2020OpaqueRed,
+                     "This pixel should be Rec2020 like red."],
+                 [39, 0, rec2020OpaqueGreen,
+                     "This pixel should be Rec2020 like green."],
+                 [0, 39, rec2020OpaqueBlue,
+                     "This pixel should be Rec2020 like blue."],
+                 [39, 39, rec2020OpaqueBlack,
+                     "This pixel should be Rec2020 like black."],
+                 [41, 41, rec2020Black,
+                     "This pixel should be Rec2020 black."]];
+    else if (colorInfo == 'transparent')
+        tests = [[0, 0, rec2020TransparentRed,
+                     "This pixel should be Rec2020 transparent red."],
+                 [39, 0, rec2020TransparentGreen,
+                     "This pixel should be Rec2020 transparent green."],
+                 [0, 39, rec2020TransparentBlue,
+                     "This pixel should be Rec2020 transparent blue."],
+                 [39, 39, rec2020TransparentBlack,
+                     "This pixel should be Rec2020 transparent black."],
+                 [41, 41, rec2020Black, "This pixel should be Rec2020 black."]];
+    testPixels(ctx, tests, sourceType);
+}
+
+function checkCrop(imageBitmap, colorInfo, sourceType)
+{
+    var canvas = document.createElement('canvas');
+    canvas.width = 50;
+    canvas.height = 50;
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(imageBitmap, 0, 0);
+    var tests;
+    if (colorInfo === 'fullColor')
+        tests = [[0, 0, rec2020Red, "This pixel should be Rec2020 red."],
+                 [19, 0, rec2020Green, "This pixel should be Rec2020 green."],
+                 [0, 19, rec2020Blue, "This pixel should be Rec2020 blue."],
+                 [19, 19, rec2020Black, "This pixel should be Rec2020 black."],
+                 [21, 21, rec2020Black, "This pixel should be Rec2020 black."]];
+    else if (colorInfo === 'opaque')
+        tests = [[0, 0, rec2020OpaqueRed,
+                     "This pixel should be Rec2020 like red."],
+                 [19, 0, rec2020OpaqueGreen,
+                     "This pixel should be Rec2020 like green."],
+                 [0, 19, rec2020OpaqueBlue,
+                     "This pixel should be Rec2020 like blue."],
+                 [19, 19, rec2020OpaqueBlack,
+                     "This pixel should be Rec2020 like black."],
+                 [21, 21, rec2020Black, "This pixel should be Rec2020 black."]];
+    else if (colorInfo === 'transparent')
+        tests = [[0, 0, rec2020TransparentRed,
+                     "This pixel should be Rec2020 transparent red."],
+                 [19, 0, rec2020TransparentGreen,
+                     "This pixel should be Rec2020 transparent green."],
+                 [0, 19, rec2020TransparentBlue,
+                     "This pixel should be Rec2020 transparent blue."],
+                 [19, 19, rec2020TransparentBlack,
+                     "This pixel should be Rec2020 transparent black."],
+                 [21, 21, rec2020Black, "This pixel should be Rec2020 black."]];
+    testPixels(ctx, tests, sourceType);
+}
+
+
+function compareBitmaps(bitmap1, bitmap2)
+{
+    var canvas1 = document.createElement('canvas');
+    var canvas2 = document.createElement('canvas');
+    canvas1.width = 50;
+    canvas1.height = 50;
+    canvas2.width = 50;
+    canvas2.height = 50;
+    var ctx1 = canvas1.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    var ctx2 = canvas2.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
+    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
+    ctx1.drawImage(bitmap1, 0, 0);
+    ctx2.drawImage(bitmap2, 0, 0);
+    var data1 = ctx1.getImageData(0, 0, 50, 50).dataUnion;
+    var data2 = ctx2.getImageData(0, 0, 50, 50).dataUnion;
+    var dataMatched = true;
+    for (var i = 0; i < data1.length; i++) {
+        if (data1[i] != data2[i]) {
+            dataMatched = false;
+            break;
+        }
+    }
+    assert_false(dataMatched);
+}
+
+function testImageBitmap(source, colorInfo, sourceType)
+{
+    return Promise.all([
+        createImageBitmap(source, {colorSpaceConversion: "rec2020",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "high"}),
+        createImageBitmap(source, {colorSpaceConversion: "rec2020",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "medium"}),
+        createImageBitmap(source, {colorSpaceConversion: "rec2020",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "low"}),
+        createImageBitmap(source, {colorSpaceConversion: "rec2020",
+            resizeWidth: 40, resizeHeight: 40, resizeQuality: "pixelated"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "rec2020",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "high"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "rec2020",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "medium"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "rec2020",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "low"}),
+        createImageBitmap(source, 5, 5, 10, 10, {colorSpaceConversion: "rec2020",
+            resizeWidth: 20, resizeHeight: 20, resizeQuality: "pixelated"}),
+    ]).then(([noCropHigh, noCropMedium, noCropLow, noCropPixelated, cropHigh,
+              cropMedium, cropLow, cropPixelated]) => {
+        checkNoCrop(noCropHigh, colorInfo, sourceType);
+        checkNoCrop(noCropMedium, colorInfo, sourceType);
+        checkNoCrop(noCropLow, colorInfo, sourceType);
+        checkNoCrop(noCropPixelated, colorInfo, sourceType);
+        checkCrop(cropHigh, colorInfo, sourceType);
+        checkCrop(cropMedium, colorInfo, sourceType);
+        checkCrop(cropLow, colorInfo, sourceType);
+        checkCrop(cropPixelated, colorInfo, sourceType);
+        // Brute-force comparison among all bitmaps is too expensive.
+        // In case of SVG, resize quality does not affect the images, so all
+        // of them are the same and the tests fail. Since, we ignore this test
+        // set for SVG.
+        if (sourceType != 'svg') {
+            compareBitmaps(noCropHigh, noCropMedium);
+            compareBitmaps(noCropLow, noCropPixelated);
+            compareBitmaps(cropHigh, cropMedium);
+            compareBitmaps(cropLow, cropPixelated);
+        }
+    });
+}
+
+function testImageBitmapTransparent(source)
+{
+    return testImageBitmap(source, 'transparent', 'general');
+}
+
+function testImageBitmapFromVideo(source)
+{
+    return testImageBitmap(source, 'fullColor', 'video');
+}
+
+function testImageBitmapOpaque(source)
+{
+    return testImageBitmap(source, 'opaque', 'general');
+}
+
+function testImageBitmapFromSVG(source)
+{
+    return testImageBitmap(source, 'opaque', 'svg');
+}
+
+function initializeTestCanvas(canvasColorSpace, canvasPixelFormat)
+{
+    var testCanvas = document.createElement("canvas");
+    testCanvas.width = 20;
+    testCanvas.height = 20;
+    var testCtx = testCanvas.getContext('2d',
+        {colorSpace: canvasColorSpace, pixelFormat:canvasPixelFormat});
+    testCtx.fillStyle = "rgba(155, 27, 27, 1)";
+    testCtx.fillRect(0, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 155, 27, 1)";
+    testCtx.fillRect(10, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 155, 1)";
+    testCtx.fillRect(0, 10, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 27, 1)";
+    testCtx.fillRect(10, 10, 10, 10);
+    return testCanvas;
+}
+
+function initializeTestCanvasTransparent(canvasColorSpace, canvasPixelFormat)
+{
+    var testCanvas = document.createElement("canvas");
+    testCanvas.width = 20;
+    testCanvas.height = 20;
+    var testCtx = testCanvas.getContext('2d',
+        {colorSpace: canvasColorSpace, pixelFormat:canvasPixelFormat});
+    testCtx.fillStyle = "rgba(155, 27, 27, 0.5)";
+    testCtx.fillRect(0, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 155, 27, 0.5)";
+    testCtx.fillRect(10, 0, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 155, 0.5)";
+    testCtx.fillRect(0, 10, 10, 10);
+    testCtx.fillStyle = "rgba(27, 27, 27, 0.5)";
+    testCtx.fillRect(10, 10, 10, 10);
+    return testCanvas;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLImageElement - Opaque SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb.png'
+    }).then(testImageBitmapOpaque);
+}, 'createImageBitmap in Rec2020 from an opaque SRGB HTMLImageElement with resize.');
+
+// HTMLImageElement - Transparent SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb-transparent.png'
+    }).then(testImageBitmapTransparent);
+}, 'createImageBitmap in Rec2020 from a transparent SRGB HTMLImageElement with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more test scenarios for loading the image element from P3
+// and Rec2020 images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// SVG Image - SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var image = new Image();
+        image.onload = function() {
+            resolve(image);
+        }
+        image.src = 'resources/pattern-srgb.svg'
+    }).then(testImageBitmapFromSVG);
+}, 'createImageBitmap in Rec2020 from a SRGB SVG image with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the image element from P3 and Rec2020
+// SVG images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLVideoElement - SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var video = document.createElement("video");
+        video.oncanplaythrough = function() {
+            resolve(video);
+        }
+        video.src = 'resources/pattern-srgb-fullcolor.ogv'
+    }).then(testImageBitmapFromVideo);
+}, 'createImageBitmap in Rec2020 from a SRGB HTMLVideoElement with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the video element from P3 and Rec2020
+// videos.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLCanvasElement - Opaque SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', '8-8-8-8');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in Rec2020 from an opaque SRGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in Rec2020 from an opaque linear RGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('rec2020', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in Rec2020 from an opaque Rec2020 HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Opaque P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('p3', 'float16');
+    return testImageBitmapOpaque(testCanvas);
+}, 'createImageBitmap in Rec2020 from an opaque P3 HTMLCanvasElement with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HTMLCanvasElement - Transparent SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in Rec2020 from a transparent SRGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in Rec2020 from a transparent linear RGB HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in Rec2020 from a transparent Rec2020 HTMLCanvasElement with resize.');
+
+// HTMLCanvasElement - Transparent P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('p3', 'float16');
+    return testImageBitmapTransparent(testCanvas);
+}, 'createImageBitmap in Rec2020 from a transparent P3 HTMLCanvasElement with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Blob - Opaque SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", 'resources/pattern-srgb.png');
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    }).then(testImageBitmapOpaque);
+}, 'createImageBitmap in Rec2020 from an opaque SRGB Blob with resize.');
+
+// Blob - Transparent SRGB
+promise_test(function() {
+    return new Promise((resolve, reject) => {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", 'resources/pattern-srgb-transparent.png');
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    }).then(testImageBitmapTransparent);
+}, 'createImageBitmap in Rec2020 from a transparent SRGB Blob with resize.');
+
+// TODO(zakerinasab): crbug.com/668547
+// Add at least two more tests for loading the blob from P3 and Rec2020 images.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageData - Opaque SRGB
+promise_test(function() {
+    var canvas = initializeTestCanvas('srgb', '8-8-8-8');
+    var ctx = canvas.getContext('2d');
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in Rec2020 from an opaque SRGB ImageData with resize.');
+
+// ImageData - Opaque Linear RGB
+promise_test(function() {
+    var canvas = initializeTestCanvas('srgb', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in Rec2020 from an opaque Linear RGB ImageData with resize.');
+
+// ImageData - Opaque Rec2020
+promise_test(function() {
+    var canvas = initializeTestCanvas('rec2020', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in Rec2020 from an opaque Rec2020 ImageData with resize.');
+
+// ImageData - Opaque P3
+promise_test(function() {
+    var canvas = initializeTestCanvas('p3', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapOpaque(data);
+}, 'createImageBitmap in Rec2020 from an opaque P3 ImageData with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageData - Transparent SRGB
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    var ctx = canvas.getContext('2d');
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in Rec2020 from a transparent SRGB ImageData with resize.');
+
+// ImageData - Transparent Linear RGB
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('srgb', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'srgb', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in Rec2020 from a transparent Linear RGB ImageData with resize.');
+
+// ImageData - Transparent Rec2020
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'rec2020', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in Rec2020 from a transparent Rec2020 ImageData with resize.');
+
+// ImageData - Transparent P3
+promise_test(function() {
+    var canvas = initializeTestCanvasTransparent('p3', 'float16');
+    var ctx = canvas.getContext('2d',
+        {colorSpace: 'p3', pixelFormat:'float16'});
+    var data = ctx.getImageData(0, 0, 20, 20);
+    return testImageBitmapTransparent(data);
+}, 'createImageBitmap in Rec2020 from a transparent P3 ImageData with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageBitmap - Opaque SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', '8-8-8-8');
+    return createImageBitmap(testCanvas).then(testImageBitmapOpaque);
+}, 'createImageBitmap in Rec2020 from an opaque SRGB ImageBitmap with resize.');
+
+// ImageBitmap - Opaque Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('srgb', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "linear-rgb"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in Rec2020 from an opaque Linear RGB ImageBitmap with resize.');
+
+// ImageBitmap - Opaque Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('rec2020', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "rec2020"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in Rec2020 from an opaque Rec2020 ImageBitmap with resize.');
+
+// ImageBitmap - Opaque P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvas('p3', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "p3"}
+        ).then(testImageBitmapOpaque);
+}, 'createImageBitmap in Rec2020 from an opaque P3 ImageBitmap with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+// ImageBitmap - Transparent SRGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', '8-8-8-8');
+    return createImageBitmap(testCanvas).then(testImageBitmapTransparent);
+}, 'createImageBitmap in Rec2020 from a transparent SRGB ImageBitmap with resize.');
+
+// ImageBitmap - Transparent Linear RGB
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('srgb', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "linear-rgb"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in Rec2020 from a transparent Linear RGB ImageBitmap with resize.');
+
+// ImageBitmap - Transparent Rec2020
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('rec2020', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "rec2020"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in Rec2020 from a transparent Rec2020 ImageBitmap with resize.');
+
+// ImageBitmap - Transparent P3
+promise_test(function() {
+    var testCanvas = initializeTestCanvasTransparent('p3', 'float16');
+    return createImageBitmap(testCanvas, {colorSpaceConversion: "p3"}
+        ).then(testImageBitmapTransparent);
+}, 'createImageBitmap in Rec2020 from a transparent P3 ImageBitmap with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+function initializeOffscreenCanvas(canvasColorSpace, canvasPixelFormat)
+{
+    var canvas = document.createElement("canvas");
+    canvas.width = 20;
+    canvas.height = 20;
+    var offscreen = canvas.transferControlToOffscreen();
+    var ctx = offscreen.getContext('2d');
+    ctx.fillStyle = "rgba(155, 27, 27, 1)";
+    ctx.fillRect(0, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 155, 27, 1)";
+    ctx.fillRect(10, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 155, 1)";
+    ctx.fillRect(0, 10, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 27, 1)";
+    ctx.fillRect(10, 10, 10, 10);
+    return offscreen;
+}
+
+//OffscreenCanvas - Opaque SRGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('srgb', '8-8-8-8');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in Rec2020 from an opaque SRGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque Linear RGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('srgb', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in Rec2020 from an opaque linear RGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque Rec2020
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('rec2020', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in Rec2020 from an opaque Rec2020 OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Opaque P3
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvas('p3', 'float16');
+    return testImageBitmapOpaque(offscreen);
+}, 'createImageBitmap in Rec2020 from an opaque P3 OffscreenCanvas with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+function initializeOffscreenCanvasTransparent(canvasColorSpace, canvasPixelFormat)
+{
+    var canvas = document.createElement("canvas");
+    canvas.width = 20;
+    canvas.height = 20;
+    var offscreen = canvas.transferControlToOffscreen();
+    var ctx = offscreen.getContext('2d');
+    ctx.fillStyle = "rgba(155, 27, 27, 0.5)";
+    ctx.fillRect(0, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 155, 27, 0.5)";
+    ctx.fillRect(10, 0, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 155, 0.5)";
+    ctx.fillRect(0, 10, 10, 10);
+    ctx.fillStyle = "rgba(27, 27, 27, 0.5)";
+    ctx.fillRect(10, 10, 10, 10);
+    return offscreen;
+}
+
+//OffscreenCanvas - Transparent SRGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('srgb', '8-8-8-8');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in Rec2020 from a transparent SRGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent Linear RGB
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('srgb', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in Rec2020 from a transparent linear RGB OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent Rec2020
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('rec2020', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in Rec2020 from a transparent Rec2020 OffscreenCanvas with resize.');
+
+//OffscreenCanvas - Transparent P3
+promise_test(function() {
+    var offscreen = initializeOffscreenCanvasTransparent('p3', 'float16');
+    return testImageBitmapTransparent(offscreen);
+}, 'createImageBitmap in Rec2020 from a transparent P3 OffscreenCanvas with resize.');
+
+////////////////////////////////////////////////////////////////////////////////
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-linear-rgb.html b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-linear-rgb.html
new file mode 100644
index 0000000..6453c3d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-linear-rgb.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script>
+
+// The reference values are generated by calling SkImage::makeColorSpace()
+// in a Skia fiddle. SkColorSpaceXform() may generate different results.
+// Please see: https://fiddle.skia.org/c/94578944d9d52c2b4c2cadda88a4e204
+var linearTransparentRed = [0.329346, 0.011765, 0.011765, 0.501953];
+var linearTransparentGreen = [0.011765, 0.329346, 0.011765, 0.501953];
+var linearTransparentBlue = [0.011765, 0.011765, 0.329346, 0.501953];
+var linearTransparentBlack = [0.011765, 0.011765, 0.011765, 0.501953];
+
+function testPixels(ctx, tests)
+{
+    var actual, expected, tolerance = 0.005;
+    console.log(tests.length);
+    for (var i = 0; i < tests.length; i++) {
+      actual = ctx.getImageData(tests[i].x, tests[i].y, 1, 1).dataUnion;
+      expected = tests[i].color;
+      assert_true(actual.length === expected.length);
+      for (var j = 0; j < actual.length; j++)
+        assert_approx_equals(actual[j], expected[j], tolerance);
+    }
+}
+
+function drawSRGBImageOnLinearRGBCanvas(source)
+{
+  var canvas = document.createElement('canvas');
+  canvas.width = 20;
+  canvas.height = 20;
+  var ctx = canvas.getContext('2d',
+      {colorSpace: 'srgb', pixelFormat:'float16'});
+  ctx.drawImage(source, 0, 0);
+  var tests = [{x: 5, y: 5, color: linearTransparentRed},
+               {x: 15, y: 5, color: linearTransparentGreen},
+               {x: 5, y: 15, color: linearTransparentBlue},
+               {x: 15, y: 15, color: linearTransparentBlack}];
+  testPixels(ctx, tests);
+}
+
+promise_test(function() {
+  return new Promise((resolve, reject) => {
+    var image = new Image();
+    image.onload = function() {
+      resolve(image);
+    }
+    image.src = 'resources/pattern-semitransparent-srgb.png'
+  }).then(drawSRGBImageOnLinearRGBCanvas);
+}, 'Draw SRGB image on a linear RGB canvas and read back the linear RGB pixels.');
+
+// TODO(zakerinasab): crbug.com/713867
+// Add at least two more tests to load pattern-semitransparent-p3d65.png and
+// pattern-semitransparent-rec2020.png and draw them on a linear RGB canvas.
+
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-p3.html b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-p3.html
new file mode 100644
index 0000000..0d9ed53
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-p3.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script>
+
+// The reference values are generated by calling SkImage::makeColorSpace()
+// in a Skia fiddle. SkColorSpaceXform() may generate different results.
+// Please see: https://fiddle.skia.org/c/94578944d9d52c2b4c2cadda88a4e204
+var p3TransparentRed = [0.270508, 0.019608, 0.015686, 0.501953];
+var p3TransparentGreen = [0.066650, 0.317627, 0.035278, 0.501953];
+var p3TransparentBlue = [0.011765, 0.011765, 0.297852, 0.501953];
+var p3TransparentBlack = [0.011765, 0.011765, 0.011765, 0.501953];
+
+function testPixels(ctx, tests)
+{
+    var actual, expected, tolerance = 0.005;
+    console.log(tests.length);
+    for (var i = 0; i < tests.length; i++) {
+      actual = ctx.getImageData(tests[i].x, tests[i].y, 1, 1).dataUnion;
+      expected = tests[i].color;
+      assert_true(actual.length === expected.length);
+      for (var j = 0; j < actual.length; j++)
+        assert_approx_equals(actual[j], expected[j], tolerance);
+    }
+}
+
+function drawSRGBImageOnP3Canvas(source)
+{
+  var canvas = document.createElement('canvas');
+  canvas.width = 20;
+  canvas.height = 20;
+  var ctx = canvas.getContext('2d',
+      {colorSpace: 'p3', pixelFormat:'float16'});
+  ctx.drawImage(source, 0, 0);
+  var tests = [{x: 5, y: 5, color: p3TransparentRed},
+               {x: 15, y: 5, color: p3TransparentGreen},
+               {x: 5, y: 15, color: p3TransparentBlue},
+               {x: 15, y: 15, color: p3TransparentBlack}];
+  testPixels(ctx, tests);
+}
+
+promise_test(function() {
+  return new Promise((resolve, reject) => {
+    var image = new Image();
+    image.onload = function() {
+      resolve(image);
+    }
+    image.src = 'resources/pattern-semitransparent-srgb.png'
+  }).then(drawSRGBImageOnP3Canvas);
+}, 'Draw SRGB image on a P3 canvas and read back the P3 pixels.');
+
+// TODO(zakerinasab): crbug.com/713867
+// Add at least two more tests to load pattern-semitransparent-p3d65.png and
+// pattern-semitransparent-rec2020.png and draw them on a P3 canvas.
+
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-rec2020.html b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-rec2020.html
new file mode 100644
index 0000000..05c9338c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/canvas-drawImage-rec2020.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script>
+
+// The reference values are generated by calling SkImage::makeColorSpace()
+// in a Skia fiddle. SkColorSpaceXform() may generate different results.
+// Please see: https://fiddle.skia.org/c/94578944d9d52c2b4c2cadda88a4e204
+var rec2020TransparentRed = [ 0.207764, 0.031372, 0.015686, 0.501953 ];
+var rec2020TransparentGreen = [ 0.113708, 0.301758, 0.039215, 0.501953 ];
+var rec2020TransparentBlue = [ 0.023529, 0.015686, 0.293945, 0.501953 ];
+var rec2020TransparentBlack = [ 0.011765, 0.011765, 0.011765, 0.501953 ];
+
+function testPixels(ctx, tests)
+{
+    var actual, expected, tolerance = 0.005;
+    console.log(tests.length);
+    for (var i = 0; i < tests.length; i++) {
+      actual = ctx.getImageData(tests[i].x, tests[i].y, 1, 1).dataUnion;
+      expected = tests[i].color;
+      assert_true(actual.length === expected.length);
+      for (var j = 0; j < actual.length; j++)
+        assert_approx_equals(actual[j], expected[j], tolerance);
+    }
+}
+
+function drawSRGBImageOnRec2020Canvas(source)
+{
+  var canvas = document.createElement('canvas');
+  canvas.width = 20;
+  canvas.height = 20;
+  var ctx = canvas.getContext('2d',
+      {colorSpace: 'rec2020', pixelFormat:'float16'});
+  ctx.drawImage(source, 0, 0);
+  var tests = [{x: 5, y: 5, color: rec2020TransparentRed},
+               {x: 15, y: 5, color: rec2020TransparentGreen},
+               {x: 5, y: 15, color: rec2020TransparentBlue},
+               {x: 15, y: 15, color: rec2020TransparentBlack}];
+  testPixels(ctx, tests);
+}
+
+promise_test(function() {
+  return new Promise((resolve, reject) => {
+    var image = new Image();
+    image.onload = function() {
+      resolve(image);
+    }
+    image.src = 'resources/pattern-semitransparent-srgb.png'
+  }).then(drawSRGBImageOnRec2020Canvas);
+}, 'Draw SRGB image on a Rec2020 canvas and read back the Rec2020 pixels.');
+
+// TODO(zakerinasab): crbug.com/713867
+// Add at least two more tests to load pattern-semitransparent-p3d65.png and
+// pattern-semitransparent-rec2020.png and draw them on a Rec2020 canvas.
+
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-p3d65.png b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-p3d65.png
new file mode 100644
index 0000000..5eb3f6a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-p3d65.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-rec2020.png b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-rec2020.png
new file mode 100644
index 0000000..b64db07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-rec2020.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-srgb.png b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-srgb.png
new file mode 100644
index 0000000..bfbba8b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-semitransparent-srgb.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb-fullcolor.ogv b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb-fullcolor.ogv
new file mode 100644
index 0000000..43a72bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb-fullcolor.ogv
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb-transparent.png b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb-transparent.png
new file mode 100644
index 0000000..bfbba8b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb-transparent.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb.png b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb.png
new file mode 100644
index 0000000..1b5876b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb.svg b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb.svg
new file mode 100644
index 0000000..0517130
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/color_space/fast/canvas/color-space/resources/pattern-srgb.svg
@@ -0,0 +1,6 @@
+<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <rect x="0" y="0" width="10px" height="10px" fill="#9b1b1b"/>
+    <rect x="10" y="0" width="10px" height="10px" fill="#1b9b1b"/>
+    <rect x="0" y="10" width="10px" height="10px" fill="#1b1b9b"/>
+    <rect x="10" y="10" width="10px" height="10px" fill="#1b1b1b"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt
index 5b1fe49..0d3c672 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/css-property-listing-expected.txt
@@ -515,8 +515,6 @@
         grid-auto-columns
         grid-auto-flow
         grid-auto-rows
-        grid-column-gap
-        grid-row-gap
         grid-template-areas
         grid-template-columns
         grid-template-rows
diff --git a/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt
index 8cf1d73..f19ccbe8 100644
--- a/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt
@@ -548,8 +548,6 @@
         grid-auto-columns
         grid-auto-flow
         grid-auto-rows
-        grid-column-gap
-        grid-row-gap
         grid-template-areas
         grid-template-columns
         grid-template-rows
diff --git a/third_party/WebKit/Source/bindings/__init__.py b/third_party/WebKit/Source/bindings/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/WebKit/Source/bindings/__init__.py
+++ /dev/null
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
index d48c4ee..81a5bbaa 100644
--- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -11,110 +11,110 @@
 visibility = [ "//third_party/WebKit/Source/*" ]
 
 bindings_core_generated_union_type_files = [
-  "$bindings_core_v8_output_dir/AddEventListenerOptionsOrBoolean.cpp",
-  "$bindings_core_v8_output_dir/AddEventListenerOptionsOrBoolean.h",
-  "$bindings_core_v8_output_dir/ArrayBufferOrArrayBufferView.cpp",
-  "$bindings_core_v8_output_dir/ArrayBufferOrArrayBufferView.h",
-  "$bindings_core_v8_output_dir/ArrayBufferOrArrayBufferViewOrBlobOrDocumentOrStringOrFormDataOrURLSearchParams.cpp",
-  "$bindings_core_v8_output_dir/ArrayBufferOrArrayBufferViewOrBlobOrDocumentOrStringOrFormDataOrURLSearchParams.h",
-  "$bindings_core_v8_output_dir/ArrayBufferOrArrayBufferViewOrBlobOrUSVString.cpp",
-  "$bindings_core_v8_output_dir/ArrayBufferOrArrayBufferViewOrBlobOrUSVString.h",
-  "$bindings_core_v8_output_dir/BooleanOrByteStringByteStringRecord.cpp",
-  "$bindings_core_v8_output_dir/BooleanOrByteStringByteStringRecord.h",
-  "$bindings_core_v8_output_dir/CSSStyleValueOrCSSStyleValueSequence.cpp",
-  "$bindings_core_v8_output_dir/CSSStyleValueOrCSSStyleValueSequence.h",
-  "$bindings_core_v8_output_dir/CSSStyleValueOrCSSStyleValueSequenceOrString.cpp",
-  "$bindings_core_v8_output_dir/CSSStyleValueOrCSSStyleValueSequenceOrString.h",
-  "$bindings_core_v8_output_dir/DictionarySequenceOrDictionary.cpp",
-  "$bindings_core_v8_output_dir/DictionarySequenceOrDictionary.h",
-  "$bindings_core_v8_output_dir/DoubleOrAutoKeyword.cpp",
-  "$bindings_core_v8_output_dir/DoubleOrAutoKeyword.h",
-  "$bindings_core_v8_output_dir/DoubleOrDoubleSequence.cpp",
-  "$bindings_core_v8_output_dir/DoubleOrDoubleSequence.h",
-  "$bindings_core_v8_output_dir/DoubleOrInternalEnum.cpp",
-  "$bindings_core_v8_output_dir/DoubleOrInternalEnum.h",
-  "$bindings_core_v8_output_dir/DoubleOrScrollTimelineAutoKeyword.cpp",
-  "$bindings_core_v8_output_dir/DoubleOrScrollTimelineAutoKeyword.h",
-  "$bindings_core_v8_output_dir/DoubleOrString.cpp",
-  "$bindings_core_v8_output_dir/DoubleOrString.h",
-  "$bindings_core_v8_output_dir/DoubleOrStringOrStringSequence.cpp",
-  "$bindings_core_v8_output_dir/DoubleOrStringOrStringSequence.h",
-  "$bindings_core_v8_output_dir/EventListenerOptionsOrBoolean.cpp",
-  "$bindings_core_v8_output_dir/EventListenerOptionsOrBoolean.h",
-  "$bindings_core_v8_output_dir/FileOrUSVString.cpp",
-  "$bindings_core_v8_output_dir/FileOrUSVString.h",
-  "$bindings_core_v8_output_dir/FloatOrStringElementRecord.cpp",
-  "$bindings_core_v8_output_dir/FloatOrStringElementRecord.h",
-  "$bindings_core_v8_output_dir/HTMLElementOrLong.cpp",
-  "$bindings_core_v8_output_dir/HTMLElementOrLong.h",
-  "$bindings_core_v8_output_dir/ImageBitmapSource.cpp",
-  "$bindings_core_v8_output_dir/ImageBitmapSource.h",
-  "$bindings_core_v8_output_dir/HTMLOptionElementOrHTMLOptGroupElement.cpp",
-  "$bindings_core_v8_output_dir/HTMLOptionElementOrHTMLOptGroupElement.h",
-  "$bindings_core_v8_output_dir/HTMLScriptElementOrSVGScriptElement.cpp",
-  "$bindings_core_v8_output_dir/HTMLScriptElementOrSVGScriptElement.h",
-  "$bindings_core_v8_output_dir/NodeListOrElement.cpp",
-  "$bindings_core_v8_output_dir/NodeListOrElement.h",
-  "$bindings_core_v8_output_dir/NodeOrString.cpp",
-  "$bindings_core_v8_output_dir/NodeOrString.h",
-  "$bindings_core_v8_output_dir/RadioNodeListOrElement.cpp",
-  "$bindings_core_v8_output_dir/RadioNodeListOrElement.h",
-  "$bindings_core_v8_output_dir/ScrollIntoViewOptionsOrBoolean.cpp",
-  "$bindings_core_v8_output_dir/ScrollIntoViewOptionsOrBoolean.h",
-  "$bindings_core_v8_output_dir/StringOrArrayBuffer.cpp",
-  "$bindings_core_v8_output_dir/StringOrArrayBuffer.h",
-  "$bindings_core_v8_output_dir/StringOrArrayBufferOrArrayBufferView.cpp",
-  "$bindings_core_v8_output_dir/StringOrArrayBufferOrArrayBufferView.h",
-  "$bindings_core_v8_output_dir/StringOrCSSVariableReferenceValue.cpp",
-  "$bindings_core_v8_output_dir/StringOrCSSVariableReferenceValue.h",
-  "$bindings_core_v8_output_dir/StringOrDictionary.cpp",
-  "$bindings_core_v8_output_dir/StringOrDictionary.h",
-  "$bindings_core_v8_output_dir/StringOrFloat.cpp",
-  "$bindings_core_v8_output_dir/StringOrFloat.h",
-  "$bindings_core_v8_output_dir/StringOrUnrestrictedDoubleSequence.cpp",
-  "$bindings_core_v8_output_dir/StringOrUnrestrictedDoubleSequence.h",
-  "$bindings_core_v8_output_dir/USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString.cpp",
-  "$bindings_core_v8_output_dir/USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString.h",
-  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeAnimationOptions.cpp",
-  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeAnimationOptions.h",
-  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeEffectOptions.cpp",
-  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrKeyframeEffectOptions.h",
-  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrString.cpp",
-  "$bindings_core_v8_output_dir/UnrestrictedDoubleOrString.h",
-  "$bindings_core_v8_output_dir/Uint8ClampedArrayOrUint16ArrayOrFloat32Array.cpp",
-  "$bindings_core_v8_output_dir/Uint8ClampedArrayOrUint16ArrayOrFloat32Array.h",
-  "$bindings_core_v8_output_dir/VideoTrackOrAudioTrackOrTextTrack.cpp",
-  "$bindings_core_v8_output_dir/VideoTrackOrAudioTrackOrTextTrack.h",
+  "$bindings_core_v8_output_dir/add_event_listener_options_or_boolean.cc",
+  "$bindings_core_v8_output_dir/add_event_listener_options_or_boolean.h",
+  "$bindings_core_v8_output_dir/array_buffer_or_array_buffer_view.cc",
+  "$bindings_core_v8_output_dir/array_buffer_or_array_buffer_view.h",
+  "$bindings_core_v8_output_dir/array_buffer_or_array_buffer_view_or_blob_or_document_or_string_or_form_data_or_url_search_params.cc",
+  "$bindings_core_v8_output_dir/array_buffer_or_array_buffer_view_or_blob_or_document_or_string_or_form_data_or_url_search_params.h",
+  "$bindings_core_v8_output_dir/array_buffer_or_array_buffer_view_or_blob_or_usv_string.cc",
+  "$bindings_core_v8_output_dir/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h",
+  "$bindings_core_v8_output_dir/boolean_or_byte_string_byte_string_record.cc",
+  "$bindings_core_v8_output_dir/boolean_or_byte_string_byte_string_record.h",
+  "$bindings_core_v8_output_dir/css_style_value_or_css_style_value_sequence.cc",
+  "$bindings_core_v8_output_dir/css_style_value_or_css_style_value_sequence.h",
+  "$bindings_core_v8_output_dir/css_style_value_or_css_style_value_sequence_or_string.cc",
+  "$bindings_core_v8_output_dir/css_style_value_or_css_style_value_sequence_or_string.h",
+  "$bindings_core_v8_output_dir/dictionary_sequence_or_dictionary.cc",
+  "$bindings_core_v8_output_dir/dictionary_sequence_or_dictionary.h",
+  "$bindings_core_v8_output_dir/double_or_auto_keyword.cc",
+  "$bindings_core_v8_output_dir/double_or_auto_keyword.h",
+  "$bindings_core_v8_output_dir/double_or_double_sequence.cc",
+  "$bindings_core_v8_output_dir/double_or_double_sequence.h",
+  "$bindings_core_v8_output_dir/double_or_internal_enum.cc",
+  "$bindings_core_v8_output_dir/double_or_internal_enum.h",
+  "$bindings_core_v8_output_dir/double_or_scroll_timeline_auto_keyword.cc",
+  "$bindings_core_v8_output_dir/double_or_scroll_timeline_auto_keyword.h",
+  "$bindings_core_v8_output_dir/double_or_string.cc",
+  "$bindings_core_v8_output_dir/double_or_string.h",
+  "$bindings_core_v8_output_dir/double_or_string_or_string_sequence.cc",
+  "$bindings_core_v8_output_dir/double_or_string_or_string_sequence.h",
+  "$bindings_core_v8_output_dir/event_listener_options_or_boolean.cc",
+  "$bindings_core_v8_output_dir/event_listener_options_or_boolean.h",
+  "$bindings_core_v8_output_dir/file_or_usv_string.cc",
+  "$bindings_core_v8_output_dir/file_or_usv_string.h",
+  "$bindings_core_v8_output_dir/float_or_string_element_record.cc",
+  "$bindings_core_v8_output_dir/float_or_string_element_record.h",
+  "$bindings_core_v8_output_dir/html_element_or_long.cc",
+  "$bindings_core_v8_output_dir/html_element_or_long.h",
+  "$bindings_core_v8_output_dir/image_bitmap_source.cc",
+  "$bindings_core_v8_output_dir/image_bitmap_source.h",
+  "$bindings_core_v8_output_dir/html_option_element_or_html_opt_group_element.cc",
+  "$bindings_core_v8_output_dir/html_option_element_or_html_opt_group_element.h",
+  "$bindings_core_v8_output_dir/html_script_element_or_svg_script_element.cc",
+  "$bindings_core_v8_output_dir/html_script_element_or_svg_script_element.h",
+  "$bindings_core_v8_output_dir/node_list_or_element.cc",
+  "$bindings_core_v8_output_dir/node_list_or_element.h",
+  "$bindings_core_v8_output_dir/node_or_string.cc",
+  "$bindings_core_v8_output_dir/node_or_string.h",
+  "$bindings_core_v8_output_dir/radio_node_list_or_element.cc",
+  "$bindings_core_v8_output_dir/radio_node_list_or_element.h",
+  "$bindings_core_v8_output_dir/scroll_into_view_options_or_boolean.cc",
+  "$bindings_core_v8_output_dir/scroll_into_view_options_or_boolean.h",
+  "$bindings_core_v8_output_dir/string_or_array_buffer.cc",
+  "$bindings_core_v8_output_dir/string_or_array_buffer.h",
+  "$bindings_core_v8_output_dir/string_or_array_buffer_or_array_buffer_view.cc",
+  "$bindings_core_v8_output_dir/string_or_array_buffer_or_array_buffer_view.h",
+  "$bindings_core_v8_output_dir/string_or_css_variable_reference_value.cc",
+  "$bindings_core_v8_output_dir/string_or_css_variable_reference_value.h",
+  "$bindings_core_v8_output_dir/string_or_dictionary.cc",
+  "$bindings_core_v8_output_dir/string_or_dictionary.h",
+  "$bindings_core_v8_output_dir/string_or_float.cc",
+  "$bindings_core_v8_output_dir/string_or_float.h",
+  "$bindings_core_v8_output_dir/string_or_unrestricted_double_sequence.cc",
+  "$bindings_core_v8_output_dir/string_or_unrestricted_double_sequence.h",
+  "$bindings_core_v8_output_dir/usv_string_sequence_sequence_or_usv_string_usv_string_record_or_usv_string.cc",
+  "$bindings_core_v8_output_dir/usv_string_sequence_sequence_or_usv_string_usv_string_record_or_usv_string.h",
+  "$bindings_core_v8_output_dir/unrestricted_double_or_keyframe_animation_options.cc",
+  "$bindings_core_v8_output_dir/unrestricted_double_or_keyframe_animation_options.h",
+  "$bindings_core_v8_output_dir/unrestricted_double_or_keyframe_effect_options.cc",
+  "$bindings_core_v8_output_dir/unrestricted_double_or_keyframe_effect_options.h",
+  "$bindings_core_v8_output_dir/unrestricted_double_or_string.cc",
+  "$bindings_core_v8_output_dir/unrestricted_double_or_string.h",
+  "$bindings_core_v8_output_dir/uint8_clamped_array_or_uint16_array_or_float32_array.cc",
+  "$bindings_core_v8_output_dir/uint8_clamped_array_or_uint16_array_or_float32_array.h",
+  "$bindings_core_v8_output_dir/video_track_or_audio_track_or_text_track.cc",
+  "$bindings_core_v8_output_dir/video_track_or_audio_track_or_text_track.h",
 ]
 
 generated_core_testing_callback_function_files = [
-  "$bindings_core_v8_output_dir/TestCallback.cpp",
-  "$bindings_core_v8_output_dir/TestCallback.h",
-  "$bindings_core_v8_output_dir/TestEnumCallback.cpp",
-  "$bindings_core_v8_output_dir/TestEnumCallback.h",
-  "$bindings_core_v8_output_dir/TestInterfaceCallback.cpp",
-  "$bindings_core_v8_output_dir/TestInterfaceCallback.h",
-  "$bindings_core_v8_output_dir/TestReceiverObjectCallback.cpp",
-  "$bindings_core_v8_output_dir/TestReceiverObjectCallback.h",
-  "$bindings_core_v8_output_dir/TestSequenceCallback.cpp",
-  "$bindings_core_v8_output_dir/TestSequenceCallback.h",
+  "$bindings_core_v8_output_dir/test_callback.cc",
+  "$bindings_core_v8_output_dir/test_callback.h",
+  "$bindings_core_v8_output_dir/test_enum_callback.cc",
+  "$bindings_core_v8_output_dir/test_enum_callback.h",
+  "$bindings_core_v8_output_dir/test_interface_callback.cc",
+  "$bindings_core_v8_output_dir/test_interface_callback.h",
+  "$bindings_core_v8_output_dir/test_receiver_object_callback.cc",
+  "$bindings_core_v8_output_dir/test_receiver_object_callback.h",
+  "$bindings_core_v8_output_dir/test_sequence_callback.cc",
+  "$bindings_core_v8_output_dir/test_sequence_callback.h",
 ]
 
 generated_core_callback_function_files = [
-  "$bindings_core_v8_output_dir/FunctionStringCallback.cpp",
-  "$bindings_core_v8_output_dir/FunctionStringCallback.h",
-  "$bindings_core_v8_output_dir/IntersectionObserverCallback.cpp",
-  "$bindings_core_v8_output_dir/IntersectionObserverCallback.h",
-  "$bindings_core_v8_output_dir/MojoWatchCallback.cpp",
-  "$bindings_core_v8_output_dir/MojoWatchCallback.h",
-  "$bindings_core_v8_output_dir/MutationCallback.cpp",
-  "$bindings_core_v8_output_dir/MutationCallback.h",
-  "$bindings_core_v8_output_dir/PerformanceObserverCallback.cpp",
-  "$bindings_core_v8_output_dir/PerformanceObserverCallback.h",
-  "$bindings_core_v8_output_dir/ReportingObserverCallback.cpp",
-  "$bindings_core_v8_output_dir/ReportingObserverCallback.h",
-  "$bindings_core_v8_output_dir/ResizeObserverCallback.cpp",
-  "$bindings_core_v8_output_dir/ResizeObserverCallback.h",
+  "$bindings_core_v8_output_dir/function_string_callback.cc",
+  "$bindings_core_v8_output_dir/function_string_callback.h",
+  "$bindings_core_v8_output_dir/intersection_observer_callback.cc",
+  "$bindings_core_v8_output_dir/intersection_observer_callback.h",
+  "$bindings_core_v8_output_dir/mojo_watch_callback.cc",
+  "$bindings_core_v8_output_dir/mojo_watch_callback.h",
+  "$bindings_core_v8_output_dir/mutation_callback.cc",
+  "$bindings_core_v8_output_dir/mutation_callback.h",
+  "$bindings_core_v8_output_dir/performance_observer_callback.cc",
+  "$bindings_core_v8_output_dir/performance_observer_callback.h",
+  "$bindings_core_v8_output_dir/reporting_observer_callback.cc",
+  "$bindings_core_v8_output_dir/reporting_observer_callback.h",
+  "$bindings_core_v8_output_dir/resize_observer_callback.cc",
+  "$bindings_core_v8_output_dir/resize_observer_callback.h",
 ]
 
 generate_conditional_features("bindings_core_conditional_features") {
diff --git a/third_party/WebKit/Source/bindings/core/v8/IDLTypesTest.cpp b/third_party/WebKit/Source/bindings/core/v8/IDLTypesTest.cpp
index a2ef41302..d7cd667 100644
--- a/third_party/WebKit/Source/bindings/core/v8/IDLTypesTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/IDLTypesTest.cpp
@@ -5,8 +5,8 @@
 #include "bindings/core/v8/IDLTypes.h"
 
 #include <type_traits>
-#include "bindings/core/v8/DictionarySequenceOrDictionary.h"
 #include "bindings/core/v8/V8InternalDictionary.h"
+#include "bindings/core/v8/dictionary_sequence_or_dictionary.h"
 #include "core/dom/Element.h"
 #include "platform/heap/Handle.h"
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImplTest.cpp b/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImplTest.cpp
index 8203b29..6087c6a 100644
--- a/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImplTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImplTest.cpp
@@ -7,10 +7,10 @@
 #include <utility>
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/TestSequenceCallback.h"
 #include "bindings/core/v8/ToV8ForCore.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
 #include "bindings/core/v8/V8Internals.h"
+#include "bindings/core/v8/test_sequence_callback.h"
 #include "platform/wtf/Vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V0CustomElementConstructorBuilder.cpp b/third_party/WebKit/Source/bindings/core/v8/V0CustomElementConstructorBuilder.cpp
index 3e7d5c9..7128b56 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V0CustomElementConstructorBuilder.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V0CustomElementConstructorBuilder.cpp
@@ -31,11 +31,11 @@
 #include "bindings/core/v8/V0CustomElementConstructorBuilder.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/StringOrDictionary.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8Document.h"
 #include "bindings/core/v8/V8HTMLElement.h"
 #include "bindings/core/v8/V8SVGElement.h"
+#include "bindings/core/v8/string_or_dictionary.h"
 #include "core/HTMLNames.h"
 #include "core/SVGNames.h"
 #include "core/dom/Document.h"
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8DOMConfiguration.cpp b/third_party/WebKit/Source/bindings/core/v8/V8DOMConfiguration.cpp
index c30afdd..7b98d9d2 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8DOMConfiguration.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8DOMConfiguration.cpp
@@ -255,9 +255,10 @@
         config.cached_property_key);
   }
 
-  // Support [LenientThis] by not specifying the signature.  V8 does not do
-  // the type checking against holder if no signature is specified.  Note that
-  // info.Holder() passed to callbacks will be *unsafe*.
+  // Support [LenientThis] and attributes with Promise types by not specifying
+  // the signature. V8 does not do the type checking against holder if no
+  // signature is specified. Note that info.Holder() passed to callbacks will
+  // be *unsafe*.
   if (config.holder_check_configuration ==
       V8DOMConfiguration::kDoNotCheckHolder)
     signature = v8::Local<v8::Signature>();
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp b/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp
index be1f6466..6f7249c 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8IntersectionObserverDelegate.cpp
@@ -4,9 +4,9 @@
 
 #include "bindings/core/v8/V8IntersectionObserverDelegate.h"
 
-#include "bindings/core/v8/IntersectionObserverCallback.h"
 #include "bindings/core/v8/ScriptController.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/intersection_observer_callback.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/intersection_observer/IntersectionObserver.h"
 #include "platform/bindings/V8PrivateProperty.h"
diff --git a/third_party/WebKit/Source/bindings/core/v8/WindowProxyManager.cpp b/third_party/WebKit/Source/bindings/core/v8/WindowProxyManager.cpp
index 753b12c48..44984b28 100644
--- a/third_party/WebKit/Source/bindings/core/v8/WindowProxyManager.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/WindowProxyManager.cpp
@@ -5,6 +5,7 @@
 #include "bindings/core/v8/WindowProxyManager.h"
 
 #include "platform/bindings/DOMWrapperWorld.h"
+#include "platform/bindings/V8PerIsolateData.h"
 
 namespace blink {
 
@@ -53,10 +54,15 @@
 }
 
 WindowProxyManager::WindowProxyManager(Frame& frame, FrameType frame_type)
-    : isolate_(v8::Isolate::GetCurrent()),
+    : isolate_(V8PerIsolateData::MainThreadIsolate()),
       frame_(&frame),
       frame_type_(frame_type),
-      window_proxy_(CreateWindowProxy(DOMWrapperWorld::MainWorld())) {}
+      window_proxy_(CreateWindowProxy(DOMWrapperWorld::MainWorld())) {
+  // All WindowProxyManagers must be created in the main thread.
+  // Note that |isolate_| is initialized with
+  // V8PerIsolateData::MainThreadIsolate().
+  DCHECK(IsMainThread());
+}
 
 WindowProxy* WindowProxyManager::CreateWindowProxy(DOMWrapperWorld& world) {
   switch (frame_type_) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8PromiseRejectionEventCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8PromiseRejectionEventCustom.cpp
index 3e462d1..424a7c7 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8PromiseRejectionEventCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8PromiseRejectionEventCustom.cpp
@@ -4,6 +4,8 @@
 
 #include "bindings/core/v8/V8PromiseRejectionEvent.h"
 
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/GeneratedCodeHelper.h"
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptValue.h"
 #include "bindings/core/v8/V8BindingForCore.h"
@@ -15,7 +17,22 @@
 void V8PromiseRejectionEvent::promiseAttributeGetterCustom(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
   v8::Isolate* isolate = info.GetIsolate();
-  PromiseRejectionEvent* event = V8PromiseRejectionEvent::toImpl(info.Holder());
+
+  // This attribute returns a Promise.
+  // Per https://heycam.github.io/webidl/#dfn-attribute-getter, all exceptions
+  // must be turned into a Promise rejection. Returning a Promise type requires
+  // us to disable some of V8's type checks, so we have to manually check that
+  // info.Holder() really points to an instance of the type.
+  PromiseRejectionEvent* event =
+      V8PromiseRejectionEvent::toImplWithTypeCheck(isolate, info.Holder());
+  if (!event) {
+    ExceptionState exception_state(isolate, ExceptionState::kGetterContext,
+                                   "PromiseRejectionEvent", "promise");
+    ExceptionToRejectPromiseScope rejectPromiseScope(info, exception_state);
+    exception_state.ThrowTypeError("Illegal invocation");
+    return;
+  }
+
   ScriptPromise promise = event->promise(ScriptState::Current(isolate));
   if (promise.IsEmpty()) {
     V8SetReturnValue(info, v8::Null(isolate));
diff --git a/third_party/WebKit/Source/bindings/modules/v8/generated.gni b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
index 530cecb..f7fe7c3 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/generated.gni
+++ b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
@@ -14,77 +14,77 @@
 
 # TODO(bashi): It would be better to have a way to update this list automatically.
 bindings_modules_generated_union_type_files = [
-  "$bindings_modules_v8_output_dir/ArrayBufferOrArrayBufferViewOrDictionary.cpp",
-  "$bindings_modules_v8_output_dir/ArrayBufferOrArrayBufferViewOrDictionary.h",
-  "$bindings_modules_v8_output_dir/ArrayBufferOrArrayBufferViewOrUSVString.cpp",
-  "$bindings_modules_v8_output_dir/ArrayBufferOrArrayBufferViewOrUSVString.h",
-  "$bindings_modules_v8_output_dir/ArrayBufferViewOrBlobOrStringOrFormData.cpp",
-  "$bindings_modules_v8_output_dir/ArrayBufferViewOrBlobOrStringOrFormData.h",
-  "$bindings_modules_v8_output_dir/AudioContextLatencyCategoryOrDouble.cpp",
-  "$bindings_modules_v8_output_dir/AudioContextLatencyCategoryOrDouble.h",
-  "$bindings_modules_v8_output_dir/BooleanOrConstrainBooleanParameters.cpp",
-  "$bindings_modules_v8_output_dir/BooleanOrConstrainBooleanParameters.h",
-  "$bindings_modules_v8_output_dir/BooleanOrMediaTrackConstraints.cpp",
-  "$bindings_modules_v8_output_dir/BooleanOrMediaTrackConstraints.h",
-  "$bindings_modules_v8_output_dir/ByteStringSequenceSequenceOrByteStringByteStringRecord.cpp",
-  "$bindings_modules_v8_output_dir/ByteStringSequenceSequenceOrByteStringByteStringRecord.h",
-  "$bindings_modules_v8_output_dir/CanvasImageSource.cpp",
-  "$bindings_modules_v8_output_dir/CanvasImageSource.h",
-  "$bindings_modules_v8_output_dir/ClientOrServiceWorkerOrMessagePort.cpp",
-  "$bindings_modules_v8_output_dir/ClientOrServiceWorkerOrMessagePort.h",
-  "$bindings_modules_v8_output_dir/DecodeErrorCallback.cpp",
-  "$bindings_modules_v8_output_dir/DecodeErrorCallback.h",
-  "$bindings_modules_v8_output_dir/DecodeSuccessCallback.cpp",
-  "$bindings_modules_v8_output_dir/DecodeSuccessCallback.h",
-  "$bindings_modules_v8_output_dir/DictionaryOrString.cpp",
-  "$bindings_modules_v8_output_dir/DictionaryOrString.h",
-  "$bindings_modules_v8_output_dir/DoubleOrConstrainDoubleRange.cpp",
-  "$bindings_modules_v8_output_dir/DoubleOrConstrainDoubleRange.h",
-  "$bindings_modules_v8_output_dir/Float32ArrayOrFloat64ArrayOrDOMMatrix.cpp",
-  "$bindings_modules_v8_output_dir/Float32ArrayOrFloat64ArrayOrDOMMatrix.h",
-  "$bindings_modules_v8_output_dir/FormDataOrURLSearchParams.cpp",
-  "$bindings_modules_v8_output_dir/FormDataOrURLSearchParams.h",
-  "$bindings_modules_v8_output_dir/HTMLCanvasElementOrOffscreenCanvas.cpp",
-  "$bindings_modules_v8_output_dir/HTMLCanvasElementOrOffscreenCanvas.h",
-  "$bindings_modules_v8_output_dir/LongOrConstrainLongRange.cpp",
-  "$bindings_modules_v8_output_dir/LongOrConstrainLongRange.h",
-  "$bindings_modules_v8_output_dir/OffscreenRenderingContext.cpp",
-  "$bindings_modules_v8_output_dir/OffscreenRenderingContext.h",
-  "$bindings_modules_v8_output_dir/PasswordCredentialDataOrHTMLFormElement.cpp",
-  "$bindings_modules_v8_output_dir/PasswordCredentialDataOrHTMLFormElement.h",
-  "$bindings_modules_v8_output_dir/Point2DSequenceOrConstrainPoint2DParameters.cpp",
-  "$bindings_modules_v8_output_dir/Point2DSequenceOrConstrainPoint2DParameters.h",
-  "$bindings_modules_v8_output_dir/RTCIceCandidateInitOrRTCIceCandidate.cpp",
-  "$bindings_modules_v8_output_dir/RTCIceCandidateInitOrRTCIceCandidate.h",
-  "$bindings_modules_v8_output_dir/RenderingContext.cpp",
-  "$bindings_modules_v8_output_dir/RenderingContext.h",
-  "$bindings_modules_v8_output_dir/RequestOrUSVString.cpp",
-  "$bindings_modules_v8_output_dir/RequestOrUSVString.h",
-  "$bindings_modules_v8_output_dir/RequestOrUSVStringOrRequestOrUSVStringSequence.cpp",
-  "$bindings_modules_v8_output_dir/RequestOrUSVStringOrRequestOrUSVStringSequence.h",
-  "$bindings_modules_v8_output_dir/StringOrArrayBufferOrNFCMessage.cpp",
-  "$bindings_modules_v8_output_dir/StringOrArrayBufferOrNFCMessage.h",
-  "$bindings_modules_v8_output_dir/StringOrCanvasGradientOrCanvasPattern.cpp",
-  "$bindings_modules_v8_output_dir/StringOrCanvasGradientOrCanvasPattern.h",
-  "$bindings_modules_v8_output_dir/StringOrStringSequence.cpp",
-  "$bindings_modules_v8_output_dir/StringOrStringSequence.h",
-  "$bindings_modules_v8_output_dir/StringOrStringSequenceOrConstrainDOMStringParameters.cpp",
-  "$bindings_modules_v8_output_dir/StringOrStringSequenceOrConstrainDOMStringParameters.h",
-  "$bindings_modules_v8_output_dir/StringOrUnsignedLong.cpp",
-  "$bindings_modules_v8_output_dir/StringOrUnsignedLong.h",
-  "$bindings_modules_v8_output_dir/UnsignedLongOrUnsignedLongSequence.cpp",
-  "$bindings_modules_v8_output_dir/UnsignedLongOrUnsignedLongSequence.h",
+  "$bindings_modules_v8_output_dir/array_buffer_or_array_buffer_view_or_dictionary.cc",
+  "$bindings_modules_v8_output_dir/array_buffer_or_array_buffer_view_or_dictionary.h",
+  "$bindings_modules_v8_output_dir/array_buffer_or_array_buffer_view_or_usv_string.cc",
+  "$bindings_modules_v8_output_dir/array_buffer_or_array_buffer_view_or_usv_string.h",
+  "$bindings_modules_v8_output_dir/array_buffer_view_or_blob_or_string_or_form_data.cc",
+  "$bindings_modules_v8_output_dir/array_buffer_view_or_blob_or_string_or_form_data.h",
+  "$bindings_modules_v8_output_dir/audio_context_latency_category_or_double.cc",
+  "$bindings_modules_v8_output_dir/audio_context_latency_category_or_double.h",
+  "$bindings_modules_v8_output_dir/boolean_or_constrain_boolean_parameters.cc",
+  "$bindings_modules_v8_output_dir/boolean_or_constrain_boolean_parameters.h",
+  "$bindings_modules_v8_output_dir/boolean_or_media_track_constraints.cc",
+  "$bindings_modules_v8_output_dir/boolean_or_media_track_constraints.h",
+  "$bindings_modules_v8_output_dir/byte_string_sequence_sequence_or_byte_string_byte_string_record.cc",
+  "$bindings_modules_v8_output_dir/byte_string_sequence_sequence_or_byte_string_byte_string_record.h",
+  "$bindings_modules_v8_output_dir/canvas_image_source.cc",
+  "$bindings_modules_v8_output_dir/canvas_image_source.h",
+  "$bindings_modules_v8_output_dir/client_or_service_worker_or_message_port.cc",
+  "$bindings_modules_v8_output_dir/client_or_service_worker_or_message_port.h",
+  "$bindings_modules_v8_output_dir/decode_error_callback.cc",
+  "$bindings_modules_v8_output_dir/decode_error_callback.h",
+  "$bindings_modules_v8_output_dir/decode_success_callback.cc",
+  "$bindings_modules_v8_output_dir/decode_success_callback.h",
+  "$bindings_modules_v8_output_dir/dictionary_or_string.cc",
+  "$bindings_modules_v8_output_dir/dictionary_or_string.h",
+  "$bindings_modules_v8_output_dir/double_or_constrain_double_range.cc",
+  "$bindings_modules_v8_output_dir/double_or_constrain_double_range.h",
+  "$bindings_modules_v8_output_dir/float32_array_or_float64_array_or_dom_matrix.cc",
+  "$bindings_modules_v8_output_dir/float32_array_or_float64_array_or_dom_matrix.h",
+  "$bindings_modules_v8_output_dir/form_data_or_url_search_params.cc",
+  "$bindings_modules_v8_output_dir/form_data_or_url_search_params.h",
+  "$bindings_modules_v8_output_dir/html_canvas_element_or_offscreen_canvas.cc",
+  "$bindings_modules_v8_output_dir/html_canvas_element_or_offscreen_canvas.h",
+  "$bindings_modules_v8_output_dir/long_or_constrain_long_range.cc",
+  "$bindings_modules_v8_output_dir/long_or_constrain_long_range.h",
+  "$bindings_modules_v8_output_dir/offscreen_rendering_context.cc",
+  "$bindings_modules_v8_output_dir/offscreen_rendering_context.h",
+  "$bindings_modules_v8_output_dir/password_credential_data_or_html_form_element.cc",
+  "$bindings_modules_v8_output_dir/password_credential_data_or_html_form_element.h",
+  "$bindings_modules_v8_output_dir/point_2d_sequence_or_constrain_point_2d_parameters.cc",
+  "$bindings_modules_v8_output_dir/point_2d_sequence_or_constrain_point_2d_parameters.h",
+  "$bindings_modules_v8_output_dir/rtc_ice_candidate_init_or_rtc_ice_candidate.cc",
+  "$bindings_modules_v8_output_dir/rtc_ice_candidate_init_or_rtc_ice_candidate.h",
+  "$bindings_modules_v8_output_dir/rendering_context.cc",
+  "$bindings_modules_v8_output_dir/rendering_context.h",
+  "$bindings_modules_v8_output_dir/request_or_usv_string.cc",
+  "$bindings_modules_v8_output_dir/request_or_usv_string.h",
+  "$bindings_modules_v8_output_dir/request_or_usv_string_or_request_or_usv_string_sequence.cc",
+  "$bindings_modules_v8_output_dir/request_or_usv_string_or_request_or_usv_string_sequence.h",
+  "$bindings_modules_v8_output_dir/string_or_array_buffer_or_nfc_message.cc",
+  "$bindings_modules_v8_output_dir/string_or_array_buffer_or_nfc_message.h",
+  "$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.cc",
+  "$bindings_modules_v8_output_dir/string_or_canvas_gradient_or_canvas_pattern.h",
+  "$bindings_modules_v8_output_dir/string_or_string_sequence.cc",
+  "$bindings_modules_v8_output_dir/string_or_string_sequence.h",
+  "$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.cc",
+  "$bindings_modules_v8_output_dir/string_or_string_sequence_or_constrain_dom_string_parameters.h",
+  "$bindings_modules_v8_output_dir/string_or_unsigned_long.cc",
+  "$bindings_modules_v8_output_dir/string_or_unsigned_long.h",
+  "$bindings_modules_v8_output_dir/unsigned_long_or_unsigned_long_sequence.cc",
+  "$bindings_modules_v8_output_dir/unsigned_long_or_unsigned_long_sequence.h",
 ]
 
 generated_modules_callback_function_files = [
-  "$bindings_modules_v8_output_dir/DatabaseCallback.cpp",
-  "$bindings_modules_v8_output_dir/DatabaseCallback.h",
-  "$bindings_modules_v8_output_dir/IDBObserverCallback.cpp",
-  "$bindings_modules_v8_output_dir/IDBObserverCallback.h",
-  "$bindings_modules_v8_output_dir/MediaSessionActionHandler.cpp",
-  "$bindings_modules_v8_output_dir/MediaSessionActionHandler.h",
-  "$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.cpp",
-  "$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.h",
+  "$bindings_modules_v8_output_dir/database_callback.cc",
+  "$bindings_modules_v8_output_dir/database_callback.h",
+  "$bindings_modules_v8_output_dir/idb_observer_callback.cc",
+  "$bindings_modules_v8_output_dir/idb_observer_callback.h",
+  "$bindings_modules_v8_output_dir/media_session_action_handler.cc",
+  "$bindings_modules_v8_output_dir/media_session_action_handler.h",
+  "$bindings_modules_v8_output_dir/remote_playback_availability_callback.cc",
+  "$bindings_modules_v8_output_dir/remote_playback_availability_callback.h",
 ]
 
 bindings_generated_v8_context_snapshot_external_references_file =
diff --git a/third_party/WebKit/Source/bindings/scripts/__init__.py b/third_party/WebKit/Source/bindings/scripts/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/WebKit/Source/bindings/scripts/__init__.py
+++ /dev/null
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py b/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
index 67e145f0..f22f720 100644
--- a/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
@@ -59,7 +59,7 @@
 import v8_types
 import v8_union
 from v8_utilities import cpp_name
-from utilities import idl_filename_to_component, is_testing_target, shorten_union_name
+from utilities import idl_filename_to_component, is_testing_target, shorten_union_name, to_snake_case
 
 
 # Make sure extension is .py, not .pyc or .pyo, so doesn't depend on caching
@@ -318,12 +318,12 @@
             template_context['header_includes'])
         template_context['code_generator'] = self.generator_name
         template_context['exported'] = self.info_provider.specifier_for_export
-        name = shorten_union_name(union_type)
-        template_context['this_include_header_name'] = name
+        snake_base_name = to_snake_case(shorten_union_name(union_type))
+        template_context['this_include_header_name'] = snake_base_name
         header_text = render_template(header_template, template_context)
         cpp_text = render_template(cpp_template, template_context)
-        header_path = posixpath.join(self.output_dir, '%s.h' % name)
-        cpp_path = posixpath.join(self.output_dir, '%s.cpp' % name)
+        header_path = posixpath.join(self.output_dir, '%s.h' % snake_base_name)
+        cpp_path = posixpath.join(self.output_dir, '%s.cc' % snake_base_name)
         return (
             (header_path, header_text),
             (cpp_path, cpp_text),
@@ -377,8 +377,9 @@
         template_context['code_generator'] = MODULE_PYNAME
         header_text = render_template(header_template, template_context)
         cpp_text = render_template(cpp_template, template_context)
-        header_path = posixpath.join(self.output_dir, '%s.h' % callback_function.name)
-        cpp_path = posixpath.join(self.output_dir, '%s.cpp' % callback_function.name)
+        snake_base_name = to_snake_case(callback_function.name)
+        header_path = posixpath.join(self.output_dir, '%s.h' % snake_base_name)
+        cpp_path = posixpath.join(self.output_dir, '%s.cc' % snake_base_name)
         return (
             (header_path, header_text),
             (cpp_path, cpp_text),
diff --git a/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py b/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py
index 45e1907..5fa475d8 100755
--- a/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py
+++ b/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py
@@ -8,8 +8,6 @@
 # compute_interfaces_info_overall.py, and writes out the code which adds
 # bindings for origin-trial-enabled features at runtime.
 
-# pylint: disable=W0403
-
 import optparse
 import os
 import posixpath
diff --git a/third_party/WebKit/Source/bindings/scripts/idl_compiler.py b/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
index bbd2afa..c1c07df 100755
--- a/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
+++ b/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# pylint: disable=W0403
-
 """Compile an .idl file to Blink V8 bindings (.h and .cpp files).
 
 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
diff --git a/third_party/WebKit/Source/bindings/scripts/utilities.py b/third_party/WebKit/Source/bindings/scripts/utilities.py
index 3fd13c2..9b54872a 100644
--- a/third_party/WebKit/Source/bindings/scripts/utilities.py
+++ b/third_party/WebKit/Source/bindings/scripts/utilities.py
@@ -13,6 +13,11 @@
 import shlex
 import string
 import subprocess
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..',
+                             'third_party', 'blink', 'tools'))
+from blinkpy.common.name_style_converter import NameStyleConverter
 
 
 KNOWN_COMPONENTS = frozenset(['core', 'modules'])
@@ -123,7 +128,7 @@
         return self._component_info['union_types']
 
     def include_path_for_union_types(self, union_type):
-        name = shorten_union_name(union_type)
+        name = to_snake_case(shorten_union_name(union_type))
         return 'bindings/core/v8/%s.h' % name
 
     @property
@@ -178,8 +183,8 @@
                                  in self._component_info_core['union_types']]
         name = shorten_union_name(union_type)
         if union_type.name in core_union_type_names:
-            return 'bindings/core/v8/%s.h' % name
-        return 'bindings/modules/v8/%s.h' % name
+            return 'bindings/core/v8/%s.h' % to_snake_case(name)
+        return 'bindings/modules/v8/%s.h' % to_snake_case(name)
 
     @property
     def callback_functions(self):
@@ -450,6 +455,12 @@
     return name
 
 
+def to_snake_case(name):
+    if name.lower() == name:
+        return name
+    return NameStyleConverter(name).to_snake_case()
+
+
 def format_remove_duplicates(text, patterns):
     """Removes duplicated line-basis patterns.
 
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_attributes.py b/third_party/WebKit/Source/bindings/scripts/v8_attributes.py
index 9a21120..1da911ca 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_attributes.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_attributes.py
@@ -138,6 +138,7 @@
         'has_cross_origin_setter': has_extended_attribute_value(attribute, 'CrossOrigin', 'Setter'),
         'has_custom_getter': has_custom_getter(attribute),
         'has_custom_setter': has_custom_setter(attribute),
+        'has_promise_type': idl_type.name == 'Promise',
         'has_setter': has_setter(interface, attribute),
         'idl_type': str(idl_type),
         'is_cached_accessor': is_cached_accessor,
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py b/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py
index 3bdf0c3..4fe23fb 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_callback_function.py
@@ -7,8 +7,8 @@
 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
 """
 
-from v8_globals import includes  # pylint: disable=W0403
-import v8_utilities  # pylint: disable=W0403
+from utilities import to_snake_case
+from v8_globals import includes
 
 CALLBACK_FUNCTION_H_INCLUDES = frozenset([
     'bindings/core/v8/NativeValueTraits.h',
@@ -49,6 +49,7 @@
         'forward_declarations': sorted(forward_declarations(callback_function)),
         'header_includes': sorted(CALLBACK_FUNCTION_H_INCLUDES),
         'idl_type': idl_type_str,
+        'this_include_header_name': to_snake_case(callback_function.name),
     }
 
     if idl_type_str != 'void':
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_dictionary.py b/third_party/WebKit/Source/bindings/scripts/v8_dictionary.py
index 5dab0dc..884c7288 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_dictionary.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_dictionary.py
@@ -8,6 +8,7 @@
 
 import operator
 from idl_types import IdlType
+from utilities import to_snake_case
 from v8_globals import includes
 import v8_types
 import v8_utilities
@@ -121,7 +122,7 @@
         return cpp_default_value, v8_default_value
 
     cpp_default_value, v8_default_value = default_values()
-    cpp_name = v8_utilities.to_snake_case(v8_utilities.cpp_name(member))
+    cpp_name = to_snake_case(v8_utilities.cpp_name(member))
     getter_name = getter_name_for_dictionary_member(member)
     is_deprecated_dictionary = unwrapped_idl_type.name == 'Dictionary'
 
@@ -200,7 +201,7 @@
 def member_impl_context(member, interfaces_info, header_includes,
                         header_forward_decls):
     idl_type = unwrap_nullable_if_needed(member.idl_type)
-    cpp_name = v8_utilities.to_snake_case(v8_utilities.cpp_name(member))
+    cpp_name = to_snake_case(v8_utilities.cpp_name(member))
 
     nullable_indicator_name = None
     if not idl_type.cpp_type_has_null_value:
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_types.py b/third_party/WebKit/Source/bindings/scripts/v8_types.py
index d3d09e8f..63cb21c7 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_types.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_types.py
@@ -47,6 +47,7 @@
 from idl_types import IdlType
 from idl_types import IdlTypeBase
 from idl_types import IdlUnionType
+from utilities import to_snake_case
 import v8_attributes  # for IdlType.constructor_type_name
 from v8_globals import includes
 from v8_utilities import extended_attribute_value_contains
@@ -412,7 +413,7 @@
         return set()
     if idl_type.is_callback_function:
         component = IdlType.callback_functions[base_idl_type]['component_dir']
-        return set(['bindings/%s/v8/%s.h' % (component, base_idl_type)])
+        return set(['bindings/%s/v8/%s.h' % (component, to_snake_case(base_idl_type))])
     if base_idl_type not in component_dir:
         return set()
     return set(['bindings/%s/v8/V8%s.h' % (component_dir[base_idl_type],
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_union.py b/third_party/WebKit/Source/bindings/scripts/v8_union.py
index 468a927..5fef903 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_union.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_union.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from utilities import to_snake_case
 import v8_types
 import v8_utilities
 
@@ -153,7 +154,7 @@
     if member.is_nullable:
         member = member.inner_type
     return {
-        'cpp_name': v8_utilities.to_snake_case(v8_utilities.cpp_name(member)),
+        'cpp_name': to_snake_case(v8_utilities.cpp_name(member)),
         'cpp_type': member.cpp_type_args(used_in_cpp_sequence=True),
         'cpp_local_type': member.cpp_type,
         'cpp_value_to_v8_value': member.cpp_value_to_v8_value(
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_utilities.py b/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
index 423112c0..39e91533 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
@@ -40,10 +40,6 @@
 from idl_definitions import Exposure, IdlInterface, IdlAttribute
 from v8_globals import includes
 
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '..',
-                             'third_party', 'blink', 'tools'))
-from blinkpy.common.name_style_converter import NameStyleConverter
-
 ACRONYMS = [
     'CSSOM',  # must come *before* CSS to match full acronym
     'CSS',
@@ -119,10 +115,6 @@
     return name[0].lower() + name[1:]
 
 
-def to_snake_case(name):
-    return NameStyleConverter(name).to_snake_case()
-
-
 def runtime_enabled_function(name):
     """Returns a function call of a runtime enabled feature."""
     return 'RuntimeEnabledFeatures::%sEnabled()' % name
diff --git a/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl
index 4ec6d03..8791e9c 100644
--- a/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/attributes.cpp.tmpl
@@ -19,6 +19,20 @@
   // Make sure that info.Holder() really points to an instance if [LenientThis].
   if (!{{v8_class}}::hasInstance(info.Holder(), info.GetIsolate()))
     return; // Return silently because of [LenientThis].
+  {% elif attribute.has_promise_type %}
+  // This attribute returns a Promise.
+  // Per https://heycam.github.io/webidl/#dfn-attribute-getter, all exceptions
+  // must be turned into a Promise rejection.
+  {{define_exception_state}}
+  ExceptionToRejectPromiseScope rejectPromiseScope(info, exceptionState);
+
+  // Returning a Promise type requires us to disable some of V8's type checks,
+  // so we have to manually check that info.Holder() really points to an
+  // instance of the type.
+  if (!{{v8_class}}::hasInstance(info.Holder(), info.GetIsolate())) {
+    exceptionState.ThrowTypeError("Illegal invocation");
+    return;
+  }
   {% endif %}
 
   {% if not attribute.is_static or attribute.is_save_same_object %}
@@ -516,7 +530,8 @@
     (attribute.cached_accessor_name if attribute.is_cached_accessor
      else 'NoCachedAccessor') %}
 {% set holder_check = 'V8DOMConfiguration::kDoNotCheckHolder'
-    if attribute.is_lenient_this else 'V8DOMConfiguration::kCheckHolder' %}
+    if attribute.is_lenient_this or attribute.has_promise_type
+    else 'V8DOMConfiguration::kCheckHolder' %}
 {% if attribute.is_per_world_bindings %}
   {% set getter_callback_for_main_world = '%sForMainWorld' % getter_callback %}
   {% set setter_callback_for_main_world =
diff --git a/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
index 664bbf1..adab1f0d 100644
--- a/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
@@ -3,7 +3,7 @@
 
 {% include 'copyright_block.txt' %}
 
-#include "{{cpp_class}}.h"
+#include "{{this_include_header_name}}.h"
 
 {% for filename in cpp_includes %}
 #include "{{filename}}"
diff --git a/third_party/WebKit/Source/bindings/tests/idls/core/TestAttributeGetters.idl b/third_party/WebKit/Source/bindings/tests/idls/core/TestAttributeGetters.idl
new file mode 100644
index 0000000..0bb8eb4
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/idls/core/TestAttributeGetters.idl
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://heycam.github.io/webidl/#dfn-attribute-getter
+
+// Attribute getters must behave differently based on whether [LenientThis] has
+// been specified or whether the attribute's type is Promise<T>.
+// All attributes below are marked readonly because we are only interested in
+// the behavior of attribute getters.
+
+interface TestAttributeGetters {
+    // [LenientThis] causes some V8 type checks to be bypassed; they are done
+    // on the Blink side instead and access exceptions just return undefined.
+    [LenientThis] readonly attribute long lenientThisLongAttribute;
+
+    // Promise types must turn exceptions into promise rejections.
+    readonly attribute Promise<DOMString> stringPromiseAttribute;
+
+    // Mixing both should cause [LenientThis] to return without raising an
+    // exception if type checking fails.
+    [LenientThis] readonly attribute Promise<DOMString> lenientThisStringPromiseAttribute;
+
+    // [RaisesException] also creates an ExceptionState instance. Make sure it
+    // is not declared twice.
+    [RaisesException] readonly attribute Promise<short> raisesExceptionShortPromiseAttribute;
+
+    // Regular attribute with no special rules.
+    readonly attribute float floatAttribute;
+};
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.cpp
deleted file mode 100644
index bf8a745..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "AnyCallbackFunctionOptionalAnyArg.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ScriptValue.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-AnyCallbackFunctionOptionalAnyArg* AnyCallbackFunctionOptionalAnyArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new AnyCallbackFunctionOptionalAnyArg(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-AnyCallbackFunctionOptionalAnyArg::AnyCallbackFunctionOptionalAnyArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(AnyCallbackFunctionOptionalAnyArg) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool AnyCallbackFunctionOptionalAnyArg::call(ScriptWrappable* scriptWrappable, ScriptValue optionalAnyArg, ScriptValue& returnValue) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_optionalAnyArg = optionalAnyArg.V8Value();
-  v8::Local<v8::Value> argv[] = { v8_optionalAnyArg };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    1,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  ScriptValue cppValue = ScriptValue(ScriptState::Current(script_state_->GetIsolate()), v8ReturnValue);
-  returnValue = cppValue;
-  return true;
-}
-
-AnyCallbackFunctionOptionalAnyArg* NativeValueTraits<AnyCallbackFunctionOptionalAnyArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  AnyCallbackFunctionOptionalAnyArg* nativeValue = AnyCallbackFunctionOptionalAnyArg::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "AnyCallbackFunctionOptionalAnyArg"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ArrayBufferOrArrayBufferViewOrDictionary.cpp b/third_party/WebKit/Source/bindings/tests/results/core/ArrayBufferOrArrayBufferViewOrDictionary.cpp
deleted file mode 100644
index c988c24e..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/ArrayBufferOrArrayBufferViewOrDictionary.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "ArrayBufferOrArrayBufferViewOrDictionary.h"
-
-#include "bindings/core/v8/Dictionary.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8ArrayBuffer.h"
-
-namespace blink {
-
-ArrayBufferOrArrayBufferViewOrDictionary::ArrayBufferOrArrayBufferViewOrDictionary() : type_(SpecificTypeNone) {}
-
-TestArrayBuffer* ArrayBufferOrArrayBufferViewOrDictionary::getAsArrayBuffer() const {
-  DCHECK(isArrayBuffer());
-  return array_buffer_;
-}
-
-void ArrayBufferOrArrayBufferViewOrDictionary::setArrayBuffer(TestArrayBuffer* value) {
-  DCHECK(isNull());
-  array_buffer_ = value;
-  type_ = SpecificTypeArrayBuffer;
-}
-
-ArrayBufferOrArrayBufferViewOrDictionary ArrayBufferOrArrayBufferViewOrDictionary::fromArrayBuffer(TestArrayBuffer* value) {
-  ArrayBufferOrArrayBufferViewOrDictionary container;
-  container.setArrayBuffer(value);
-  return container;
-}
-
-NotShared<TestArrayBufferView> ArrayBufferOrArrayBufferViewOrDictionary::getAsArrayBufferView() const {
-  DCHECK(isArrayBufferView());
-  return array_buffer_view_;
-}
-
-void ArrayBufferOrArrayBufferViewOrDictionary::setArrayBufferView(NotShared<TestArrayBufferView> value) {
-  DCHECK(isNull());
-  array_buffer_view_ = Member<TestArrayBufferView>(value.View());
-  type_ = SpecificTypeArrayBufferView;
-}
-
-ArrayBufferOrArrayBufferViewOrDictionary ArrayBufferOrArrayBufferViewOrDictionary::fromArrayBufferView(NotShared<TestArrayBufferView> value) {
-  ArrayBufferOrArrayBufferViewOrDictionary container;
-  container.setArrayBufferView(value);
-  return container;
-}
-
-Dictionary ArrayBufferOrArrayBufferViewOrDictionary::getAsDictionary() const {
-  DCHECK(isDictionary());
-  return dictionary_;
-}
-
-void ArrayBufferOrArrayBufferViewOrDictionary::setDictionary(Dictionary value) {
-  DCHECK(isNull());
-  dictionary_ = value;
-  type_ = SpecificTypeDictionary;
-}
-
-ArrayBufferOrArrayBufferViewOrDictionary ArrayBufferOrArrayBufferViewOrDictionary::fromDictionary(Dictionary value) {
-  ArrayBufferOrArrayBufferViewOrDictionary container;
-  container.setDictionary(value);
-  return container;
-}
-
-ArrayBufferOrArrayBufferViewOrDictionary::ArrayBufferOrArrayBufferViewOrDictionary(const ArrayBufferOrArrayBufferViewOrDictionary&) = default;
-ArrayBufferOrArrayBufferViewOrDictionary::~ArrayBufferOrArrayBufferViewOrDictionary() = default;
-ArrayBufferOrArrayBufferViewOrDictionary& ArrayBufferOrArrayBufferViewOrDictionary::operator=(const ArrayBufferOrArrayBufferViewOrDictionary&) = default;
-
-DEFINE_TRACE(ArrayBufferOrArrayBufferViewOrDictionary) {
-  visitor->Trace(array_buffer_);
-  visitor->Trace(array_buffer_view_);
-}
-
-void V8ArrayBufferOrArrayBufferViewOrDictionary::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ArrayBufferOrArrayBufferViewOrDictionary& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsArrayBuffer()) {
-    TestArrayBuffer* cppValue = V8ArrayBuffer::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setArrayBuffer(cppValue);
-    return;
-  }
-
-  if (v8Value->IsArrayBufferView()) {
-    NotShared<TestArrayBufferView> cppValue = ToNotShared<NotShared<TestArrayBufferView>>(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setArrayBufferView(cppValue);
-    return;
-  }
-
-  if (IsUndefinedOrNull(v8Value) || v8Value->IsObject()) {
-    Dictionary cppValue = NativeValueTraits<Dictionary>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDictionary(cppValue);
-    return;
-  }
-
-  exceptionState.ThrowTypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView or Dictionary)'");
-}
-
-v8::Local<v8::Value> ToV8(const ArrayBufferOrArrayBufferViewOrDictionary& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeNone:
-      return v8::Null(isolate);
-    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeArrayBuffer:
-      return ToV8(impl.getAsArrayBuffer(), creationContext, isolate);
-    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeArrayBufferView:
-      return ToV8(impl.getAsArrayBufferView(), creationContext, isolate);
-    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeDictionary:
-      return impl.getAsDictionary().V8Value();
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-ArrayBufferOrArrayBufferViewOrDictionary NativeValueTraits<ArrayBufferOrArrayBufferViewOrDictionary>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  ArrayBufferOrArrayBufferViewOrDictionary impl;
-  V8ArrayBufferOrArrayBufferViewOrDictionary::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrElementSequence.cpp b/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrElementSequence.cpp
deleted file mode 100644
index 3b19c8a..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrElementSequence.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "BooleanOrElementSequence.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8Element.h"
-#include "core/animation/ElementAnimation.h"
-#include "core/dom/ChildNode.h"
-#include "core/dom/NonDocumentTypeChildNode.h"
-#include "core/dom/ParentNode.h"
-#include "core/fullscreen/ElementFullscreen.h"
-
-namespace blink {
-
-BooleanOrElementSequence::BooleanOrElementSequence() : type_(SpecificTypeNone) {}
-
-bool BooleanOrElementSequence::getAsBoolean() const {
-  DCHECK(isBoolean());
-  return boolean_;
-}
-
-void BooleanOrElementSequence::setBoolean(bool value) {
-  DCHECK(isNull());
-  boolean_ = value;
-  type_ = SpecificTypeBoolean;
-}
-
-BooleanOrElementSequence BooleanOrElementSequence::fromBoolean(bool value) {
-  BooleanOrElementSequence container;
-  container.setBoolean(value);
-  return container;
-}
-
-const HeapVector<Member<Element>>& BooleanOrElementSequence::getAsElementSequence() const {
-  DCHECK(isElementSequence());
-  return element_sequence_;
-}
-
-void BooleanOrElementSequence::setElementSequence(const HeapVector<Member<Element>>& value) {
-  DCHECK(isNull());
-  element_sequence_ = value;
-  type_ = SpecificTypeElementSequence;
-}
-
-BooleanOrElementSequence BooleanOrElementSequence::fromElementSequence(const HeapVector<Member<Element>>& value) {
-  BooleanOrElementSequence container;
-  container.setElementSequence(value);
-  return container;
-}
-
-BooleanOrElementSequence::BooleanOrElementSequence(const BooleanOrElementSequence&) = default;
-BooleanOrElementSequence::~BooleanOrElementSequence() = default;
-BooleanOrElementSequence& BooleanOrElementSequence::operator=(const BooleanOrElementSequence&) = default;
-
-DEFINE_TRACE(BooleanOrElementSequence) {
-  visitor->Trace(element_sequence_);
-}
-
-void V8BooleanOrElementSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrElementSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    HeapVector<Member<Element>> cppValue = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setElementSequence(cppValue);
-    return;
-  }
-
-  if (v8Value->IsBoolean()) {
-    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
-    return;
-  }
-
-  {
-    impl.setBoolean(v8Value->BooleanValue());
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const BooleanOrElementSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case BooleanOrElementSequence::SpecificTypeNone:
-      return v8::Null(isolate);
-    case BooleanOrElementSequence::SpecificTypeBoolean:
-      return v8::Boolean::New(isolate, impl.getAsBoolean());
-    case BooleanOrElementSequence::SpecificTypeElementSequence:
-      return ToV8(impl.getAsElementSequence(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-BooleanOrElementSequence NativeValueTraits<BooleanOrElementSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  BooleanOrElementSequence impl;
-  V8BooleanOrElementSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrStringOrUnrestrictedDouble.cpp b/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrStringOrUnrestrictedDouble.cpp
deleted file mode 100644
index 85e6025..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrStringOrUnrestrictedDouble.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "BooleanOrStringOrUnrestrictedDouble.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-BooleanOrStringOrUnrestrictedDouble::BooleanOrStringOrUnrestrictedDouble() : type_(SpecificTypeNone) {}
-
-bool BooleanOrStringOrUnrestrictedDouble::getAsBoolean() const {
-  DCHECK(isBoolean());
-  return boolean_;
-}
-
-void BooleanOrStringOrUnrestrictedDouble::setBoolean(bool value) {
-  DCHECK(isNull());
-  boolean_ = value;
-  type_ = SpecificTypeBoolean;
-}
-
-BooleanOrStringOrUnrestrictedDouble BooleanOrStringOrUnrestrictedDouble::fromBoolean(bool value) {
-  BooleanOrStringOrUnrestrictedDouble container;
-  container.setBoolean(value);
-  return container;
-}
-
-const String& BooleanOrStringOrUnrestrictedDouble::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void BooleanOrStringOrUnrestrictedDouble::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-BooleanOrStringOrUnrestrictedDouble BooleanOrStringOrUnrestrictedDouble::fromString(const String& value) {
-  BooleanOrStringOrUnrestrictedDouble container;
-  container.setString(value);
-  return container;
-}
-
-double BooleanOrStringOrUnrestrictedDouble::getAsUnrestrictedDouble() const {
-  DCHECK(isUnrestrictedDouble());
-  return unrestricted_double_;
-}
-
-void BooleanOrStringOrUnrestrictedDouble::setUnrestrictedDouble(double value) {
-  DCHECK(isNull());
-  unrestricted_double_ = value;
-  type_ = SpecificTypeUnrestrictedDouble;
-}
-
-BooleanOrStringOrUnrestrictedDouble BooleanOrStringOrUnrestrictedDouble::fromUnrestrictedDouble(double value) {
-  BooleanOrStringOrUnrestrictedDouble container;
-  container.setUnrestrictedDouble(value);
-  return container;
-}
-
-BooleanOrStringOrUnrestrictedDouble::BooleanOrStringOrUnrestrictedDouble(const BooleanOrStringOrUnrestrictedDouble&) = default;
-BooleanOrStringOrUnrestrictedDouble::~BooleanOrStringOrUnrestrictedDouble() = default;
-BooleanOrStringOrUnrestrictedDouble& BooleanOrStringOrUnrestrictedDouble::operator=(const BooleanOrStringOrUnrestrictedDouble&) = default;
-
-DEFINE_TRACE(BooleanOrStringOrUnrestrictedDouble) {
-}
-
-void V8BooleanOrStringOrUnrestrictedDouble::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrStringOrUnrestrictedDouble& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsBoolean()) {
-    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    double cppValue = NativeValueTraits<IDLUnrestrictedDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setUnrestrictedDouble(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const BooleanOrStringOrUnrestrictedDouble& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeNone:
-      return v8::Null(isolate);
-    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeBoolean:
-      return v8::Boolean::New(isolate, impl.getAsBoolean());
-    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeUnrestrictedDouble:
-      return v8::Number::New(isolate, impl.getAsUnrestrictedDouble());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-BooleanOrStringOrUnrestrictedDouble NativeValueTraits<BooleanOrStringOrUnrestrictedDouble>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  BooleanOrStringOrUnrestrictedDouble impl;
-  V8BooleanOrStringOrUnrestrictedDouble::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrTestCallbackInterface.cpp b/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrTestCallbackInterface.cpp
deleted file mode 100644
index b3786ce..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrTestCallbackInterface.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "BooleanOrTestCallbackInterface.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8TestCallbackInterface.h"
-
-namespace blink {
-
-BooleanOrTestCallbackInterface::BooleanOrTestCallbackInterface() : type_(SpecificTypeNone) {}
-
-bool BooleanOrTestCallbackInterface::getAsBoolean() const {
-  DCHECK(isBoolean());
-  return boolean_;
-}
-
-void BooleanOrTestCallbackInterface::setBoolean(bool value) {
-  DCHECK(isNull());
-  boolean_ = value;
-  type_ = SpecificTypeBoolean;
-}
-
-BooleanOrTestCallbackInterface BooleanOrTestCallbackInterface::fromBoolean(bool value) {
-  BooleanOrTestCallbackInterface container;
-  container.setBoolean(value);
-  return container;
-}
-
-TestCallbackInterface* BooleanOrTestCallbackInterface::getAsTestCallbackInterface() const {
-  DCHECK(isTestCallbackInterface());
-  return test_callback_interface_;
-}
-
-void BooleanOrTestCallbackInterface::setTestCallbackInterface(TestCallbackInterface* value) {
-  DCHECK(isNull());
-  test_callback_interface_ = value;
-  type_ = SpecificTypeTestCallbackInterface;
-}
-
-BooleanOrTestCallbackInterface BooleanOrTestCallbackInterface::fromTestCallbackInterface(TestCallbackInterface* value) {
-  BooleanOrTestCallbackInterface container;
-  container.setTestCallbackInterface(value);
-  return container;
-}
-
-BooleanOrTestCallbackInterface::BooleanOrTestCallbackInterface(const BooleanOrTestCallbackInterface&) = default;
-BooleanOrTestCallbackInterface::~BooleanOrTestCallbackInterface() = default;
-BooleanOrTestCallbackInterface& BooleanOrTestCallbackInterface::operator=(const BooleanOrTestCallbackInterface&) = default;
-
-DEFINE_TRACE(BooleanOrTestCallbackInterface) {
-  visitor->Trace(test_callback_interface_);
-}
-
-void V8BooleanOrTestCallbackInterface::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrTestCallbackInterface& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8TestCallbackInterface::hasInstance(v8Value, isolate)) {
-    TestCallbackInterface* cppValue = V8TestCallbackInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setTestCallbackInterface(cppValue);
-    return;
-  }
-
-  if (v8Value->IsBoolean()) {
-    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
-    return;
-  }
-
-  {
-    impl.setBoolean(v8Value->BooleanValue());
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const BooleanOrTestCallbackInterface& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case BooleanOrTestCallbackInterface::SpecificTypeNone:
-      return v8::Null(isolate);
-    case BooleanOrTestCallbackInterface::SpecificTypeBoolean:
-      return v8::Boolean::New(isolate, impl.getAsBoolean());
-    case BooleanOrTestCallbackInterface::SpecificTypeTestCallbackInterface:
-      return ToV8(impl.getAsTestCallbackInterface(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-BooleanOrTestCallbackInterface NativeValueTraits<BooleanOrTestCallbackInterface>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  BooleanOrTestCallbackInterface impl;
-  V8BooleanOrTestCallbackInterface::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ByteStringOrNodeList.cpp b/third_party/WebKit/Source/bindings/tests/results/core/ByteStringOrNodeList.cpp
deleted file mode 100644
index 9f8c58c0..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/ByteStringOrNodeList.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "ByteStringOrNodeList.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8NodeList.h"
-#include "core/dom/NameNodeList.h"
-#include "core/dom/NodeList.h"
-#include "core/dom/StaticNodeList.h"
-#include "core/html/LabelsNodeList.h"
-
-namespace blink {
-
-ByteStringOrNodeList::ByteStringOrNodeList() : type_(SpecificTypeNone) {}
-
-const String& ByteStringOrNodeList::getAsByteString() const {
-  DCHECK(isByteString());
-  return byte_string_;
-}
-
-void ByteStringOrNodeList::setByteString(const String& value) {
-  DCHECK(isNull());
-  byte_string_ = value;
-  type_ = SpecificTypeByteString;
-}
-
-ByteStringOrNodeList ByteStringOrNodeList::fromByteString(const String& value) {
-  ByteStringOrNodeList container;
-  container.setByteString(value);
-  return container;
-}
-
-NodeList* ByteStringOrNodeList::getAsNodeList() const {
-  DCHECK(isNodeList());
-  return node_list_;
-}
-
-void ByteStringOrNodeList::setNodeList(NodeList* value) {
-  DCHECK(isNull());
-  node_list_ = value;
-  type_ = SpecificTypeNodeList;
-}
-
-ByteStringOrNodeList ByteStringOrNodeList::fromNodeList(NodeList* value) {
-  ByteStringOrNodeList container;
-  container.setNodeList(value);
-  return container;
-}
-
-ByteStringOrNodeList::ByteStringOrNodeList(const ByteStringOrNodeList&) = default;
-ByteStringOrNodeList::~ByteStringOrNodeList() = default;
-ByteStringOrNodeList& ByteStringOrNodeList::operator=(const ByteStringOrNodeList&) = default;
-
-DEFINE_TRACE(ByteStringOrNodeList) {
-  visitor->Trace(node_list_);
-}
-
-void V8ByteStringOrNodeList::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ByteStringOrNodeList& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8NodeList::hasInstance(v8Value, isolate)) {
-    NodeList* cppValue = V8NodeList::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setNodeList(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = NativeValueTraits<IDLByteString>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setByteString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const ByteStringOrNodeList& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case ByteStringOrNodeList::SpecificTypeNone:
-      return v8::Null(isolate);
-    case ByteStringOrNodeList::SpecificTypeByteString:
-      return V8String(isolate, impl.getAsByteString());
-    case ByteStringOrNodeList::SpecificTypeNodeList:
-      return ToV8(impl.getAsNodeList(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-ByteStringOrNodeList NativeValueTraits<ByteStringOrNodeList>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  ByteStringOrNodeList impl;
-  V8ByteStringOrNodeList::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ByteStringSequenceSequenceOrByteStringByteStringRecord.cpp b/third_party/WebKit/Source/bindings/tests/results/core/ByteStringSequenceSequenceOrByteStringByteStringRecord.cpp
deleted file mode 100644
index 58f434766..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/ByteStringSequenceSequenceOrByteStringByteStringRecord.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "ByteStringSequenceSequenceOrByteStringByteStringRecord.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-ByteStringSequenceSequenceOrByteStringByteStringRecord::ByteStringSequenceSequenceOrByteStringByteStringRecord() : type_(SpecificTypeNone) {}
-
-const Vector<std::pair<String, String>>& ByteStringSequenceSequenceOrByteStringByteStringRecord::getAsByteStringByteStringRecord() const {
-  DCHECK(isByteStringByteStringRecord());
-  return byte_string_byte_string_record_;
-}
-
-void ByteStringSequenceSequenceOrByteStringByteStringRecord::setByteStringByteStringRecord(const Vector<std::pair<String, String>>& value) {
-  DCHECK(isNull());
-  byte_string_byte_string_record_ = value;
-  type_ = SpecificTypeByteStringByteStringRecord;
-}
-
-ByteStringSequenceSequenceOrByteStringByteStringRecord ByteStringSequenceSequenceOrByteStringByteStringRecord::fromByteStringByteStringRecord(const Vector<std::pair<String, String>>& value) {
-  ByteStringSequenceSequenceOrByteStringByteStringRecord container;
-  container.setByteStringByteStringRecord(value);
-  return container;
-}
-
-const Vector<Vector<String>>& ByteStringSequenceSequenceOrByteStringByteStringRecord::getAsByteStringSequenceSequence() const {
-  DCHECK(isByteStringSequenceSequence());
-  return byte_string_sequence_sequence_;
-}
-
-void ByteStringSequenceSequenceOrByteStringByteStringRecord::setByteStringSequenceSequence(const Vector<Vector<String>>& value) {
-  DCHECK(isNull());
-  byte_string_sequence_sequence_ = value;
-  type_ = SpecificTypeByteStringSequenceSequence;
-}
-
-ByteStringSequenceSequenceOrByteStringByteStringRecord ByteStringSequenceSequenceOrByteStringByteStringRecord::fromByteStringSequenceSequence(const Vector<Vector<String>>& value) {
-  ByteStringSequenceSequenceOrByteStringByteStringRecord container;
-  container.setByteStringSequenceSequence(value);
-  return container;
-}
-
-ByteStringSequenceSequenceOrByteStringByteStringRecord::ByteStringSequenceSequenceOrByteStringByteStringRecord(const ByteStringSequenceSequenceOrByteStringByteStringRecord&) = default;
-ByteStringSequenceSequenceOrByteStringByteStringRecord::~ByteStringSequenceSequenceOrByteStringByteStringRecord() = default;
-ByteStringSequenceSequenceOrByteStringByteStringRecord& ByteStringSequenceSequenceOrByteStringByteStringRecord::operator=(const ByteStringSequenceSequenceOrByteStringByteStringRecord&) = default;
-
-DEFINE_TRACE(ByteStringSequenceSequenceOrByteStringByteStringRecord) {
-}
-
-void V8ByteStringSequenceSequenceOrByteStringByteStringRecord::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ByteStringSequenceSequenceOrByteStringByteStringRecord& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    Vector<Vector<String>> cppValue = NativeValueTraits<IDLSequence<IDLSequence<IDLByteString>>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setByteStringSequenceSequence(cppValue);
-    return;
-  }
-
-  if (v8Value->IsObject()) {
-    Vector<std::pair<String, String>> cppValue = NativeValueTraits<IDLRecord<IDLByteString, IDLByteString>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setByteStringByteStringRecord(cppValue);
-    return;
-  }
-
-  exceptionState.ThrowTypeError("The provided value is not of type '(sequence<sequence<ByteString>> or record<ByteString, ByteString>)'");
-}
-
-v8::Local<v8::Value> ToV8(const ByteStringSequenceSequenceOrByteStringByteStringRecord& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case ByteStringSequenceSequenceOrByteStringByteStringRecord::SpecificTypeNone:
-      return v8::Null(isolate);
-    case ByteStringSequenceSequenceOrByteStringByteStringRecord::SpecificTypeByteStringByteStringRecord:
-      return ToV8(impl.getAsByteStringByteStringRecord(), creationContext, isolate);
-    case ByteStringSequenceSequenceOrByteStringByteStringRecord::SpecificTypeByteStringSequenceSequence:
-      return ToV8(impl.getAsByteStringSequenceSequence(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-ByteStringSequenceSequenceOrByteStringByteStringRecord NativeValueTraits<ByteStringSequenceSequenceOrByteStringByteStringRecord>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  ByteStringSequenceSequenceOrByteStringByteStringRecord impl;
-  V8ByteStringSequenceSequenceOrByteStringByteStringRecord::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrLongOrBooleanSequence.cpp b/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrLongOrBooleanSequence.cpp
deleted file mode 100644
index bbcb99b..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrLongOrBooleanSequence.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "DoubleOrLongOrBooleanSequence.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/LongOrBoolean.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-DoubleOrLongOrBooleanSequence::DoubleOrLongOrBooleanSequence() : type_(SpecificTypeNone) {}
-
-double DoubleOrLongOrBooleanSequence::getAsDouble() const {
-  DCHECK(isDouble());
-  return double_;
-}
-
-void DoubleOrLongOrBooleanSequence::setDouble(double value) {
-  DCHECK(isNull());
-  double_ = value;
-  type_ = SpecificTypeDouble;
-}
-
-DoubleOrLongOrBooleanSequence DoubleOrLongOrBooleanSequence::fromDouble(double value) {
-  DoubleOrLongOrBooleanSequence container;
-  container.setDouble(value);
-  return container;
-}
-
-const HeapVector<LongOrBoolean>& DoubleOrLongOrBooleanSequence::getAsLongOrBooleanSequence() const {
-  DCHECK(isLongOrBooleanSequence());
-  return long_or_boolean_sequence_;
-}
-
-void DoubleOrLongOrBooleanSequence::setLongOrBooleanSequence(const HeapVector<LongOrBoolean>& value) {
-  DCHECK(isNull());
-  long_or_boolean_sequence_ = value;
-  type_ = SpecificTypeLongOrBooleanSequence;
-}
-
-DoubleOrLongOrBooleanSequence DoubleOrLongOrBooleanSequence::fromLongOrBooleanSequence(const HeapVector<LongOrBoolean>& value) {
-  DoubleOrLongOrBooleanSequence container;
-  container.setLongOrBooleanSequence(value);
-  return container;
-}
-
-DoubleOrLongOrBooleanSequence::DoubleOrLongOrBooleanSequence(const DoubleOrLongOrBooleanSequence&) = default;
-DoubleOrLongOrBooleanSequence::~DoubleOrLongOrBooleanSequence() = default;
-DoubleOrLongOrBooleanSequence& DoubleOrLongOrBooleanSequence::operator=(const DoubleOrLongOrBooleanSequence&) = default;
-
-DEFINE_TRACE(DoubleOrLongOrBooleanSequence) {
-  visitor->Trace(long_or_boolean_sequence_);
-}
-
-void V8DoubleOrLongOrBooleanSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, DoubleOrLongOrBooleanSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    HeapVector<LongOrBoolean> cppValue = NativeValueTraits<IDLSequence<LongOrBoolean>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setLongOrBooleanSequence(cppValue);
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDouble(cppValue);
-    return;
-  }
-
-  {
-    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDouble(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const DoubleOrLongOrBooleanSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case DoubleOrLongOrBooleanSequence::SpecificTypeNone:
-      return v8::Null(isolate);
-    case DoubleOrLongOrBooleanSequence::SpecificTypeDouble:
-      return v8::Number::New(isolate, impl.getAsDouble());
-    case DoubleOrLongOrBooleanSequence::SpecificTypeLongOrBooleanSequence:
-      return ToV8(impl.getAsLongOrBooleanSequence(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-DoubleOrLongOrBooleanSequence NativeValueTraits<DoubleOrLongOrBooleanSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  DoubleOrLongOrBooleanSequence impl;
-  V8DoubleOrLongOrBooleanSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrString.cpp b/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrString.cpp
deleted file mode 100644
index 8b9bbd2..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrString.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "DoubleOrString.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-DoubleOrString::DoubleOrString() : type_(SpecificTypeNone) {}
-
-double DoubleOrString::getAsDouble() const {
-  DCHECK(isDouble());
-  return double_;
-}
-
-void DoubleOrString::setDouble(double value) {
-  DCHECK(isNull());
-  double_ = value;
-  type_ = SpecificTypeDouble;
-}
-
-DoubleOrString DoubleOrString::fromDouble(double value) {
-  DoubleOrString container;
-  container.setDouble(value);
-  return container;
-}
-
-const String& DoubleOrString::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void DoubleOrString::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-DoubleOrString DoubleOrString::fromString(const String& value) {
-  DoubleOrString container;
-  container.setString(value);
-  return container;
-}
-
-DoubleOrString::DoubleOrString(const DoubleOrString&) = default;
-DoubleOrString::~DoubleOrString() = default;
-DoubleOrString& DoubleOrString::operator=(const DoubleOrString&) = default;
-
-DEFINE_TRACE(DoubleOrString) {
-}
-
-void V8DoubleOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, DoubleOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsNumber()) {
-    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDouble(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const DoubleOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case DoubleOrString::SpecificTypeNone:
-      return v8::Null(isolate);
-    case DoubleOrString::SpecificTypeDouble:
-      return v8::Number::New(isolate, impl.getAsDouble());
-    case DoubleOrString::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-DoubleOrString NativeValueTraits<DoubleOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  DoubleOrString impl;
-  V8DoubleOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrStringOrDoubleOrStringSequence.cpp b/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrStringOrDoubleOrStringSequence.cpp
deleted file mode 100644
index 69bb6f7..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrStringOrDoubleOrStringSequence.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "DoubleOrStringOrDoubleOrStringSequence.h"
-
-#include "bindings/core/v8/DoubleOrString.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-DoubleOrStringOrDoubleOrStringSequence::DoubleOrStringOrDoubleOrStringSequence() : type_(SpecificTypeNone) {}
-
-double DoubleOrStringOrDoubleOrStringSequence::getAsDouble() const {
-  DCHECK(isDouble());
-  return double_;
-}
-
-void DoubleOrStringOrDoubleOrStringSequence::setDouble(double value) {
-  DCHECK(isNull());
-  double_ = value;
-  type_ = SpecificTypeDouble;
-}
-
-DoubleOrStringOrDoubleOrStringSequence DoubleOrStringOrDoubleOrStringSequence::fromDouble(double value) {
-  DoubleOrStringOrDoubleOrStringSequence container;
-  container.setDouble(value);
-  return container;
-}
-
-const HeapVector<DoubleOrString>& DoubleOrStringOrDoubleOrStringSequence::getAsDoubleOrStringSequence() const {
-  DCHECK(isDoubleOrStringSequence());
-  return double_or_string_sequence_;
-}
-
-void DoubleOrStringOrDoubleOrStringSequence::setDoubleOrStringSequence(const HeapVector<DoubleOrString>& value) {
-  DCHECK(isNull());
-  double_or_string_sequence_ = value;
-  type_ = SpecificTypeDoubleOrStringSequence;
-}
-
-DoubleOrStringOrDoubleOrStringSequence DoubleOrStringOrDoubleOrStringSequence::fromDoubleOrStringSequence(const HeapVector<DoubleOrString>& value) {
-  DoubleOrStringOrDoubleOrStringSequence container;
-  container.setDoubleOrStringSequence(value);
-  return container;
-}
-
-const String& DoubleOrStringOrDoubleOrStringSequence::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void DoubleOrStringOrDoubleOrStringSequence::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-DoubleOrStringOrDoubleOrStringSequence DoubleOrStringOrDoubleOrStringSequence::fromString(const String& value) {
-  DoubleOrStringOrDoubleOrStringSequence container;
-  container.setString(value);
-  return container;
-}
-
-DoubleOrStringOrDoubleOrStringSequence::DoubleOrStringOrDoubleOrStringSequence(const DoubleOrStringOrDoubleOrStringSequence&) = default;
-DoubleOrStringOrDoubleOrStringSequence::~DoubleOrStringOrDoubleOrStringSequence() = default;
-DoubleOrStringOrDoubleOrStringSequence& DoubleOrStringOrDoubleOrStringSequence::operator=(const DoubleOrStringOrDoubleOrStringSequence&) = default;
-
-DEFINE_TRACE(DoubleOrStringOrDoubleOrStringSequence) {
-  visitor->Trace(double_or_string_sequence_);
-}
-
-void V8DoubleOrStringOrDoubleOrStringSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, DoubleOrStringOrDoubleOrStringSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    HeapVector<DoubleOrString> cppValue = NativeValueTraits<IDLSequence<DoubleOrString>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDoubleOrStringSequence(cppValue);
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDouble(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const DoubleOrStringOrDoubleOrStringSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeNone:
-      return v8::Null(isolate);
-    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeDouble:
-      return v8::Number::New(isolate, impl.getAsDouble());
-    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeDoubleOrStringSequence:
-      return ToV8(impl.getAsDoubleOrStringSequence(), creationContext, isolate);
-    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-DoubleOrStringOrDoubleOrStringSequence NativeValueTraits<DoubleOrStringOrDoubleOrStringSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  DoubleOrStringOrDoubleOrStringSequence impl;
-  V8DoubleOrStringOrDoubleOrStringSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ElementSequenceOrByteStringDoubleOrStringRecord.cpp b/third_party/WebKit/Source/bindings/tests/results/core/ElementSequenceOrByteStringDoubleOrStringRecord.cpp
deleted file mode 100644
index 41a823a..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/ElementSequenceOrByteStringDoubleOrStringRecord.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "ElementSequenceOrByteStringDoubleOrStringRecord.h"
-
-#include "bindings/core/v8/DoubleOrString.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8Element.h"
-#include "core/animation/ElementAnimation.h"
-#include "core/dom/ChildNode.h"
-#include "core/dom/NonDocumentTypeChildNode.h"
-#include "core/dom/ParentNode.h"
-#include "core/fullscreen/ElementFullscreen.h"
-
-namespace blink {
-
-ElementSequenceOrByteStringDoubleOrStringRecord::ElementSequenceOrByteStringDoubleOrStringRecord() : type_(SpecificTypeNone) {}
-
-const HeapVector<std::pair<String, DoubleOrString>>& ElementSequenceOrByteStringDoubleOrStringRecord::getAsByteStringDoubleOrStringRecord() const {
-  DCHECK(isByteStringDoubleOrStringRecord());
-  return byte_string_double_or_string_record_;
-}
-
-void ElementSequenceOrByteStringDoubleOrStringRecord::setByteStringDoubleOrStringRecord(const HeapVector<std::pair<String, DoubleOrString>>& value) {
-  DCHECK(isNull());
-  byte_string_double_or_string_record_ = value;
-  type_ = SpecificTypeByteStringDoubleOrStringRecord;
-}
-
-ElementSequenceOrByteStringDoubleOrStringRecord ElementSequenceOrByteStringDoubleOrStringRecord::fromByteStringDoubleOrStringRecord(const HeapVector<std::pair<String, DoubleOrString>>& value) {
-  ElementSequenceOrByteStringDoubleOrStringRecord container;
-  container.setByteStringDoubleOrStringRecord(value);
-  return container;
-}
-
-const HeapVector<Member<Element>>& ElementSequenceOrByteStringDoubleOrStringRecord::getAsElementSequence() const {
-  DCHECK(isElementSequence());
-  return element_sequence_;
-}
-
-void ElementSequenceOrByteStringDoubleOrStringRecord::setElementSequence(const HeapVector<Member<Element>>& value) {
-  DCHECK(isNull());
-  element_sequence_ = value;
-  type_ = SpecificTypeElementSequence;
-}
-
-ElementSequenceOrByteStringDoubleOrStringRecord ElementSequenceOrByteStringDoubleOrStringRecord::fromElementSequence(const HeapVector<Member<Element>>& value) {
-  ElementSequenceOrByteStringDoubleOrStringRecord container;
-  container.setElementSequence(value);
-  return container;
-}
-
-ElementSequenceOrByteStringDoubleOrStringRecord::ElementSequenceOrByteStringDoubleOrStringRecord(const ElementSequenceOrByteStringDoubleOrStringRecord&) = default;
-ElementSequenceOrByteStringDoubleOrStringRecord::~ElementSequenceOrByteStringDoubleOrStringRecord() = default;
-ElementSequenceOrByteStringDoubleOrStringRecord& ElementSequenceOrByteStringDoubleOrStringRecord::operator=(const ElementSequenceOrByteStringDoubleOrStringRecord&) = default;
-
-DEFINE_TRACE(ElementSequenceOrByteStringDoubleOrStringRecord) {
-  visitor->Trace(byte_string_double_or_string_record_);
-  visitor->Trace(element_sequence_);
-}
-
-void V8ElementSequenceOrByteStringDoubleOrStringRecord::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ElementSequenceOrByteStringDoubleOrStringRecord& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    HeapVector<Member<Element>> cppValue = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setElementSequence(cppValue);
-    return;
-  }
-
-  if (v8Value->IsObject()) {
-    HeapVector<std::pair<String, DoubleOrString>> cppValue = NativeValueTraits<IDLRecord<IDLByteString, DoubleOrString>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setByteStringDoubleOrStringRecord(cppValue);
-    return;
-  }
-
-  exceptionState.ThrowTypeError("The provided value is not of type '(sequence<Element> or record<ByteString, (double or DOMString)>)'");
-}
-
-v8::Local<v8::Value> ToV8(const ElementSequenceOrByteStringDoubleOrStringRecord& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case ElementSequenceOrByteStringDoubleOrStringRecord::SpecificTypeNone:
-      return v8::Null(isolate);
-    case ElementSequenceOrByteStringDoubleOrStringRecord::SpecificTypeByteStringDoubleOrStringRecord:
-      return ToV8(impl.getAsByteStringDoubleOrStringRecord(), creationContext, isolate);
-    case ElementSequenceOrByteStringDoubleOrStringRecord::SpecificTypeElementSequence:
-      return ToV8(impl.getAsElementSequence(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-ElementSequenceOrByteStringDoubleOrStringRecord NativeValueTraits<ElementSequenceOrByteStringDoubleOrStringRecord>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  ElementSequenceOrByteStringDoubleOrStringRecord impl;
-  V8ElementSequenceOrByteStringDoubleOrStringRecord::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/FloatOrBoolean.cpp b/third_party/WebKit/Source/bindings/tests/results/core/FloatOrBoolean.cpp
deleted file mode 100644
index 5af3764a..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/FloatOrBoolean.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "FloatOrBoolean.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-FloatOrBoolean::FloatOrBoolean() : type_(SpecificTypeNone) {}
-
-bool FloatOrBoolean::getAsBoolean() const {
-  DCHECK(isBoolean());
-  return boolean_;
-}
-
-void FloatOrBoolean::setBoolean(bool value) {
-  DCHECK(isNull());
-  boolean_ = value;
-  type_ = SpecificTypeBoolean;
-}
-
-FloatOrBoolean FloatOrBoolean::fromBoolean(bool value) {
-  FloatOrBoolean container;
-  container.setBoolean(value);
-  return container;
-}
-
-float FloatOrBoolean::getAsFloat() const {
-  DCHECK(isFloat());
-  return float_;
-}
-
-void FloatOrBoolean::setFloat(float value) {
-  DCHECK(isNull());
-  float_ = value;
-  type_ = SpecificTypeFloat;
-}
-
-FloatOrBoolean FloatOrBoolean::fromFloat(float value) {
-  FloatOrBoolean container;
-  container.setFloat(value);
-  return container;
-}
-
-FloatOrBoolean::FloatOrBoolean(const FloatOrBoolean&) = default;
-FloatOrBoolean::~FloatOrBoolean() = default;
-FloatOrBoolean& FloatOrBoolean::operator=(const FloatOrBoolean&) = default;
-
-DEFINE_TRACE(FloatOrBoolean) {
-}
-
-void V8FloatOrBoolean::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, FloatOrBoolean& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsBoolean()) {
-    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    float cppValue = NativeValueTraits<IDLFloat>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setFloat(cppValue);
-    return;
-  }
-
-  {
-    float cppValue = NativeValueTraits<IDLFloat>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setFloat(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const FloatOrBoolean& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case FloatOrBoolean::SpecificTypeNone:
-      return v8::Null(isolate);
-    case FloatOrBoolean::SpecificTypeBoolean:
-      return v8::Boolean::New(isolate, impl.getAsBoolean());
-    case FloatOrBoolean::SpecificTypeFloat:
-      return v8::Number::New(isolate, impl.getAsFloat());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-FloatOrBoolean NativeValueTraits<FloatOrBoolean>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  FloatOrBoolean impl;
-  V8FloatOrBoolean::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.cpp b/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.cpp
deleted file mode 100644
index 74c5c27..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "LongCallbackFunction.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-LongCallbackFunction* LongCallbackFunction::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new LongCallbackFunction(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-LongCallbackFunction::LongCallbackFunction(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(LongCallbackFunction) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool LongCallbackFunction::call(ScriptWrappable* scriptWrappable, int32_t num1, int32_t num2, int32_t& returnValue) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_num1 = v8::Integer::New(script_state_->GetIsolate(), num1);
-  v8::Local<v8::Value> v8_num2 = v8::Integer::New(script_state_->GetIsolate(), num2);
-  v8::Local<v8::Value> argv[] = { v8_num1, v8_num2 };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    2,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(script_state_->GetIsolate(), v8ReturnValue, exceptionState, kNormalConversion);
-  if (exceptionState.HadException())
-    return false;
-  returnValue = cppValue;
-  return true;
-}
-
-LongCallbackFunction* NativeValueTraits<LongCallbackFunction>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  LongCallbackFunction* nativeValue = LongCallbackFunction::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "LongCallbackFunction"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongOrBoolean.cpp b/third_party/WebKit/Source/bindings/tests/results/core/LongOrBoolean.cpp
deleted file mode 100644
index 19a45e5a..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/LongOrBoolean.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "LongOrBoolean.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-LongOrBoolean::LongOrBoolean() : type_(SpecificTypeNone) {}
-
-bool LongOrBoolean::getAsBoolean() const {
-  DCHECK(isBoolean());
-  return boolean_;
-}
-
-void LongOrBoolean::setBoolean(bool value) {
-  DCHECK(isNull());
-  boolean_ = value;
-  type_ = SpecificTypeBoolean;
-}
-
-LongOrBoolean LongOrBoolean::fromBoolean(bool value) {
-  LongOrBoolean container;
-  container.setBoolean(value);
-  return container;
-}
-
-int32_t LongOrBoolean::getAsLong() const {
-  DCHECK(isLong());
-  return long_;
-}
-
-void LongOrBoolean::setLong(int32_t value) {
-  DCHECK(isNull());
-  long_ = value;
-  type_ = SpecificTypeLong;
-}
-
-LongOrBoolean LongOrBoolean::fromLong(int32_t value) {
-  LongOrBoolean container;
-  container.setLong(value);
-  return container;
-}
-
-LongOrBoolean::LongOrBoolean(const LongOrBoolean&) = default;
-LongOrBoolean::~LongOrBoolean() = default;
-LongOrBoolean& LongOrBoolean::operator=(const LongOrBoolean&) = default;
-
-DEFINE_TRACE(LongOrBoolean) {
-}
-
-void V8LongOrBoolean::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, LongOrBoolean& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsBoolean()) {
-    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setLong(cppValue);
-    return;
-  }
-
-  {
-    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setLong(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const LongOrBoolean& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case LongOrBoolean::SpecificTypeNone:
-      return v8::Null(isolate);
-    case LongOrBoolean::SpecificTypeBoolean:
-      return v8::Boolean::New(isolate, impl.getAsBoolean());
-    case LongOrBoolean::SpecificTypeLong:
-      return v8::Integer::New(isolate, impl.getAsLong());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-LongOrBoolean NativeValueTraits<LongOrBoolean>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  LongOrBoolean impl;
-  V8LongOrBoolean::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongOrTestDictionary.cpp b/third_party/WebKit/Source/bindings/tests/results/core/LongOrTestDictionary.cpp
deleted file mode 100644
index 54242f6..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/LongOrTestDictionary.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "LongOrTestDictionary.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-LongOrTestDictionary::LongOrTestDictionary() : type_(SpecificTypeNone) {}
-
-int32_t LongOrTestDictionary::getAsLong() const {
-  DCHECK(isLong());
-  return long_;
-}
-
-void LongOrTestDictionary::setLong(int32_t value) {
-  DCHECK(isNull());
-  long_ = value;
-  type_ = SpecificTypeLong;
-}
-
-LongOrTestDictionary LongOrTestDictionary::fromLong(int32_t value) {
-  LongOrTestDictionary container;
-  container.setLong(value);
-  return container;
-}
-
-const TestDictionary& LongOrTestDictionary::getAsTestDictionary() const {
-  DCHECK(isTestDictionary());
-  return test_dictionary_;
-}
-
-void LongOrTestDictionary::setTestDictionary(const TestDictionary& value) {
-  DCHECK(isNull());
-  test_dictionary_ = value;
-  type_ = SpecificTypeTestDictionary;
-}
-
-LongOrTestDictionary LongOrTestDictionary::fromTestDictionary(const TestDictionary& value) {
-  LongOrTestDictionary container;
-  container.setTestDictionary(value);
-  return container;
-}
-
-LongOrTestDictionary::LongOrTestDictionary(const LongOrTestDictionary&) = default;
-LongOrTestDictionary::~LongOrTestDictionary() = default;
-LongOrTestDictionary& LongOrTestDictionary::operator=(const LongOrTestDictionary&) = default;
-
-DEFINE_TRACE(LongOrTestDictionary) {
-  visitor->Trace(test_dictionary_);
-}
-
-void V8LongOrTestDictionary::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, LongOrTestDictionary& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (IsUndefinedOrNull(v8Value)) {
-    TestDictionary cppValue;
-    V8TestDictionary::toImpl(isolate, v8Value, cppValue, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setTestDictionary(cppValue);
-    return;
-  }
-
-  if (v8Value->IsObject()) {
-    TestDictionary cppValue;
-    V8TestDictionary::toImpl(isolate, v8Value, cppValue, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setTestDictionary(cppValue);
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setLong(cppValue);
-    return;
-  }
-
-  {
-    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setLong(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const LongOrTestDictionary& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case LongOrTestDictionary::SpecificTypeNone:
-      return v8::Null(isolate);
-    case LongOrTestDictionary::SpecificTypeLong:
-      return v8::Integer::New(isolate, impl.getAsLong());
-    case LongOrTestDictionary::SpecificTypeTestDictionary:
-      return ToV8(impl.getAsTestDictionary(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-LongOrTestDictionary NativeValueTraits<LongOrTestDictionary>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  LongOrTestDictionary impl;
-  V8LongOrTestDictionary::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongSequenceOrEvent.cpp b/third_party/WebKit/Source/bindings/tests/results/core/LongSequenceOrEvent.cpp
deleted file mode 100644
index e286d5ed..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/LongSequenceOrEvent.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "LongSequenceOrEvent.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8Event.h"
-
-namespace blink {
-
-LongSequenceOrEvent::LongSequenceOrEvent() : type_(SpecificTypeNone) {}
-
-Event* LongSequenceOrEvent::getAsEvent() const {
-  DCHECK(isEvent());
-  return event_;
-}
-
-void LongSequenceOrEvent::setEvent(Event* value) {
-  DCHECK(isNull());
-  event_ = value;
-  type_ = SpecificTypeEvent;
-}
-
-LongSequenceOrEvent LongSequenceOrEvent::fromEvent(Event* value) {
-  LongSequenceOrEvent container;
-  container.setEvent(value);
-  return container;
-}
-
-const Vector<int32_t>& LongSequenceOrEvent::getAsLongSequence() const {
-  DCHECK(isLongSequence());
-  return long_sequence_;
-}
-
-void LongSequenceOrEvent::setLongSequence(const Vector<int32_t>& value) {
-  DCHECK(isNull());
-  long_sequence_ = value;
-  type_ = SpecificTypeLongSequence;
-}
-
-LongSequenceOrEvent LongSequenceOrEvent::fromLongSequence(const Vector<int32_t>& value) {
-  LongSequenceOrEvent container;
-  container.setLongSequence(value);
-  return container;
-}
-
-LongSequenceOrEvent::LongSequenceOrEvent(const LongSequenceOrEvent&) = default;
-LongSequenceOrEvent::~LongSequenceOrEvent() = default;
-LongSequenceOrEvent& LongSequenceOrEvent::operator=(const LongSequenceOrEvent&) = default;
-
-DEFINE_TRACE(LongSequenceOrEvent) {
-  visitor->Trace(event_);
-}
-
-void V8LongSequenceOrEvent::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, LongSequenceOrEvent& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8Event::hasInstance(v8Value, isolate)) {
-    Event* cppValue = V8Event::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setEvent(cppValue);
-    return;
-  }
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    Vector<int32_t> cppValue = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setLongSequence(cppValue);
-    return;
-  }
-
-  exceptionState.ThrowTypeError("The provided value is not of type '(sequence<long> or Event)'");
-}
-
-v8::Local<v8::Value> ToV8(const LongSequenceOrEvent& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case LongSequenceOrEvent::SpecificTypeNone:
-      return v8::Null(isolate);
-    case LongSequenceOrEvent::SpecificTypeEvent:
-      return ToV8(impl.getAsEvent(), creationContext, isolate);
-    case LongSequenceOrEvent::SpecificTypeLongSequence:
-      return ToV8(impl.getAsLongSequence(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-LongSequenceOrEvent NativeValueTraits<LongSequenceOrEvent>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  LongSequenceOrEvent impl;
-  V8LongSequenceOrEvent::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/NestedUnionType.cpp b/third_party/WebKit/Source/bindings/tests/results/core/NestedUnionType.cpp
deleted file mode 100644
index f393166c..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/NestedUnionType.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "NestedUnionType.h"
-
-#include "bindings/core/v8/ByteStringOrNodeList.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8Event.h"
-#include "bindings/core/v8/V8Node.h"
-#include "bindings/core/v8/V8NodeList.h"
-#include "bindings/core/v8/V8XMLHttpRequest.h"
-#include "core/dom/NameNodeList.h"
-#include "core/dom/NodeList.h"
-#include "core/dom/StaticNodeList.h"
-#include "core/html/LabelsNodeList.h"
-
-namespace blink {
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord() : type_(SpecificTypeNone) {}
-
-Event* NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsEvent() const {
-  DCHECK(isEvent());
-  return event_;
-}
-
-void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setEvent(Event* value) {
-  DCHECK(isNull());
-  event_ = value;
-  type_ = SpecificTypeEvent;
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromEvent(Event* value) {
-  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
-  container.setEvent(value);
-  return container;
-}
-
-const Vector<int32_t>& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsLongSequence() const {
-  DCHECK(isLongSequence());
-  return long_sequence_;
-}
-
-void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setLongSequence(const Vector<int32_t>& value) {
-  DCHECK(isNull());
-  long_sequence_ = value;
-  type_ = SpecificTypeLongSequence;
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromLongSequence(const Vector<int32_t>& value) {
-  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
-  container.setLongSequence(value);
-  return container;
-}
-
-Node* NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsNode() const {
-  DCHECK(isNode());
-  return node_;
-}
-
-void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setNode(Node* value) {
-  DCHECK(isNull());
-  node_ = value;
-  type_ = SpecificTypeNode;
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromNode(Node* value) {
-  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
-  container.setNode(value);
-  return container;
-}
-
-const String& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromString(const String& value) {
-  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
-  container.setString(value);
-  return container;
-}
-
-const HeapVector<std::pair<String, ByteStringOrNodeList>>& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsStringByteStringOrNodeListRecord() const {
-  DCHECK(isStringByteStringOrNodeListRecord());
-  return string_byte_string_or_node_list_record_;
-}
-
-void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setStringByteStringOrNodeListRecord(const HeapVector<std::pair<String, ByteStringOrNodeList>>& value) {
-  DCHECK(isNull());
-  string_byte_string_or_node_list_record_ = value;
-  type_ = SpecificTypeStringByteStringOrNodeListRecord;
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromStringByteStringOrNodeListRecord(const HeapVector<std::pair<String, ByteStringOrNodeList>>& value) {
-  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
-  container.setStringByteStringOrNodeListRecord(value);
-  return container;
-}
-
-XMLHttpRequest* NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsXMLHttpRequest() const {
-  DCHECK(isXMLHttpRequest());
-  return xml_http_request_;
-}
-
-void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setXMLHttpRequest(XMLHttpRequest* value) {
-  DCHECK(isNull());
-  xml_http_request_ = value;
-  type_ = SpecificTypeXMLHttpRequest;
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromXMLHttpRequest(XMLHttpRequest* value) {
-  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
-  container.setXMLHttpRequest(value);
-  return container;
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord(const NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord&) = default;
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::~NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord() = default;
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::operator=(const NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord&) = default;
-
-DEFINE_TRACE(NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord) {
-  visitor->Trace(event_);
-  visitor->Trace(node_);
-  visitor->Trace(string_byte_string_or_node_list_record_);
-  visitor->Trace(xml_http_request_);
-}
-
-void V8NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8Event::hasInstance(v8Value, isolate)) {
-    Event* cppValue = V8Event::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setEvent(cppValue);
-    return;
-  }
-
-  if (V8Node::hasInstance(v8Value, isolate)) {
-    Node* cppValue = V8Node::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setNode(cppValue);
-    return;
-  }
-
-  if (V8XMLHttpRequest::hasInstance(v8Value, isolate)) {
-    XMLHttpRequest* cppValue = V8XMLHttpRequest::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setXMLHttpRequest(cppValue);
-    return;
-  }
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    Vector<int32_t> cppValue = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setLongSequence(cppValue);
-    return;
-  }
-
-  if (v8Value->IsObject()) {
-    HeapVector<std::pair<String, ByteStringOrNodeList>> cppValue = NativeValueTraits<IDLRecord<IDLString, ByteStringOrNodeList>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setStringByteStringOrNodeListRecord(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeNone:
-      return v8::Null(isolate);
-    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeEvent:
-      return ToV8(impl.getAsEvent(), creationContext, isolate);
-    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeLongSequence:
-      return ToV8(impl.getAsLongSequence(), creationContext, isolate);
-    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeNode:
-      return ToV8(impl.getAsNode(), creationContext, isolate);
-    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeStringByteStringOrNodeListRecord:
-      return ToV8(impl.getAsStringByteStringOrNodeListRecord(), creationContext, isolate);
-    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeXMLHttpRequest:
-      return ToV8(impl.getAsXMLHttpRequest(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NativeValueTraits<NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord impl;
-  V8NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/NodeOrNodeList.cpp b/third_party/WebKit/Source/bindings/tests/results/core/NodeOrNodeList.cpp
deleted file mode 100644
index 15b8a09c..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/NodeOrNodeList.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "NodeOrNodeList.h"
-
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8Node.h"
-#include "bindings/core/v8/V8NodeList.h"
-#include "core/dom/NameNodeList.h"
-#include "core/dom/NodeList.h"
-#include "core/dom/StaticNodeList.h"
-#include "core/html/LabelsNodeList.h"
-
-namespace blink {
-
-NodeOrNodeList::NodeOrNodeList() : type_(SpecificTypeNone) {}
-
-Node* NodeOrNodeList::getAsNode() const {
-  DCHECK(isNode());
-  return node_;
-}
-
-void NodeOrNodeList::setNode(Node* value) {
-  DCHECK(isNull());
-  node_ = value;
-  type_ = SpecificTypeNode;
-}
-
-NodeOrNodeList NodeOrNodeList::fromNode(Node* value) {
-  NodeOrNodeList container;
-  container.setNode(value);
-  return container;
-}
-
-NodeList* NodeOrNodeList::getAsNodeList() const {
-  DCHECK(isNodeList());
-  return node_list_;
-}
-
-void NodeOrNodeList::setNodeList(NodeList* value) {
-  DCHECK(isNull());
-  node_list_ = value;
-  type_ = SpecificTypeNodeList;
-}
-
-NodeOrNodeList NodeOrNodeList::fromNodeList(NodeList* value) {
-  NodeOrNodeList container;
-  container.setNodeList(value);
-  return container;
-}
-
-NodeOrNodeList::NodeOrNodeList(const NodeOrNodeList&) = default;
-NodeOrNodeList::~NodeOrNodeList() = default;
-NodeOrNodeList& NodeOrNodeList::operator=(const NodeOrNodeList&) = default;
-
-DEFINE_TRACE(NodeOrNodeList) {
-  visitor->Trace(node_);
-  visitor->Trace(node_list_);
-}
-
-void V8NodeOrNodeList::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, NodeOrNodeList& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8Node::hasInstance(v8Value, isolate)) {
-    Node* cppValue = V8Node::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setNode(cppValue);
-    return;
-  }
-
-  if (V8NodeList::hasInstance(v8Value, isolate)) {
-    NodeList* cppValue = V8NodeList::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setNodeList(cppValue);
-    return;
-  }
-
-  exceptionState.ThrowTypeError("The provided value is not of type '(Node or NodeList)'");
-}
-
-v8::Local<v8::Value> ToV8(const NodeOrNodeList& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case NodeOrNodeList::SpecificTypeNone:
-      return v8::Null(isolate);
-    case NodeOrNodeList::SpecificTypeNode:
-      return ToV8(impl.getAsNode(), creationContext, isolate);
-    case NodeOrNodeList::SpecificTypeNodeList:
-      return ToV8(impl.getAsNodeList(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-NodeOrNodeList NativeValueTraits<NodeOrNodeList>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  NodeOrNodeList impl;
-  V8NodeOrNodeList::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringOrArrayBufferOrArrayBufferView.cpp b/third_party/WebKit/Source/bindings/tests/results/core/StringOrArrayBufferOrArrayBufferView.cpp
deleted file mode 100644
index fc83b15..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/StringOrArrayBufferOrArrayBufferView.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "StringOrArrayBufferOrArrayBufferView.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8ArrayBuffer.h"
-
-namespace blink {
-
-StringOrArrayBufferOrArrayBufferView::StringOrArrayBufferOrArrayBufferView() : type_(SpecificTypeNone) {}
-
-TestArrayBuffer* StringOrArrayBufferOrArrayBufferView::getAsArrayBuffer() const {
-  DCHECK(isArrayBuffer());
-  return array_buffer_;
-}
-
-void StringOrArrayBufferOrArrayBufferView::setArrayBuffer(TestArrayBuffer* value) {
-  DCHECK(isNull());
-  array_buffer_ = value;
-  type_ = SpecificTypeArrayBuffer;
-}
-
-StringOrArrayBufferOrArrayBufferView StringOrArrayBufferOrArrayBufferView::fromArrayBuffer(TestArrayBuffer* value) {
-  StringOrArrayBufferOrArrayBufferView container;
-  container.setArrayBuffer(value);
-  return container;
-}
-
-NotShared<TestArrayBufferView> StringOrArrayBufferOrArrayBufferView::getAsArrayBufferView() const {
-  DCHECK(isArrayBufferView());
-  return array_buffer_view_;
-}
-
-void StringOrArrayBufferOrArrayBufferView::setArrayBufferView(NotShared<TestArrayBufferView> value) {
-  DCHECK(isNull());
-  array_buffer_view_ = Member<TestArrayBufferView>(value.View());
-  type_ = SpecificTypeArrayBufferView;
-}
-
-StringOrArrayBufferOrArrayBufferView StringOrArrayBufferOrArrayBufferView::fromArrayBufferView(NotShared<TestArrayBufferView> value) {
-  StringOrArrayBufferOrArrayBufferView container;
-  container.setArrayBufferView(value);
-  return container;
-}
-
-const String& StringOrArrayBufferOrArrayBufferView::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void StringOrArrayBufferOrArrayBufferView::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-StringOrArrayBufferOrArrayBufferView StringOrArrayBufferOrArrayBufferView::fromString(const String& value) {
-  StringOrArrayBufferOrArrayBufferView container;
-  container.setString(value);
-  return container;
-}
-
-StringOrArrayBufferOrArrayBufferView::StringOrArrayBufferOrArrayBufferView(const StringOrArrayBufferOrArrayBufferView&) = default;
-StringOrArrayBufferOrArrayBufferView::~StringOrArrayBufferOrArrayBufferView() = default;
-StringOrArrayBufferOrArrayBufferView& StringOrArrayBufferOrArrayBufferView::operator=(const StringOrArrayBufferOrArrayBufferView&) = default;
-
-DEFINE_TRACE(StringOrArrayBufferOrArrayBufferView) {
-  visitor->Trace(array_buffer_);
-  visitor->Trace(array_buffer_view_);
-}
-
-void V8StringOrArrayBufferOrArrayBufferView::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, StringOrArrayBufferOrArrayBufferView& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsArrayBuffer()) {
-    TestArrayBuffer* cppValue = V8ArrayBuffer::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setArrayBuffer(cppValue);
-    return;
-  }
-
-  if (v8Value->IsArrayBufferView()) {
-    NotShared<TestArrayBufferView> cppValue = ToNotShared<NotShared<TestArrayBufferView>>(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setArrayBufferView(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const StringOrArrayBufferOrArrayBufferView& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case StringOrArrayBufferOrArrayBufferView::SpecificTypeNone:
-      return v8::Null(isolate);
-    case StringOrArrayBufferOrArrayBufferView::SpecificTypeArrayBuffer:
-      return ToV8(impl.getAsArrayBuffer(), creationContext, isolate);
-    case StringOrArrayBufferOrArrayBufferView::SpecificTypeArrayBufferView:
-      return ToV8(impl.getAsArrayBufferView(), creationContext, isolate);
-    case StringOrArrayBufferOrArrayBufferView::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-StringOrArrayBufferOrArrayBufferView NativeValueTraits<StringOrArrayBufferOrArrayBufferView>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  StringOrArrayBufferOrArrayBufferView impl;
-  V8StringOrArrayBufferOrArrayBufferView::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringOrDouble.cpp b/third_party/WebKit/Source/bindings/tests/results/core/StringOrDouble.cpp
deleted file mode 100644
index 781cee7..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/StringOrDouble.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "StringOrDouble.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-StringOrDouble::StringOrDouble() : type_(SpecificTypeNone) {}
-
-double StringOrDouble::getAsDouble() const {
-  DCHECK(isDouble());
-  return double_;
-}
-
-void StringOrDouble::setDouble(double value) {
-  DCHECK(isNull());
-  double_ = value;
-  type_ = SpecificTypeDouble;
-}
-
-StringOrDouble StringOrDouble::fromDouble(double value) {
-  StringOrDouble container;
-  container.setDouble(value);
-  return container;
-}
-
-const String& StringOrDouble::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void StringOrDouble::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-StringOrDouble StringOrDouble::fromString(const String& value) {
-  StringOrDouble container;
-  container.setString(value);
-  return container;
-}
-
-StringOrDouble::StringOrDouble(const StringOrDouble&) = default;
-StringOrDouble::~StringOrDouble() = default;
-StringOrDouble& StringOrDouble::operator=(const StringOrDouble&) = default;
-
-DEFINE_TRACE(StringOrDouble) {
-}
-
-void V8StringOrDouble::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, StringOrDouble& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsNumber()) {
-    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDouble(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const StringOrDouble& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case StringOrDouble::SpecificTypeNone:
-      return v8::Null(isolate);
-    case StringOrDouble::SpecificTypeDouble:
-      return v8::Number::New(isolate, impl.getAsDouble());
-    case StringOrDouble::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-StringOrDouble NativeValueTraits<StringOrDouble>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  StringOrDouble impl;
-  V8StringOrDouble::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringOrStringSequence.cpp b/third_party/WebKit/Source/bindings/tests/results/core/StringOrStringSequence.cpp
deleted file mode 100644
index 1cd1213..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/StringOrStringSequence.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "StringOrStringSequence.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-StringOrStringSequence::StringOrStringSequence() : type_(SpecificTypeNone) {}
-
-const String& StringOrStringSequence::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void StringOrStringSequence::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-StringOrStringSequence StringOrStringSequence::fromString(const String& value) {
-  StringOrStringSequence container;
-  container.setString(value);
-  return container;
-}
-
-const Vector<String>& StringOrStringSequence::getAsStringSequence() const {
-  DCHECK(isStringSequence());
-  return string_sequence_;
-}
-
-void StringOrStringSequence::setStringSequence(const Vector<String>& value) {
-  DCHECK(isNull());
-  string_sequence_ = value;
-  type_ = SpecificTypeStringSequence;
-}
-
-StringOrStringSequence StringOrStringSequence::fromStringSequence(const Vector<String>& value) {
-  StringOrStringSequence container;
-  container.setStringSequence(value);
-  return container;
-}
-
-StringOrStringSequence::StringOrStringSequence(const StringOrStringSequence&) = default;
-StringOrStringSequence::~StringOrStringSequence() = default;
-StringOrStringSequence& StringOrStringSequence::operator=(const StringOrStringSequence&) = default;
-
-DEFINE_TRACE(StringOrStringSequence) {
-}
-
-void V8StringOrStringSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, StringOrStringSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
-    Vector<String> cppValue = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setStringSequence(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const StringOrStringSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case StringOrStringSequence::SpecificTypeNone:
-      return v8::Null(isolate);
-    case StringOrStringSequence::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    case StringOrStringSequence::SpecificTypeStringSequence:
-      return ToV8(impl.getAsStringSequence(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-StringOrStringSequence NativeValueTraits<StringOrStringSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  StringOrStringSequence impl;
-  V8StringOrStringSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.cpp
deleted file mode 100644
index 44dd530..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "StringSequenceCallbackFunctionLongSequenceArg.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-StringSequenceCallbackFunctionLongSequenceArg* StringSequenceCallbackFunctionLongSequenceArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new StringSequenceCallbackFunctionLongSequenceArg(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-StringSequenceCallbackFunctionLongSequenceArg::StringSequenceCallbackFunctionLongSequenceArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(StringSequenceCallbackFunctionLongSequenceArg) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool StringSequenceCallbackFunctionLongSequenceArg::call(ScriptWrappable* scriptWrappable, const Vector<int32_t>& arg, Vector<String>& returnValue) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate());
-  v8::Local<v8::Value> argv[] = { v8_arg };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    1,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  Vector<String> cppValue = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(script_state_->GetIsolate(), v8ReturnValue, exceptionState);
-  if (exceptionState.HadException())
-    return false;
-  returnValue = cppValue;
-  return true;
-}
-
-StringSequenceCallbackFunctionLongSequenceArg* NativeValueTraits<StringSequenceCallbackFunctionLongSequenceArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  StringSequenceCallbackFunctionLongSequenceArg* nativeValue = StringSequenceCallbackFunctionLongSequenceArg::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "StringSequenceCallbackFunctionLongSequenceArg"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestDictionary.h b/third_party/WebKit/Source/bindings/tests/results/core/TestDictionary.h
index daf685d1..9ca613c 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestDictionary.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/TestDictionary.h
@@ -13,12 +13,12 @@
 #define TestDictionary_h
 
 #include "bindings/core/v8/Dictionary.h"
-#include "bindings/core/v8/DoubleOrString.h"
-#include "bindings/core/v8/FloatOrBoolean.h"
 #include "bindings/core/v8/IDLDictionaryBase.h"
-#include "bindings/core/v8/LongOrBoolean.h"
 #include "bindings/core/v8/ScriptValue.h"
-#include "bindings/core/v8/TestInterface2OrUint8Array.h"
+#include "bindings/core/v8/double_or_string.h"
+#include "bindings/core/v8/float_or_boolean.h"
+#include "bindings/core/v8/long_or_boolean.h"
+#include "bindings/core/v8/test_interface_2_or_uint8_array.h"
 #include "bindings/tests/idls/core/TestInterface2.h"
 #include "core/CoreExport.h"
 #include "core/testing/InternalDictionary.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestDictionaryDerivedImplementedAs.h b/third_party/WebKit/Source/bindings/tests/results/core/TestDictionaryDerivedImplementedAs.h
index 70f95d93..ddad8bbb 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestDictionaryDerivedImplementedAs.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/TestDictionaryDerivedImplementedAs.h
@@ -12,7 +12,7 @@
 #ifndef TestDictionaryDerivedImplementedAs_h
 #define TestDictionaryDerivedImplementedAs_h
 
-#include "bindings/core/v8/StringOrDouble.h"
+#include "bindings/core/v8/string_or_double.h"
 #include "bindings/tests/idls/core/TestDictionary.h"
 #include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestEnumOrDouble.cpp b/third_party/WebKit/Source/bindings/tests/results/core/TestEnumOrDouble.cpp
deleted file mode 100644
index 17d6683..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestEnumOrDouble.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "TestEnumOrDouble.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-TestEnumOrDouble::TestEnumOrDouble() : type_(SpecificTypeNone) {}
-
-double TestEnumOrDouble::getAsDouble() const {
-  DCHECK(isDouble());
-  return double_;
-}
-
-void TestEnumOrDouble::setDouble(double value) {
-  DCHECK(isNull());
-  double_ = value;
-  type_ = SpecificTypeDouble;
-}
-
-TestEnumOrDouble TestEnumOrDouble::fromDouble(double value) {
-  TestEnumOrDouble container;
-  container.setDouble(value);
-  return container;
-}
-
-const String& TestEnumOrDouble::getAsTestEnum() const {
-  DCHECK(isTestEnum());
-  return test_enum_;
-}
-
-void TestEnumOrDouble::setTestEnum(const String& value) {
-  DCHECK(isNull());
-  NonThrowableExceptionState exceptionState;
-  const char* validValues[] = {
-      "",
-      "EnumValue1",
-      "EnumValue2",
-      "EnumValue3",
-  };
-  if (!IsValidEnum(value, validValues, WTF_ARRAY_LENGTH(validValues), "TestEnum", exceptionState)) {
-    NOTREACHED();
-    return;
-  }
-  test_enum_ = value;
-  type_ = SpecificTypeTestEnum;
-}
-
-TestEnumOrDouble TestEnumOrDouble::fromTestEnum(const String& value) {
-  TestEnumOrDouble container;
-  container.setTestEnum(value);
-  return container;
-}
-
-TestEnumOrDouble::TestEnumOrDouble(const TestEnumOrDouble&) = default;
-TestEnumOrDouble::~TestEnumOrDouble() = default;
-TestEnumOrDouble& TestEnumOrDouble::operator=(const TestEnumOrDouble&) = default;
-
-DEFINE_TRACE(TestEnumOrDouble) {
-}
-
-void V8TestEnumOrDouble::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestEnumOrDouble& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsNumber()) {
-    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setDouble(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    const char* validValues[] = {
-        "",
-        "EnumValue1",
-        "EnumValue2",
-        "EnumValue3",
-    };
-    if (!IsValidEnum(cppValue, validValues, WTF_ARRAY_LENGTH(validValues), "TestEnum", exceptionState))
-      return;
-    impl.setTestEnum(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const TestEnumOrDouble& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case TestEnumOrDouble::SpecificTypeNone:
-      return v8::Null(isolate);
-    case TestEnumOrDouble::SpecificTypeDouble:
-      return v8::Number::New(isolate, impl.getAsDouble());
-    case TestEnumOrDouble::SpecificTypeTestEnum:
-      return V8String(isolate, impl.getAsTestEnum());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-TestEnumOrDouble NativeValueTraits<TestEnumOrDouble>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  TestEnumOrDouble impl;
-  V8TestEnumOrDouble::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.cpp b/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.cpp
deleted file mode 100644
index e7e4138..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "TestInterface2OrUint8Array.h"
-
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8TestInterface2.h"
-
-namespace blink {
-
-TestInterface2OrUint8Array::TestInterface2OrUint8Array() : type_(SpecificTypeNone) {}
-
-TestInterface2* TestInterface2OrUint8Array::getAsTestInterface2() const {
-  DCHECK(isTestInterface2());
-  return test_interface_2_;
-}
-
-void TestInterface2OrUint8Array::setTestInterface2(TestInterface2* value) {
-  DCHECK(isNull());
-  test_interface_2_ = value;
-  type_ = SpecificTypeTestInterface2;
-}
-
-TestInterface2OrUint8Array TestInterface2OrUint8Array::fromTestInterface2(TestInterface2* value) {
-  TestInterface2OrUint8Array container;
-  container.setTestInterface2(value);
-  return container;
-}
-
-NotShared<DOMUint8Array> TestInterface2OrUint8Array::getAsUint8Array() const {
-  DCHECK(isUint8Array());
-  return uint8_array_;
-}
-
-void TestInterface2OrUint8Array::setUint8Array(NotShared<DOMUint8Array> value) {
-  DCHECK(isNull());
-  uint8_array_ = Member<DOMUint8Array>(value.View());
-  type_ = SpecificTypeUint8Array;
-}
-
-TestInterface2OrUint8Array TestInterface2OrUint8Array::fromUint8Array(NotShared<DOMUint8Array> value) {
-  TestInterface2OrUint8Array container;
-  container.setUint8Array(value);
-  return container;
-}
-
-TestInterface2OrUint8Array::TestInterface2OrUint8Array(const TestInterface2OrUint8Array&) = default;
-TestInterface2OrUint8Array::~TestInterface2OrUint8Array() = default;
-TestInterface2OrUint8Array& TestInterface2OrUint8Array::operator=(const TestInterface2OrUint8Array&) = default;
-
-DEFINE_TRACE(TestInterface2OrUint8Array) {
-  visitor->Trace(test_interface_2_);
-  visitor->Trace(uint8_array_);
-}
-
-void V8TestInterface2OrUint8Array::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterface2OrUint8Array& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8TestInterface2::hasInstance(v8Value, isolate)) {
-    TestInterface2* cppValue = V8TestInterface2::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setTestInterface2(cppValue);
-    return;
-  }
-
-  if (v8Value->IsUint8Array()) {
-    NotShared<DOMUint8Array> cppValue = ToNotShared<NotShared<DOMUint8Array>>(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setUint8Array(cppValue);
-    return;
-  }
-
-  exceptionState.ThrowTypeError("The provided value is not of type '(TestInterface2 or Uint8Array)'");
-}
-
-v8::Local<v8::Value> ToV8(const TestInterface2OrUint8Array& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case TestInterface2OrUint8Array::SpecificTypeNone:
-      return v8::Null(isolate);
-    case TestInterface2OrUint8Array::SpecificTypeTestInterface2:
-      return ToV8(impl.getAsTestInterface2(), creationContext, isolate);
-    case TestInterface2OrUint8Array::SpecificTypeUint8Array:
-      return ToV8(impl.getAsUint8Array(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-TestInterface2OrUint8Array NativeValueTraits<TestInterface2OrUint8Array>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  TestInterface2OrUint8Array impl;
-  V8TestInterface2OrUint8Array::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceGarbageCollectedOrString.cpp b/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceGarbageCollectedOrString.cpp
deleted file mode 100644
index 506fc2ab..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceGarbageCollectedOrString.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "TestInterfaceGarbageCollectedOrString.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8TestInterfaceGarbageCollected.h"
-
-namespace blink {
-
-TestInterfaceGarbageCollectedOrString::TestInterfaceGarbageCollectedOrString() : type_(SpecificTypeNone) {}
-
-const String& TestInterfaceGarbageCollectedOrString::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void TestInterfaceGarbageCollectedOrString::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-TestInterfaceGarbageCollectedOrString TestInterfaceGarbageCollectedOrString::fromString(const String& value) {
-  TestInterfaceGarbageCollectedOrString container;
-  container.setString(value);
-  return container;
-}
-
-TestInterfaceGarbageCollected* TestInterfaceGarbageCollectedOrString::getAsTestInterfaceGarbageCollected() const {
-  DCHECK(isTestInterfaceGarbageCollected());
-  return test_interface_garbage_collected_;
-}
-
-void TestInterfaceGarbageCollectedOrString::setTestInterfaceGarbageCollected(TestInterfaceGarbageCollected* value) {
-  DCHECK(isNull());
-  test_interface_garbage_collected_ = value;
-  type_ = SpecificTypeTestInterfaceGarbageCollected;
-}
-
-TestInterfaceGarbageCollectedOrString TestInterfaceGarbageCollectedOrString::fromTestInterfaceGarbageCollected(TestInterfaceGarbageCollected* value) {
-  TestInterfaceGarbageCollectedOrString container;
-  container.setTestInterfaceGarbageCollected(value);
-  return container;
-}
-
-TestInterfaceGarbageCollectedOrString::TestInterfaceGarbageCollectedOrString(const TestInterfaceGarbageCollectedOrString&) = default;
-TestInterfaceGarbageCollectedOrString::~TestInterfaceGarbageCollectedOrString() = default;
-TestInterfaceGarbageCollectedOrString& TestInterfaceGarbageCollectedOrString::operator=(const TestInterfaceGarbageCollectedOrString&) = default;
-
-DEFINE_TRACE(TestInterfaceGarbageCollectedOrString) {
-  visitor->Trace(test_interface_garbage_collected_);
-}
-
-void V8TestInterfaceGarbageCollectedOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterfaceGarbageCollectedOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8TestInterfaceGarbageCollected::hasInstance(v8Value, isolate)) {
-    TestInterfaceGarbageCollected* cppValue = V8TestInterfaceGarbageCollected::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setTestInterfaceGarbageCollected(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const TestInterfaceGarbageCollectedOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case TestInterfaceGarbageCollectedOrString::SpecificTypeNone:
-      return v8::Null(isolate);
-    case TestInterfaceGarbageCollectedOrString::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    case TestInterfaceGarbageCollectedOrString::SpecificTypeTestInterfaceGarbageCollected:
-      return ToV8(impl.getAsTestInterfaceGarbageCollected(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-TestInterfaceGarbageCollectedOrString NativeValueTraits<TestInterfaceGarbageCollectedOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  TestInterfaceGarbageCollectedOrString impl;
-  V8TestInterfaceGarbageCollectedOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrLong.cpp b/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrLong.cpp
deleted file mode 100644
index 510cade..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrLong.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "TestInterfaceOrLong.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8TestInterface.h"
-#include "bindings/tests/idls/core/TestImplements2.h"
-#include "bindings/tests/idls/core/TestImplements3Implementation.h"
-#include "bindings/tests/idls/core/TestInterfacePartial.h"
-#include "bindings/tests/idls/core/TestInterfacePartial2Implementation.h"
-#include "bindings/tests/idls/core/TestInterfacePartialSecureContext.h"
-
-namespace blink {
-
-TestInterfaceOrLong::TestInterfaceOrLong() : type_(SpecificTypeNone) {}
-
-int32_t TestInterfaceOrLong::getAsLong() const {
-  DCHECK(isLong());
-  return long_;
-}
-
-void TestInterfaceOrLong::setLong(int32_t value) {
-  DCHECK(isNull());
-  long_ = value;
-  type_ = SpecificTypeLong;
-}
-
-TestInterfaceOrLong TestInterfaceOrLong::fromLong(int32_t value) {
-  TestInterfaceOrLong container;
-  container.setLong(value);
-  return container;
-}
-
-TestInterfaceImplementation* TestInterfaceOrLong::getAsTestInterface() const {
-  DCHECK(isTestInterface());
-  return test_interface_;
-}
-
-void TestInterfaceOrLong::setTestInterface(TestInterfaceImplementation* value) {
-  DCHECK(isNull());
-  test_interface_ = value;
-  type_ = SpecificTypeTestInterface;
-}
-
-TestInterfaceOrLong TestInterfaceOrLong::fromTestInterface(TestInterfaceImplementation* value) {
-  TestInterfaceOrLong container;
-  container.setTestInterface(value);
-  return container;
-}
-
-TestInterfaceOrLong::TestInterfaceOrLong(const TestInterfaceOrLong&) = default;
-TestInterfaceOrLong::~TestInterfaceOrLong() = default;
-TestInterfaceOrLong& TestInterfaceOrLong::operator=(const TestInterfaceOrLong&) = default;
-
-DEFINE_TRACE(TestInterfaceOrLong) {
-  visitor->Trace(test_interface_);
-}
-
-void V8TestInterfaceOrLong::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterfaceOrLong& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8TestInterface::hasInstance(v8Value, isolate)) {
-    TestInterfaceImplementation* cppValue = V8TestInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setTestInterface(cppValue);
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setLong(cppValue);
-    return;
-  }
-
-  {
-    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setLong(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const TestInterfaceOrLong& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case TestInterfaceOrLong::SpecificTypeNone:
-      return v8::Null(isolate);
-    case TestInterfaceOrLong::SpecificTypeLong:
-      return v8::Integer::New(isolate, impl.getAsLong());
-    case TestInterfaceOrLong::SpecificTypeTestInterface:
-      return ToV8(impl.getAsTestInterface(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-TestInterfaceOrLong NativeValueTraits<TestInterfaceOrLong>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  TestInterfaceOrLong impl;
-  V8TestInterfaceOrLong::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrTestInterfaceEmpty.cpp b/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrTestInterfaceEmpty.cpp
deleted file mode 100644
index 5087426..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrTestInterfaceEmpty.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "TestInterfaceOrTestInterfaceEmpty.h"
-
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8TestInterface.h"
-#include "bindings/core/v8/V8TestInterfaceEmpty.h"
-#include "bindings/tests/idls/core/TestImplements2.h"
-#include "bindings/tests/idls/core/TestImplements3Implementation.h"
-#include "bindings/tests/idls/core/TestInterfacePartial.h"
-#include "bindings/tests/idls/core/TestInterfacePartial2Implementation.h"
-#include "bindings/tests/idls/core/TestInterfacePartialSecureContext.h"
-
-namespace blink {
-
-TestInterfaceOrTestInterfaceEmpty::TestInterfaceOrTestInterfaceEmpty() : type_(SpecificTypeNone) {}
-
-TestInterfaceImplementation* TestInterfaceOrTestInterfaceEmpty::getAsTestInterface() const {
-  DCHECK(isTestInterface());
-  return test_interface_;
-}
-
-void TestInterfaceOrTestInterfaceEmpty::setTestInterface(TestInterfaceImplementation* value) {
-  DCHECK(isNull());
-  test_interface_ = value;
-  type_ = SpecificTypeTestInterface;
-}
-
-TestInterfaceOrTestInterfaceEmpty TestInterfaceOrTestInterfaceEmpty::fromTestInterface(TestInterfaceImplementation* value) {
-  TestInterfaceOrTestInterfaceEmpty container;
-  container.setTestInterface(value);
-  return container;
-}
-
-TestInterfaceEmpty* TestInterfaceOrTestInterfaceEmpty::getAsTestInterfaceEmpty() const {
-  DCHECK(isTestInterfaceEmpty());
-  return test_interface_empty_;
-}
-
-void TestInterfaceOrTestInterfaceEmpty::setTestInterfaceEmpty(TestInterfaceEmpty* value) {
-  DCHECK(isNull());
-  test_interface_empty_ = value;
-  type_ = SpecificTypeTestInterfaceEmpty;
-}
-
-TestInterfaceOrTestInterfaceEmpty TestInterfaceOrTestInterfaceEmpty::fromTestInterfaceEmpty(TestInterfaceEmpty* value) {
-  TestInterfaceOrTestInterfaceEmpty container;
-  container.setTestInterfaceEmpty(value);
-  return container;
-}
-
-TestInterfaceOrTestInterfaceEmpty::TestInterfaceOrTestInterfaceEmpty(const TestInterfaceOrTestInterfaceEmpty&) = default;
-TestInterfaceOrTestInterfaceEmpty::~TestInterfaceOrTestInterfaceEmpty() = default;
-TestInterfaceOrTestInterfaceEmpty& TestInterfaceOrTestInterfaceEmpty::operator=(const TestInterfaceOrTestInterfaceEmpty&) = default;
-
-DEFINE_TRACE(TestInterfaceOrTestInterfaceEmpty) {
-  visitor->Trace(test_interface_);
-  visitor->Trace(test_interface_empty_);
-}
-
-void V8TestInterfaceOrTestInterfaceEmpty::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterfaceOrTestInterfaceEmpty& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8TestInterface::hasInstance(v8Value, isolate)) {
-    TestInterfaceImplementation* cppValue = V8TestInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setTestInterface(cppValue);
-    return;
-  }
-
-  if (V8TestInterfaceEmpty::hasInstance(v8Value, isolate)) {
-    TestInterfaceEmpty* cppValue = V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setTestInterfaceEmpty(cppValue);
-    return;
-  }
-
-  exceptionState.ThrowTypeError("The provided value is not of type '(TestInterface or TestInterfaceEmpty)'");
-}
-
-v8::Local<v8::Value> ToV8(const TestInterfaceOrTestInterfaceEmpty& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case TestInterfaceOrTestInterfaceEmpty::SpecificTypeNone:
-      return v8::Null(isolate);
-    case TestInterfaceOrTestInterfaceEmpty::SpecificTypeTestInterface:
-      return ToV8(impl.getAsTestInterface(), creationContext, isolate);
-    case TestInterfaceOrTestInterfaceEmpty::SpecificTypeTestInterfaceEmpty:
-      return ToV8(impl.getAsTestInterfaceEmpty(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-TestInterfaceOrTestInterfaceEmpty NativeValueTraits<TestInterfaceOrTestInterfaceEmpty>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  TestInterfaceOrTestInterfaceEmpty impl;
-  V8TestInterfaceOrTestInterfaceEmpty::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/UnrestrictedDoubleOrString.cpp b/third_party/WebKit/Source/bindings/tests/results/core/UnrestrictedDoubleOrString.cpp
deleted file mode 100644
index 41941a7..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/UnrestrictedDoubleOrString.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "UnrestrictedDoubleOrString.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-UnrestrictedDoubleOrString::UnrestrictedDoubleOrString() : type_(SpecificTypeNone) {}
-
-const String& UnrestrictedDoubleOrString::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void UnrestrictedDoubleOrString::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-UnrestrictedDoubleOrString UnrestrictedDoubleOrString::fromString(const String& value) {
-  UnrestrictedDoubleOrString container;
-  container.setString(value);
-  return container;
-}
-
-double UnrestrictedDoubleOrString::getAsUnrestrictedDouble() const {
-  DCHECK(isUnrestrictedDouble());
-  return unrestricted_double_;
-}
-
-void UnrestrictedDoubleOrString::setUnrestrictedDouble(double value) {
-  DCHECK(isNull());
-  unrestricted_double_ = value;
-  type_ = SpecificTypeUnrestrictedDouble;
-}
-
-UnrestrictedDoubleOrString UnrestrictedDoubleOrString::fromUnrestrictedDouble(double value) {
-  UnrestrictedDoubleOrString container;
-  container.setUnrestrictedDouble(value);
-  return container;
-}
-
-UnrestrictedDoubleOrString::UnrestrictedDoubleOrString(const UnrestrictedDoubleOrString&) = default;
-UnrestrictedDoubleOrString::~UnrestrictedDoubleOrString() = default;
-UnrestrictedDoubleOrString& UnrestrictedDoubleOrString::operator=(const UnrestrictedDoubleOrString&) = default;
-
-DEFINE_TRACE(UnrestrictedDoubleOrString) {
-}
-
-void V8UnrestrictedDoubleOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, UnrestrictedDoubleOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsNumber()) {
-    double cppValue = NativeValueTraits<IDLUnrestrictedDouble>::NativeValue(isolate, v8Value, exceptionState);
-    if (exceptionState.HadException())
-      return;
-    impl.setUnrestrictedDouble(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const UnrestrictedDoubleOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case UnrestrictedDoubleOrString::SpecificTypeNone:
-      return v8::Null(isolate);
-    case UnrestrictedDoubleOrString::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    case UnrestrictedDoubleOrString::SpecificTypeUnrestrictedDouble:
-      return v8::Number::New(isolate, impl.getAsUnrestrictedDouble());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-UnrestrictedDoubleOrString NativeValueTraits<UnrestrictedDoubleOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  UnrestrictedDoubleOrString impl;
-  V8UnrestrictedDoubleOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/UnsignedLongLongOrBooleanOrTestCallbackInterface.cpp b/third_party/WebKit/Source/bindings/tests/results/core/UnsignedLongLongOrBooleanOrTestCallbackInterface.cpp
deleted file mode 100644
index 9c78530..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/UnsignedLongLongOrBooleanOrTestCallbackInterface.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "UnsignedLongLongOrBooleanOrTestCallbackInterface.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8TestCallbackInterface.h"
-
-namespace blink {
-
-UnsignedLongLongOrBooleanOrTestCallbackInterface::UnsignedLongLongOrBooleanOrTestCallbackInterface() : type_(SpecificTypeNone) {}
-
-bool UnsignedLongLongOrBooleanOrTestCallbackInterface::getAsBoolean() const {
-  DCHECK(isBoolean());
-  return boolean_;
-}
-
-void UnsignedLongLongOrBooleanOrTestCallbackInterface::setBoolean(bool value) {
-  DCHECK(isNull());
-  boolean_ = value;
-  type_ = SpecificTypeBoolean;
-}
-
-UnsignedLongLongOrBooleanOrTestCallbackInterface UnsignedLongLongOrBooleanOrTestCallbackInterface::fromBoolean(bool value) {
-  UnsignedLongLongOrBooleanOrTestCallbackInterface container;
-  container.setBoolean(value);
-  return container;
-}
-
-TestCallbackInterface* UnsignedLongLongOrBooleanOrTestCallbackInterface::getAsTestCallbackInterface() const {
-  DCHECK(isTestCallbackInterface());
-  return test_callback_interface_;
-}
-
-void UnsignedLongLongOrBooleanOrTestCallbackInterface::setTestCallbackInterface(TestCallbackInterface* value) {
-  DCHECK(isNull());
-  test_callback_interface_ = value;
-  type_ = SpecificTypeTestCallbackInterface;
-}
-
-UnsignedLongLongOrBooleanOrTestCallbackInterface UnsignedLongLongOrBooleanOrTestCallbackInterface::fromTestCallbackInterface(TestCallbackInterface* value) {
-  UnsignedLongLongOrBooleanOrTestCallbackInterface container;
-  container.setTestCallbackInterface(value);
-  return container;
-}
-
-uint64_t UnsignedLongLongOrBooleanOrTestCallbackInterface::getAsUnsignedLongLong() const {
-  DCHECK(isUnsignedLongLong());
-  return unsigned_long_long_;
-}
-
-void UnsignedLongLongOrBooleanOrTestCallbackInterface::setUnsignedLongLong(uint64_t value) {
-  DCHECK(isNull());
-  unsigned_long_long_ = value;
-  type_ = SpecificTypeUnsignedLongLong;
-}
-
-UnsignedLongLongOrBooleanOrTestCallbackInterface UnsignedLongLongOrBooleanOrTestCallbackInterface::fromUnsignedLongLong(uint64_t value) {
-  UnsignedLongLongOrBooleanOrTestCallbackInterface container;
-  container.setUnsignedLongLong(value);
-  return container;
-}
-
-UnsignedLongLongOrBooleanOrTestCallbackInterface::UnsignedLongLongOrBooleanOrTestCallbackInterface(const UnsignedLongLongOrBooleanOrTestCallbackInterface&) = default;
-UnsignedLongLongOrBooleanOrTestCallbackInterface::~UnsignedLongLongOrBooleanOrTestCallbackInterface() = default;
-UnsignedLongLongOrBooleanOrTestCallbackInterface& UnsignedLongLongOrBooleanOrTestCallbackInterface::operator=(const UnsignedLongLongOrBooleanOrTestCallbackInterface&) = default;
-
-DEFINE_TRACE(UnsignedLongLongOrBooleanOrTestCallbackInterface) {
-  visitor->Trace(test_callback_interface_);
-}
-
-void V8UnsignedLongLongOrBooleanOrTestCallbackInterface::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, UnsignedLongLongOrBooleanOrTestCallbackInterface& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8TestCallbackInterface::hasInstance(v8Value, isolate)) {
-    TestCallbackInterface* cppValue = V8TestCallbackInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setTestCallbackInterface(cppValue);
-    return;
-  }
-
-  if (v8Value->IsBoolean()) {
-    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
-    return;
-  }
-
-  if (v8Value->IsNumber()) {
-    uint64_t cppValue = NativeValueTraits<IDLUnsignedLongLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setUnsignedLongLong(cppValue);
-    return;
-  }
-
-  {
-    uint64_t cppValue = NativeValueTraits<IDLUnsignedLongLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
-    if (exceptionState.HadException())
-      return;
-    impl.setUnsignedLongLong(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const UnsignedLongLongOrBooleanOrTestCallbackInterface& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeNone:
-      return v8::Null(isolate);
-    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeBoolean:
-      return v8::Boolean::New(isolate, impl.getAsBoolean());
-    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeTestCallbackInterface:
-      return ToV8(impl.getAsTestCallbackInterface(), creationContext, isolate);
-    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeUnsignedLongLong:
-      return v8::Number::New(isolate, static_cast<double>(impl.getAsUnsignedLongLong()));
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-UnsignedLongLongOrBooleanOrTestCallbackInterface NativeValueTraits<UnsignedLongLongOrBooleanOrTestCallbackInterface>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  UnsignedLongLongOrBooleanOrTestCallbackInterface impl;
-  V8UnsignedLongLongOrBooleanOrTestCallbackInterface::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestAttributeGetters.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestAttributeGetters.cpp
new file mode 100644
index 0000000..d40b1e2
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestAttributeGetters.cpp
@@ -0,0 +1,263 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/interface.cpp.tmpl
+
+// clang-format off
+#include "V8TestAttributeGetters.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ScriptPromise.h"
+#include "bindings/core/v8/V8DOMConfiguration.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/RuntimeCallStats.h"
+#include "platform/bindings/V8ObjectConstructor.h"
+#include "platform/wtf/GetPtr.h"
+#include "platform/wtf/RefPtr.h"
+
+namespace blink {
+
+// Suppress warning: global constructors, because struct WrapperTypeInfo is trivial
+// and does not depend on another global objects.
+#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+#endif
+const WrapperTypeInfo V8TestAttributeGetters::wrapperTypeInfo = {
+    gin::kEmbedderBlink,
+    V8TestAttributeGetters::domTemplate,
+    V8TestAttributeGetters::Trace,
+    V8TestAttributeGetters::TraceWrappers,
+    nullptr,
+    "TestAttributeGetters",
+    nullptr,
+    WrapperTypeInfo::kWrapperTypeObjectPrototype,
+    WrapperTypeInfo::kObjectClassId,
+    WrapperTypeInfo::kNotInheritFromActiveScriptWrappable,
+    WrapperTypeInfo::kIndependent,
+};
+#if defined(COMPONENT_BUILD) && defined(WIN32) && defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+// This static member must be declared by DEFINE_WRAPPERTYPEINFO in TestAttributeGetters.h.
+// For details, see the comment of DEFINE_WRAPPERTYPEINFO in
+// platform/bindings/ScriptWrappable.h.
+const WrapperTypeInfo& TestAttributeGetters::wrapper_type_info_ = V8TestAttributeGetters::wrapperTypeInfo;
+
+// not [ActiveScriptWrappable]
+static_assert(
+    !std::is_base_of<ActiveScriptWrappableBase, TestAttributeGetters>::value,
+    "TestAttributeGetters inherits from ActiveScriptWrappable<>, but is not specifying "
+    "[ActiveScriptWrappable] extended attribute in the IDL file.  "
+    "Be consistent.");
+static_assert(
+    std::is_same<decltype(&TestAttributeGetters::HasPendingActivity),
+                 decltype(&ScriptWrappable::HasPendingActivity)>::value,
+    "TestAttributeGetters is overriding hasPendingActivity(), but is not specifying "
+    "[ActiveScriptWrappable] extended attribute in the IDL file.  "
+    "Be consistent.");
+
+namespace TestAttributeGettersV8Internal {
+
+static void lenientThisLongAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  // [LenientThis]
+  // Make sure that info.Holder() really points to an instance if [LenientThis].
+  if (!V8TestAttributeGetters::hasInstance(info.Holder(), info.GetIsolate()))
+    return; // Return silently because of [LenientThis].
+
+  v8::Local<v8::Object> holder = info.Holder();
+
+  TestAttributeGetters* impl = V8TestAttributeGetters::toImpl(holder);
+
+  V8SetReturnValueInt(info, impl->lenientThisLongAttribute());
+}
+
+static void stringPromiseAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  // This attribute returns a Promise.
+  // Per https://heycam.github.io/webidl/#dfn-attribute-getter, all exceptions
+  // must be turned into a Promise rejection.
+  ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kGetterContext, "TestAttributeGetters", "stringPromiseAttribute");
+  ExceptionToRejectPromiseScope rejectPromiseScope(info, exceptionState);
+
+  // Returning a Promise type requires us to disable some of V8's type checks,
+  // so we have to manually check that info.Holder() really points to an
+  // instance of the type.
+  if (!V8TestAttributeGetters::hasInstance(info.Holder(), info.GetIsolate())) {
+    exceptionState.ThrowTypeError("Illegal invocation");
+    return;
+  }
+
+  v8::Local<v8::Object> holder = info.Holder();
+
+  TestAttributeGetters* impl = V8TestAttributeGetters::toImpl(holder);
+
+  V8SetReturnValue(info, impl->stringPromiseAttribute().V8Value());
+}
+
+static void lenientThisStringPromiseAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  // [LenientThis]
+  // Make sure that info.Holder() really points to an instance if [LenientThis].
+  if (!V8TestAttributeGetters::hasInstance(info.Holder(), info.GetIsolate()))
+    return; // Return silently because of [LenientThis].
+
+  v8::Local<v8::Object> holder = info.Holder();
+
+  TestAttributeGetters* impl = V8TestAttributeGetters::toImpl(holder);
+
+  V8SetReturnValue(info, impl->lenientThisStringPromiseAttribute().V8Value());
+}
+
+static void raisesExceptionShortPromiseAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  // This attribute returns a Promise.
+  // Per https://heycam.github.io/webidl/#dfn-attribute-getter, all exceptions
+  // must be turned into a Promise rejection.
+  ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kGetterContext, "TestAttributeGetters", "raisesExceptionShortPromiseAttribute");
+  ExceptionToRejectPromiseScope rejectPromiseScope(info, exceptionState);
+
+  // Returning a Promise type requires us to disable some of V8's type checks,
+  // so we have to manually check that info.Holder() really points to an
+  // instance of the type.
+  if (!V8TestAttributeGetters::hasInstance(info.Holder(), info.GetIsolate())) {
+    exceptionState.ThrowTypeError("Illegal invocation");
+    return;
+  }
+
+  v8::Local<v8::Object> holder = info.Holder();
+
+  TestAttributeGetters* impl = V8TestAttributeGetters::toImpl(holder);
+
+  ScriptPromise cppValue(impl->raisesExceptionShortPromiseAttribute(exceptionState));
+
+  if (UNLIKELY(exceptionState.HadException()))
+    return;
+
+  V8SetReturnValue(info, cppValue.V8Value());
+}
+
+static void floatAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  v8::Local<v8::Object> holder = info.Holder();
+
+  TestAttributeGetters* impl = V8TestAttributeGetters::toImpl(holder);
+
+  V8SetReturnValue(info, impl->floatAttribute());
+}
+
+} // namespace TestAttributeGettersV8Internal
+
+void V8TestAttributeGetters::lenientThisLongAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestAttributeGetters_lenientThisLongAttribute_Getter");
+
+  TestAttributeGettersV8Internal::lenientThisLongAttributeAttributeGetter(info);
+}
+
+void V8TestAttributeGetters::stringPromiseAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestAttributeGetters_stringPromiseAttribute_Getter");
+
+  TestAttributeGettersV8Internal::stringPromiseAttributeAttributeGetter(info);
+}
+
+void V8TestAttributeGetters::lenientThisStringPromiseAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestAttributeGetters_lenientThisStringPromiseAttribute_Getter");
+
+  TestAttributeGettersV8Internal::lenientThisStringPromiseAttributeAttributeGetter(info);
+}
+
+void V8TestAttributeGetters::raisesExceptionShortPromiseAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestAttributeGetters_raisesExceptionShortPromiseAttribute_Getter");
+
+  TestAttributeGettersV8Internal::raisesExceptionShortPromiseAttributeAttributeGetter(info);
+}
+
+void V8TestAttributeGetters::floatAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  RUNTIME_CALL_TIMER_SCOPE_DISABLED_BY_DEFAULT(info.GetIsolate(), "Blink_TestAttributeGetters_floatAttribute_Getter");
+
+  TestAttributeGettersV8Internal::floatAttributeAttributeGetter(info);
+}
+
+static const V8DOMConfiguration::AccessorConfiguration V8TestAttributeGettersAccessors[] = {
+    { "lenientThisLongAttribute", V8TestAttributeGetters::lenientThisLongAttributeAttributeGetterCallback, nullptr, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::ReadOnly), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kDoNotCheckHolder, V8DOMConfiguration::kAllWorlds },
+
+    { "stringPromiseAttribute", V8TestAttributeGetters::stringPromiseAttributeAttributeGetterCallback, nullptr, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::ReadOnly), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kDoNotCheckHolder, V8DOMConfiguration::kAllWorlds },
+
+    { "lenientThisStringPromiseAttribute", V8TestAttributeGetters::lenientThisStringPromiseAttributeAttributeGetterCallback, nullptr, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::ReadOnly), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kDoNotCheckHolder, V8DOMConfiguration::kAllWorlds },
+
+    { "raisesExceptionShortPromiseAttribute", V8TestAttributeGetters::raisesExceptionShortPromiseAttributeAttributeGetterCallback, nullptr, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::ReadOnly), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kDoNotCheckHolder, V8DOMConfiguration::kAllWorlds },
+
+    { "floatAttribute", V8TestAttributeGetters::floatAttributeAttributeGetterCallback, nullptr, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::ReadOnly), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kAllWorlds },
+};
+
+static void installV8TestAttributeGettersTemplate(
+    v8::Isolate* isolate,
+    const DOMWrapperWorld& world,
+    v8::Local<v8::FunctionTemplate> interfaceTemplate) {
+  // Initialize the interface object's template.
+  V8DOMConfiguration::InitializeDOMInterfaceTemplate(isolate, interfaceTemplate, V8TestAttributeGetters::wrapperTypeInfo.interface_name, v8::Local<v8::FunctionTemplate>(), V8TestAttributeGetters::internalFieldCount);
+
+  v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interfaceTemplate);
+  ALLOW_UNUSED_LOCAL(signature);
+  v8::Local<v8::ObjectTemplate> instanceTemplate = interfaceTemplate->InstanceTemplate();
+  ALLOW_UNUSED_LOCAL(instanceTemplate);
+  v8::Local<v8::ObjectTemplate> prototypeTemplate = interfaceTemplate->PrototypeTemplate();
+  ALLOW_UNUSED_LOCAL(prototypeTemplate);
+
+  // Register IDL constants, attributes and operations.
+  V8DOMConfiguration::InstallAccessors(
+      isolate, world, instanceTemplate, prototypeTemplate, interfaceTemplate,
+      signature, V8TestAttributeGettersAccessors, WTF_ARRAY_LENGTH(V8TestAttributeGettersAccessors));
+
+  // Custom signature
+
+  V8TestAttributeGetters::InstallRuntimeEnabledFeaturesOnTemplate(
+      isolate, world, interfaceTemplate);
+}
+
+void V8TestAttributeGetters::InstallRuntimeEnabledFeaturesOnTemplate(
+    v8::Isolate* isolate,
+    const DOMWrapperWorld& world,
+    v8::Local<v8::FunctionTemplate> interface_template) {
+  v8::Local<v8::Signature> signature = v8::Signature::New(isolate, interface_template);
+  ALLOW_UNUSED_LOCAL(signature);
+  v8::Local<v8::ObjectTemplate> instance_template = interface_template->InstanceTemplate();
+  ALLOW_UNUSED_LOCAL(instance_template);
+  v8::Local<v8::ObjectTemplate> prototype_template = interface_template->PrototypeTemplate();
+  ALLOW_UNUSED_LOCAL(prototype_template);
+
+  // Register IDL constants, attributes and operations.
+
+  // Custom signature
+}
+
+v8::Local<v8::FunctionTemplate> V8TestAttributeGetters::domTemplate(v8::Isolate* isolate, const DOMWrapperWorld& world) {
+  return V8DOMConfiguration::DomClassTemplate(isolate, world, const_cast<WrapperTypeInfo*>(&wrapperTypeInfo), installV8TestAttributeGettersTemplate);
+}
+
+bool V8TestAttributeGetters::hasInstance(v8::Local<v8::Value> v8Value, v8::Isolate* isolate) {
+  return V8PerIsolateData::From(isolate)->HasInstance(&wrapperTypeInfo, v8Value);
+}
+
+v8::Local<v8::Object> V8TestAttributeGetters::findInstanceInPrototypeChain(v8::Local<v8::Value> v8Value, v8::Isolate* isolate) {
+  return V8PerIsolateData::From(isolate)->FindInstanceInPrototypeChain(&wrapperTypeInfo, v8Value);
+}
+
+TestAttributeGetters* V8TestAttributeGetters::toImplWithTypeCheck(v8::Isolate* isolate, v8::Local<v8::Value> value) {
+  return hasInstance(value, isolate) ? toImpl(v8::Local<v8::Object>::Cast(value)) : nullptr;
+}
+
+TestAttributeGetters* NativeValueTraits<TestAttributeGetters>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  TestAttributeGetters* nativeValue = V8TestAttributeGetters::toImplWithTypeCheck(isolate, value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "TestAttributeGetters"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestAttributeGetters.h b/third_party/WebKit/Source/bindings/tests/results/core/V8TestAttributeGetters.h
new file mode 100644
index 0000000..455abe7
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestAttributeGetters.h
@@ -0,0 +1,73 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/interface.h.tmpl
+
+// clang-format off
+#ifndef V8TestAttributeGetters_h
+#define V8TestAttributeGetters_h
+
+#include "bindings/core/v8/GeneratedCodeHelper.h"
+#include "bindings/core/v8/NativeValueTraits.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/tests/idls/core/TestAttributeGetters.h"
+#include "core/CoreExport.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/bindings/V8DOMWrapper.h"
+#include "platform/bindings/WrapperTypeInfo.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class V8TestAttributeGetters {
+  STATIC_ONLY(V8TestAttributeGetters);
+ public:
+  CORE_EXPORT static bool hasInstance(v8::Local<v8::Value>, v8::Isolate*);
+  static v8::Local<v8::Object> findInstanceInPrototypeChain(v8::Local<v8::Value>, v8::Isolate*);
+  CORE_EXPORT static v8::Local<v8::FunctionTemplate> domTemplate(v8::Isolate*, const DOMWrapperWorld&);
+  static TestAttributeGetters* toImpl(v8::Local<v8::Object> object) {
+    return ToScriptWrappable(object)->ToImpl<TestAttributeGetters>();
+  }
+  CORE_EXPORT static TestAttributeGetters* toImplWithTypeCheck(v8::Isolate*, v8::Local<v8::Value>);
+  CORE_EXPORT static const WrapperTypeInfo wrapperTypeInfo;
+  static void Trace(Visitor* visitor, ScriptWrappable* scriptWrappable) {
+    visitor->TraceFromGeneratedCode(scriptWrappable->ToImpl<TestAttributeGetters>());
+  }
+  static void TraceWrappers(ScriptWrappableVisitor* visitor, ScriptWrappable* scriptWrappable) {
+    visitor->TraceWrappersFromGeneratedCode(scriptWrappable->ToImpl<TestAttributeGetters>());
+  }
+  static const int internalFieldCount = kV8DefaultWrapperInternalFieldCount;
+
+  // Callback functions
+
+  CORE_EXPORT static void lenientThisLongAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);
+  CORE_EXPORT static void stringPromiseAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);
+  CORE_EXPORT static void lenientThisStringPromiseAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);
+  CORE_EXPORT static void raisesExceptionShortPromiseAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);
+  CORE_EXPORT static void floatAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>&);
+
+  static void InstallRuntimeEnabledFeaturesOnTemplate(
+      v8::Isolate*,
+      const DOMWrapperWorld&,
+      v8::Local<v8::FunctionTemplate> interface_template);
+};
+
+template <>
+struct NativeValueTraits<TestAttributeGetters> : public NativeValueTraitsBase<TestAttributeGetters> {
+  CORE_EXPORT static TestAttributeGetters* NativeValue(v8::Isolate*, v8::Local<v8::Value>, ExceptionState&);
+};
+
+template <>
+struct V8TypeOf<TestAttributeGetters> {
+  typedef V8TestAttributeGetters Type;
+};
+
+}  // namespace blink
+
+#endif  // V8TestAttributeGetters_h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackFunctions.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackFunctions.cpp
index 67b1d6b1..a4b2052 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackFunctions.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestCallbackFunctions.cpp
@@ -11,13 +11,13 @@
 // clang-format off
 #include "V8TestCallbackFunctions.h"
 
-#include "bindings/core/v8/AnyCallbackFunctionOptionalAnyArg.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/LongCallbackFunction.h"
 #include "bindings/core/v8/NativeValueTraitsImpl.h"
 #include "bindings/core/v8/V8DOMConfiguration.h"
-#include "bindings/core/v8/VoidCallbackFunction.h"
+#include "bindings/core/v8/any_callback_function_optional_any_arg.h"
+#include "bindings/core/v8/long_callback_function.h"
+#include "bindings/core/v8/void_callback_function.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/html/custom/V0CustomElementProcessingStack.h"
 #include "platform/bindings/RuntimeCallStats.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.h b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.h
index 9e815f07..0b704350d 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.h
@@ -14,10 +14,10 @@
 
 #include "bindings/core/v8/GeneratedCodeHelper.h"
 #include "bindings/core/v8/NativeValueTraits.h"
-#include "bindings/core/v8/StringOrDouble.h"
 #include "bindings/core/v8/ToV8ForCore.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8TestInterfaceEmpty.h"
+#include "bindings/core/v8/string_or_double.h"
 #include "bindings/tests/idls/core/TestInterfaceImplementation.h"
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.h b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.h
index b2acbb29..7acb450 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor.h
@@ -13,10 +13,10 @@
 #define V8TestInterfaceConstructor_h
 
 #include "bindings/core/v8/GeneratedCodeHelper.h"
-#include "bindings/core/v8/LongOrTestDictionary.h"
 #include "bindings/core/v8/NativeValueTraits.h"
 #include "bindings/core/v8/ToV8ForCore.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/long_or_test_dictionary.h"
 #include "bindings/tests/idls/core/TestInterfaceConstructor.h"
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
index cd578ab..da3a311 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -911,6 +911,20 @@
 }
 
 static void promiseAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  // This attribute returns a Promise.
+  // Per https://heycam.github.io/webidl/#dfn-attribute-getter, all exceptions
+  // must be turned into a Promise rejection.
+  ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kGetterContext, "TestObject", "promiseAttribute");
+  ExceptionToRejectPromiseScope rejectPromiseScope(info, exceptionState);
+
+  // Returning a Promise type requires us to disable some of V8's type checks,
+  // so we have to manually check that info.Holder() really points to an
+  // instance of the type.
+  if (!V8TestObject::hasInstance(info.Holder(), info.GetIsolate())) {
+    exceptionState.ThrowTypeError("Illegal invocation");
+    return;
+  }
+
   v8::Local<v8::Object> holder = info.Holder();
 
   TestObject* impl = V8TestObject::toImpl(holder);
@@ -13242,7 +13256,7 @@
 
     { "anyAttribute", V8TestObject::anyAttributeAttributeGetterCallback, V8TestObject::anyAttributeAttributeSetterCallback, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::None), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kAllWorlds },
 
-    { "promiseAttribute", V8TestObject::promiseAttributeAttributeGetterCallback, V8TestObject::promiseAttributeAttributeSetterCallback, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::None), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kAllWorlds },
+    { "promiseAttribute", V8TestObject::promiseAttributeAttributeGetterCallback, V8TestObject::promiseAttributeAttributeSetterCallback, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::None), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kDoNotCheckHolder, V8DOMConfiguration::kAllWorlds },
 
     { "windowAttribute", V8TestObject::windowAttributeAttributeGetterCallback, V8TestObject::windowAttributeAttributeSetterCallback, V8PrivateProperty::kNoCachedAccessor, static_cast<v8::PropertyAttribute>(v8::None), V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kAllWorlds },
 
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.h b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.h
index f7ff0ec..0355550 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.h
@@ -12,24 +12,24 @@
 #ifndef V8TestObject_h
 #define V8TestObject_h
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferViewOrDictionary.h"
-#include "bindings/core/v8/BooleanOrElementSequence.h"
-#include "bindings/core/v8/BooleanOrStringOrUnrestrictedDouble.h"
-#include "bindings/core/v8/DoubleOrLongOrBooleanSequence.h"
-#include "bindings/core/v8/DoubleOrString.h"
-#include "bindings/core/v8/DoubleOrStringOrDoubleOrStringSequence.h"
-#include "bindings/core/v8/ElementSequenceOrByteStringDoubleOrStringRecord.h"
 #include "bindings/core/v8/GeneratedCodeHelper.h"
 #include "bindings/core/v8/NativeValueTraits.h"
-#include "bindings/core/v8/StringOrArrayBufferOrArrayBufferView.h"
-#include "bindings/core/v8/StringOrDouble.h"
-#include "bindings/core/v8/StringOrStringSequence.h"
-#include "bindings/core/v8/TestEnumOrDouble.h"
-#include "bindings/core/v8/TestInterfaceGarbageCollectedOrString.h"
-#include "bindings/core/v8/TestInterfaceOrLong.h"
 #include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrString.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view_or_dictionary.h"
+#include "bindings/core/v8/boolean_or_element_sequence.h"
+#include "bindings/core/v8/boolean_or_string_or_unrestricted_double.h"
+#include "bindings/core/v8/double_or_long_or_boolean_sequence.h"
+#include "bindings/core/v8/double_or_string.h"
+#include "bindings/core/v8/double_or_string_or_double_or_string_sequence.h"
+#include "bindings/core/v8/element_sequence_or_byte_string_double_or_string_record.h"
+#include "bindings/core/v8/string_or_array_buffer_or_array_buffer_view.h"
+#include "bindings/core/v8/string_or_double.h"
+#include "bindings/core/v8/string_or_string_sequence.h"
+#include "bindings/core/v8/test_enum_or_double.h"
+#include "bindings/core/v8/test_interface_garbage_collected_or_string.h"
+#include "bindings/core/v8/test_interface_or_long.h"
+#include "bindings/core/v8/unrestricted_double_or_string.h"
 #include "bindings/tests/idls/core/TestObject.h"
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.h b/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.h
index b2ebc1a..d693a0a 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.h
@@ -14,9 +14,9 @@
 
 #include "bindings/core/v8/GeneratedCodeHelper.h"
 #include "bindings/core/v8/NativeValueTraits.h"
-#include "bindings/core/v8/NodeOrNodeList.h"
 #include "bindings/core/v8/ToV8ForCore.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/node_or_node_list.h"
 #include "bindings/tests/idls/core/TestSpecialOperations.h"
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.h b/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.h
index ac64e2e..d875052 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.h
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.h
@@ -12,15 +12,15 @@
 #ifndef V8TestTypedefs_h
 #define V8TestTypedefs_h
 
-#include "bindings/core/v8/ByteStringSequenceSequenceOrByteStringByteStringRecord.h"
 #include "bindings/core/v8/GeneratedCodeHelper.h"
 #include "bindings/core/v8/NativeValueTraits.h"
-#include "bindings/core/v8/NestedUnionType.h"
-#include "bindings/core/v8/StringOrDouble.h"
-#include "bindings/core/v8/TestInterfaceOrTestInterfaceEmpty.h"
 #include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/UnsignedLongLongOrBooleanOrTestCallbackInterface.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
+#include "bindings/core/v8/nested_union_type.h"
+#include "bindings/core/v8/string_or_double.h"
+#include "bindings/core/v8/test_interface_or_test_interface_empty.h"
+#include "bindings/core/v8/unsigned_long_long_or_boolean_or_test_callback_interface.h"
 #include "bindings/tests/idls/core/TestTypedefs.h"
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.cpp
deleted file mode 100644
index 6e41217e..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "VoidCallbackFunction.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-VoidCallbackFunction* VoidCallbackFunction::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new VoidCallbackFunction(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-VoidCallbackFunction::VoidCallbackFunction(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(VoidCallbackFunction) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool VoidCallbackFunction::call(ScriptWrappable* scriptWrappable) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> *argv = nullptr;
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    0,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  return true;
-}
-
-VoidCallbackFunction* NativeValueTraits<VoidCallbackFunction>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  VoidCallbackFunction* nativeValue = VoidCallbackFunction::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "VoidCallbackFunction"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.cpp
deleted file mode 100644
index 3c8cfe2..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "VoidCallbackFunctionDictionaryArg.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "bindings/core/v8/V8TestDictionary.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-VoidCallbackFunctionDictionaryArg* VoidCallbackFunctionDictionaryArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new VoidCallbackFunctionDictionaryArg(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-VoidCallbackFunctionDictionaryArg::VoidCallbackFunctionDictionaryArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionDictionaryArg) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool VoidCallbackFunctionDictionaryArg::call(ScriptWrappable* scriptWrappable, const TestDictionary& arg) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate());
-  v8::Local<v8::Value> argv[] = { v8_arg };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    1,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  return true;
-}
-
-VoidCallbackFunctionDictionaryArg* NativeValueTraits<VoidCallbackFunctionDictionaryArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  VoidCallbackFunctionDictionaryArg* nativeValue = VoidCallbackFunctionDictionaryArg::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "VoidCallbackFunctionDictionaryArg"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.cpp
deleted file mode 100644
index f76c36c..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "VoidCallbackFunctionEnumArg.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-VoidCallbackFunctionEnumArg* VoidCallbackFunctionEnumArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new VoidCallbackFunctionEnumArg(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-VoidCallbackFunctionEnumArg::VoidCallbackFunctionEnumArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionEnumArg) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool VoidCallbackFunctionEnumArg::call(ScriptWrappable* scriptWrappable, const String& arg) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  const char* valid_arg_values[] = {
-      "",
-      "EnumValue1",
-      "EnumValue2",
-      "EnumValue3",
-  };
-  if (!IsValidEnum(arg, valid_arg_values, WTF_ARRAY_LENGTH(valid_arg_values), "TestEnum", exceptionState)) {
-    NOTREACHED();
-    return false;
-  }
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_arg = V8String(script_state_->GetIsolate(), arg);
-  v8::Local<v8::Value> argv[] = { v8_arg };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    1,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  return true;
-}
-
-VoidCallbackFunctionEnumArg* NativeValueTraits<VoidCallbackFunctionEnumArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  VoidCallbackFunctionEnumArg* nativeValue = VoidCallbackFunctionEnumArg::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "VoidCallbackFunctionEnumArg"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.cpp
deleted file mode 100644
index 599df36..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "VoidCallbackFunctionInterfaceArg.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "bindings/core/v8/V8HTMLDivElement.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-VoidCallbackFunctionInterfaceArg* VoidCallbackFunctionInterfaceArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new VoidCallbackFunctionInterfaceArg(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-VoidCallbackFunctionInterfaceArg::VoidCallbackFunctionInterfaceArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionInterfaceArg) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool VoidCallbackFunctionInterfaceArg::call(ScriptWrappable* scriptWrappable, HTMLDivElement* divElement) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_divElement = ToV8(divElement, script_state_->GetContext()->Global(), script_state_->GetIsolate());
-  v8::Local<v8::Value> argv[] = { v8_divElement };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    1,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  return true;
-}
-
-VoidCallbackFunctionInterfaceArg* NativeValueTraits<VoidCallbackFunctionInterfaceArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  VoidCallbackFunctionInterfaceArg* nativeValue = VoidCallbackFunctionInterfaceArg::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "VoidCallbackFunctionInterfaceArg"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.cpp
deleted file mode 100644
index 88dddb93..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "VoidCallbackFunctionTestInterfaceSequenceArg.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "bindings/core/v8/V8TestInterface.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-VoidCallbackFunctionTestInterfaceSequenceArg* VoidCallbackFunctionTestInterfaceSequenceArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new VoidCallbackFunctionTestInterfaceSequenceArg(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-VoidCallbackFunctionTestInterfaceSequenceArg::VoidCallbackFunctionTestInterfaceSequenceArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionTestInterfaceSequenceArg) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool VoidCallbackFunctionTestInterfaceSequenceArg::call(ScriptWrappable* scriptWrappable, const HeapVector<Member<TestInterfaceImplementation>>& arg) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate());
-  v8::Local<v8::Value> argv[] = { v8_arg };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    1,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  return true;
-}
-
-VoidCallbackFunctionTestInterfaceSequenceArg* NativeValueTraits<VoidCallbackFunctionTestInterfaceSequenceArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  VoidCallbackFunctionTestInterfaceSequenceArg* nativeValue = VoidCallbackFunctionTestInterfaceSequenceArg::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "VoidCallbackFunctionTestInterfaceSequenceArg"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.cpp b/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.cpp
deleted file mode 100644
index 5ed37e9..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "VoidCallbackFunctionTypedef.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-VoidCallbackFunctionTypedef* VoidCallbackFunctionTypedef::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new VoidCallbackFunctionTypedef(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-VoidCallbackFunctionTypedef::VoidCallbackFunctionTypedef(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionTypedef) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool VoidCallbackFunctionTypedef::call(ScriptWrappable* scriptWrappable, const String& arg) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> v8_arg = V8String(script_state_->GetIsolate(), arg);
-  v8::Local<v8::Value> argv[] = { v8_arg };
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    1,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  return true;
-}
-
-VoidCallbackFunctionTypedef* NativeValueTraits<VoidCallbackFunctionTypedef>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  VoidCallbackFunctionTypedef* nativeValue = VoidCallbackFunctionTypedef::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "VoidCallbackFunctionTypedef"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/XMLHttpRequestOrString.cpp b/third_party/WebKit/Source/bindings/tests/results/core/XMLHttpRequestOrString.cpp
deleted file mode 100644
index 0c07ae9..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/core/XMLHttpRequestOrString.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "XMLHttpRequestOrString.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8XMLHttpRequest.h"
-
-namespace blink {
-
-XMLHttpRequestOrString::XMLHttpRequestOrString() : type_(SpecificTypeNone) {}
-
-const String& XMLHttpRequestOrString::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void XMLHttpRequestOrString::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-XMLHttpRequestOrString XMLHttpRequestOrString::fromString(const String& value) {
-  XMLHttpRequestOrString container;
-  container.setString(value);
-  return container;
-}
-
-XMLHttpRequest* XMLHttpRequestOrString::getAsXMLHttpRequest() const {
-  DCHECK(isXMLHttpRequest());
-  return xml_http_request_;
-}
-
-void XMLHttpRequestOrString::setXMLHttpRequest(XMLHttpRequest* value) {
-  DCHECK(isNull());
-  xml_http_request_ = value;
-  type_ = SpecificTypeXMLHttpRequest;
-}
-
-XMLHttpRequestOrString XMLHttpRequestOrString::fromXMLHttpRequest(XMLHttpRequest* value) {
-  XMLHttpRequestOrString container;
-  container.setXMLHttpRequest(value);
-  return container;
-}
-
-XMLHttpRequestOrString::XMLHttpRequestOrString(const XMLHttpRequestOrString&) = default;
-XMLHttpRequestOrString::~XMLHttpRequestOrString() = default;
-XMLHttpRequestOrString& XMLHttpRequestOrString::operator=(const XMLHttpRequestOrString&) = default;
-
-DEFINE_TRACE(XMLHttpRequestOrString) {
-  visitor->Trace(xml_http_request_);
-}
-
-void V8XMLHttpRequestOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, XMLHttpRequestOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (V8XMLHttpRequest::hasInstance(v8Value, isolate)) {
-    XMLHttpRequest* cppValue = V8XMLHttpRequest::toImpl(v8::Local<v8::Object>::Cast(v8Value));
-    impl.setXMLHttpRequest(cppValue);
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const XMLHttpRequestOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case XMLHttpRequestOrString::SpecificTypeNone:
-      return v8::Null(isolate);
-    case XMLHttpRequestOrString::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    case XMLHttpRequestOrString::SpecificTypeXMLHttpRequest:
-      return ToV8(impl.getAsXMLHttpRequest(), creationContext, isolate);
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-XMLHttpRequestOrString NativeValueTraits<XMLHttpRequestOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  XMLHttpRequestOrString impl;
-  V8XMLHttpRequestOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/any_callback_function_optional_any_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/any_callback_function_optional_any_arg.cc
new file mode 100644
index 0000000..91eaf7ee
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/any_callback_function_optional_any_arg.cc
@@ -0,0 +1,96 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "any_callback_function_optional_any_arg.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ScriptValue.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+AnyCallbackFunctionOptionalAnyArg* AnyCallbackFunctionOptionalAnyArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new AnyCallbackFunctionOptionalAnyArg(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+AnyCallbackFunctionOptionalAnyArg::AnyCallbackFunctionOptionalAnyArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(AnyCallbackFunctionOptionalAnyArg) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool AnyCallbackFunctionOptionalAnyArg::call(ScriptWrappable* scriptWrappable, ScriptValue optionalAnyArg, ScriptValue& returnValue) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_optionalAnyArg = optionalAnyArg.V8Value();
+  v8::Local<v8::Value> argv[] = { v8_optionalAnyArg };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    1,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  ScriptValue cppValue = ScriptValue(ScriptState::Current(script_state_->GetIsolate()), v8ReturnValue);
+  returnValue = cppValue;
+  return true;
+}
+
+AnyCallbackFunctionOptionalAnyArg* NativeValueTraits<AnyCallbackFunctionOptionalAnyArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  AnyCallbackFunctionOptionalAnyArg* nativeValue = AnyCallbackFunctionOptionalAnyArg::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "AnyCallbackFunctionOptionalAnyArg"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.h b/third_party/WebKit/Source/bindings/tests/results/core/any_callback_function_optional_any_arg.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/AnyCallbackFunctionOptionalAnyArg.h
rename to third_party/WebKit/Source/bindings/tests/results/core/any_callback_function_optional_any_arg.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/array_buffer_or_array_buffer_view_or_dictionary.cc b/third_party/WebKit/Source/bindings/tests/results/core/array_buffer_or_array_buffer_view_or_dictionary.cc
new file mode 100644
index 0000000..5aba343
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/array_buffer_or_array_buffer_view_or_dictionary.cc
@@ -0,0 +1,136 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "array_buffer_or_array_buffer_view_or_dictionary.h"
+
+#include "bindings/core/v8/Dictionary.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8ArrayBuffer.h"
+
+namespace blink {
+
+ArrayBufferOrArrayBufferViewOrDictionary::ArrayBufferOrArrayBufferViewOrDictionary() : type_(SpecificTypeNone) {}
+
+TestArrayBuffer* ArrayBufferOrArrayBufferViewOrDictionary::getAsArrayBuffer() const {
+  DCHECK(isArrayBuffer());
+  return array_buffer_;
+}
+
+void ArrayBufferOrArrayBufferViewOrDictionary::setArrayBuffer(TestArrayBuffer* value) {
+  DCHECK(isNull());
+  array_buffer_ = value;
+  type_ = SpecificTypeArrayBuffer;
+}
+
+ArrayBufferOrArrayBufferViewOrDictionary ArrayBufferOrArrayBufferViewOrDictionary::fromArrayBuffer(TestArrayBuffer* value) {
+  ArrayBufferOrArrayBufferViewOrDictionary container;
+  container.setArrayBuffer(value);
+  return container;
+}
+
+NotShared<TestArrayBufferView> ArrayBufferOrArrayBufferViewOrDictionary::getAsArrayBufferView() const {
+  DCHECK(isArrayBufferView());
+  return array_buffer_view_;
+}
+
+void ArrayBufferOrArrayBufferViewOrDictionary::setArrayBufferView(NotShared<TestArrayBufferView> value) {
+  DCHECK(isNull());
+  array_buffer_view_ = Member<TestArrayBufferView>(value.View());
+  type_ = SpecificTypeArrayBufferView;
+}
+
+ArrayBufferOrArrayBufferViewOrDictionary ArrayBufferOrArrayBufferViewOrDictionary::fromArrayBufferView(NotShared<TestArrayBufferView> value) {
+  ArrayBufferOrArrayBufferViewOrDictionary container;
+  container.setArrayBufferView(value);
+  return container;
+}
+
+Dictionary ArrayBufferOrArrayBufferViewOrDictionary::getAsDictionary() const {
+  DCHECK(isDictionary());
+  return dictionary_;
+}
+
+void ArrayBufferOrArrayBufferViewOrDictionary::setDictionary(Dictionary value) {
+  DCHECK(isNull());
+  dictionary_ = value;
+  type_ = SpecificTypeDictionary;
+}
+
+ArrayBufferOrArrayBufferViewOrDictionary ArrayBufferOrArrayBufferViewOrDictionary::fromDictionary(Dictionary value) {
+  ArrayBufferOrArrayBufferViewOrDictionary container;
+  container.setDictionary(value);
+  return container;
+}
+
+ArrayBufferOrArrayBufferViewOrDictionary::ArrayBufferOrArrayBufferViewOrDictionary(const ArrayBufferOrArrayBufferViewOrDictionary&) = default;
+ArrayBufferOrArrayBufferViewOrDictionary::~ArrayBufferOrArrayBufferViewOrDictionary() = default;
+ArrayBufferOrArrayBufferViewOrDictionary& ArrayBufferOrArrayBufferViewOrDictionary::operator=(const ArrayBufferOrArrayBufferViewOrDictionary&) = default;
+
+DEFINE_TRACE(ArrayBufferOrArrayBufferViewOrDictionary) {
+  visitor->Trace(array_buffer_);
+  visitor->Trace(array_buffer_view_);
+}
+
+void V8ArrayBufferOrArrayBufferViewOrDictionary::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ArrayBufferOrArrayBufferViewOrDictionary& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsArrayBuffer()) {
+    TestArrayBuffer* cppValue = V8ArrayBuffer::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setArrayBuffer(cppValue);
+    return;
+  }
+
+  if (v8Value->IsArrayBufferView()) {
+    NotShared<TestArrayBufferView> cppValue = ToNotShared<NotShared<TestArrayBufferView>>(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setArrayBufferView(cppValue);
+    return;
+  }
+
+  if (IsUndefinedOrNull(v8Value) || v8Value->IsObject()) {
+    Dictionary cppValue = NativeValueTraits<Dictionary>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDictionary(cppValue);
+    return;
+  }
+
+  exceptionState.ThrowTypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView or Dictionary)'");
+}
+
+v8::Local<v8::Value> ToV8(const ArrayBufferOrArrayBufferViewOrDictionary& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeNone:
+      return v8::Null(isolate);
+    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeArrayBuffer:
+      return ToV8(impl.getAsArrayBuffer(), creationContext, isolate);
+    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeArrayBufferView:
+      return ToV8(impl.getAsArrayBufferView(), creationContext, isolate);
+    case ArrayBufferOrArrayBufferViewOrDictionary::SpecificTypeDictionary:
+      return impl.getAsDictionary().V8Value();
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+ArrayBufferOrArrayBufferViewOrDictionary NativeValueTraits<ArrayBufferOrArrayBufferViewOrDictionary>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  ArrayBufferOrArrayBufferViewOrDictionary impl;
+  V8ArrayBufferOrArrayBufferViewOrDictionary::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ArrayBufferOrArrayBufferViewOrDictionary.h b/third_party/WebKit/Source/bindings/tests/results/core/array_buffer_or_array_buffer_view_or_dictionary.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/ArrayBufferOrArrayBufferViewOrDictionary.h
rename to third_party/WebKit/Source/bindings/tests/results/core/array_buffer_or_array_buffer_view_or_dictionary.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_element_sequence.cc b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_element_sequence.cc
new file mode 100644
index 0000000..0e4cee0
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_element_sequence.cc
@@ -0,0 +1,116 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "boolean_or_element_sequence.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8Element.h"
+#include "core/animation/ElementAnimation.h"
+#include "core/dom/ChildNode.h"
+#include "core/dom/NonDocumentTypeChildNode.h"
+#include "core/dom/ParentNode.h"
+#include "core/fullscreen/ElementFullscreen.h"
+
+namespace blink {
+
+BooleanOrElementSequence::BooleanOrElementSequence() : type_(SpecificTypeNone) {}
+
+bool BooleanOrElementSequence::getAsBoolean() const {
+  DCHECK(isBoolean());
+  return boolean_;
+}
+
+void BooleanOrElementSequence::setBoolean(bool value) {
+  DCHECK(isNull());
+  boolean_ = value;
+  type_ = SpecificTypeBoolean;
+}
+
+BooleanOrElementSequence BooleanOrElementSequence::fromBoolean(bool value) {
+  BooleanOrElementSequence container;
+  container.setBoolean(value);
+  return container;
+}
+
+const HeapVector<Member<Element>>& BooleanOrElementSequence::getAsElementSequence() const {
+  DCHECK(isElementSequence());
+  return element_sequence_;
+}
+
+void BooleanOrElementSequence::setElementSequence(const HeapVector<Member<Element>>& value) {
+  DCHECK(isNull());
+  element_sequence_ = value;
+  type_ = SpecificTypeElementSequence;
+}
+
+BooleanOrElementSequence BooleanOrElementSequence::fromElementSequence(const HeapVector<Member<Element>>& value) {
+  BooleanOrElementSequence container;
+  container.setElementSequence(value);
+  return container;
+}
+
+BooleanOrElementSequence::BooleanOrElementSequence(const BooleanOrElementSequence&) = default;
+BooleanOrElementSequence::~BooleanOrElementSequence() = default;
+BooleanOrElementSequence& BooleanOrElementSequence::operator=(const BooleanOrElementSequence&) = default;
+
+DEFINE_TRACE(BooleanOrElementSequence) {
+  visitor->Trace(element_sequence_);
+}
+
+void V8BooleanOrElementSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrElementSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    HeapVector<Member<Element>> cppValue = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setElementSequence(cppValue);
+    return;
+  }
+
+  if (v8Value->IsBoolean()) {
+    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
+    return;
+  }
+
+  {
+    impl.setBoolean(v8Value->BooleanValue());
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const BooleanOrElementSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case BooleanOrElementSequence::SpecificTypeNone:
+      return v8::Null(isolate);
+    case BooleanOrElementSequence::SpecificTypeBoolean:
+      return v8::Boolean::New(isolate, impl.getAsBoolean());
+    case BooleanOrElementSequence::SpecificTypeElementSequence:
+      return ToV8(impl.getAsElementSequence(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+BooleanOrElementSequence NativeValueTraits<BooleanOrElementSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  BooleanOrElementSequence impl;
+  V8BooleanOrElementSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrElementSequence.h b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_element_sequence.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/BooleanOrElementSequence.h
rename to third_party/WebKit/Source/bindings/tests/results/core/boolean_or_element_sequence.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_string_or_unrestricted_double.cc b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_string_or_unrestricted_double.cc
new file mode 100644
index 0000000..1994c062e
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_string_or_unrestricted_double.cc
@@ -0,0 +1,131 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "boolean_or_string_or_unrestricted_double.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+BooleanOrStringOrUnrestrictedDouble::BooleanOrStringOrUnrestrictedDouble() : type_(SpecificTypeNone) {}
+
+bool BooleanOrStringOrUnrestrictedDouble::getAsBoolean() const {
+  DCHECK(isBoolean());
+  return boolean_;
+}
+
+void BooleanOrStringOrUnrestrictedDouble::setBoolean(bool value) {
+  DCHECK(isNull());
+  boolean_ = value;
+  type_ = SpecificTypeBoolean;
+}
+
+BooleanOrStringOrUnrestrictedDouble BooleanOrStringOrUnrestrictedDouble::fromBoolean(bool value) {
+  BooleanOrStringOrUnrestrictedDouble container;
+  container.setBoolean(value);
+  return container;
+}
+
+const String& BooleanOrStringOrUnrestrictedDouble::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void BooleanOrStringOrUnrestrictedDouble::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+BooleanOrStringOrUnrestrictedDouble BooleanOrStringOrUnrestrictedDouble::fromString(const String& value) {
+  BooleanOrStringOrUnrestrictedDouble container;
+  container.setString(value);
+  return container;
+}
+
+double BooleanOrStringOrUnrestrictedDouble::getAsUnrestrictedDouble() const {
+  DCHECK(isUnrestrictedDouble());
+  return unrestricted_double_;
+}
+
+void BooleanOrStringOrUnrestrictedDouble::setUnrestrictedDouble(double value) {
+  DCHECK(isNull());
+  unrestricted_double_ = value;
+  type_ = SpecificTypeUnrestrictedDouble;
+}
+
+BooleanOrStringOrUnrestrictedDouble BooleanOrStringOrUnrestrictedDouble::fromUnrestrictedDouble(double value) {
+  BooleanOrStringOrUnrestrictedDouble container;
+  container.setUnrestrictedDouble(value);
+  return container;
+}
+
+BooleanOrStringOrUnrestrictedDouble::BooleanOrStringOrUnrestrictedDouble(const BooleanOrStringOrUnrestrictedDouble&) = default;
+BooleanOrStringOrUnrestrictedDouble::~BooleanOrStringOrUnrestrictedDouble() = default;
+BooleanOrStringOrUnrestrictedDouble& BooleanOrStringOrUnrestrictedDouble::operator=(const BooleanOrStringOrUnrestrictedDouble&) = default;
+
+DEFINE_TRACE(BooleanOrStringOrUnrestrictedDouble) {
+}
+
+void V8BooleanOrStringOrUnrestrictedDouble::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrStringOrUnrestrictedDouble& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsBoolean()) {
+    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    double cppValue = NativeValueTraits<IDLUnrestrictedDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setUnrestrictedDouble(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const BooleanOrStringOrUnrestrictedDouble& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeNone:
+      return v8::Null(isolate);
+    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeBoolean:
+      return v8::Boolean::New(isolate, impl.getAsBoolean());
+    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    case BooleanOrStringOrUnrestrictedDouble::SpecificTypeUnrestrictedDouble:
+      return v8::Number::New(isolate, impl.getAsUnrestrictedDouble());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+BooleanOrStringOrUnrestrictedDouble NativeValueTraits<BooleanOrStringOrUnrestrictedDouble>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  BooleanOrStringOrUnrestrictedDouble impl;
+  V8BooleanOrStringOrUnrestrictedDouble::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrStringOrUnrestrictedDouble.h b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_string_or_unrestricted_double.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/BooleanOrStringOrUnrestrictedDouble.h
rename to third_party/WebKit/Source/bindings/tests/results/core/boolean_or_string_or_unrestricted_double.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_test_callback_interface.cc b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_test_callback_interface.cc
new file mode 100644
index 0000000..68c2ba6
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_test_callback_interface.cc
@@ -0,0 +1,109 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "boolean_or_test_callback_interface.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8TestCallbackInterface.h"
+
+namespace blink {
+
+BooleanOrTestCallbackInterface::BooleanOrTestCallbackInterface() : type_(SpecificTypeNone) {}
+
+bool BooleanOrTestCallbackInterface::getAsBoolean() const {
+  DCHECK(isBoolean());
+  return boolean_;
+}
+
+void BooleanOrTestCallbackInterface::setBoolean(bool value) {
+  DCHECK(isNull());
+  boolean_ = value;
+  type_ = SpecificTypeBoolean;
+}
+
+BooleanOrTestCallbackInterface BooleanOrTestCallbackInterface::fromBoolean(bool value) {
+  BooleanOrTestCallbackInterface container;
+  container.setBoolean(value);
+  return container;
+}
+
+TestCallbackInterface* BooleanOrTestCallbackInterface::getAsTestCallbackInterface() const {
+  DCHECK(isTestCallbackInterface());
+  return test_callback_interface_;
+}
+
+void BooleanOrTestCallbackInterface::setTestCallbackInterface(TestCallbackInterface* value) {
+  DCHECK(isNull());
+  test_callback_interface_ = value;
+  type_ = SpecificTypeTestCallbackInterface;
+}
+
+BooleanOrTestCallbackInterface BooleanOrTestCallbackInterface::fromTestCallbackInterface(TestCallbackInterface* value) {
+  BooleanOrTestCallbackInterface container;
+  container.setTestCallbackInterface(value);
+  return container;
+}
+
+BooleanOrTestCallbackInterface::BooleanOrTestCallbackInterface(const BooleanOrTestCallbackInterface&) = default;
+BooleanOrTestCallbackInterface::~BooleanOrTestCallbackInterface() = default;
+BooleanOrTestCallbackInterface& BooleanOrTestCallbackInterface::operator=(const BooleanOrTestCallbackInterface&) = default;
+
+DEFINE_TRACE(BooleanOrTestCallbackInterface) {
+  visitor->Trace(test_callback_interface_);
+}
+
+void V8BooleanOrTestCallbackInterface::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrTestCallbackInterface& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8TestCallbackInterface::hasInstance(v8Value, isolate)) {
+    TestCallbackInterface* cppValue = V8TestCallbackInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setTestCallbackInterface(cppValue);
+    return;
+  }
+
+  if (v8Value->IsBoolean()) {
+    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
+    return;
+  }
+
+  {
+    impl.setBoolean(v8Value->BooleanValue());
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const BooleanOrTestCallbackInterface& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case BooleanOrTestCallbackInterface::SpecificTypeNone:
+      return v8::Null(isolate);
+    case BooleanOrTestCallbackInterface::SpecificTypeBoolean:
+      return v8::Boolean::New(isolate, impl.getAsBoolean());
+    case BooleanOrTestCallbackInterface::SpecificTypeTestCallbackInterface:
+      return ToV8(impl.getAsTestCallbackInterface(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+BooleanOrTestCallbackInterface NativeValueTraits<BooleanOrTestCallbackInterface>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  BooleanOrTestCallbackInterface impl;
+  V8BooleanOrTestCallbackInterface::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/BooleanOrTestCallbackInterface.h b/third_party/WebKit/Source/bindings/tests/results/core/boolean_or_test_callback_interface.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/BooleanOrTestCallbackInterface.h
rename to third_party/WebKit/Source/bindings/tests/results/core/boolean_or_test_callback_interface.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/byte_string_or_node_list.cc b/third_party/WebKit/Source/bindings/tests/results/core/byte_string_or_node_list.cc
new file mode 100644
index 0000000..866b134
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/byte_string_or_node_list.cc
@@ -0,0 +1,111 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "byte_string_or_node_list.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8NodeList.h"
+#include "core/dom/NameNodeList.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/StaticNodeList.h"
+#include "core/html/LabelsNodeList.h"
+
+namespace blink {
+
+ByteStringOrNodeList::ByteStringOrNodeList() : type_(SpecificTypeNone) {}
+
+const String& ByteStringOrNodeList::getAsByteString() const {
+  DCHECK(isByteString());
+  return byte_string_;
+}
+
+void ByteStringOrNodeList::setByteString(const String& value) {
+  DCHECK(isNull());
+  byte_string_ = value;
+  type_ = SpecificTypeByteString;
+}
+
+ByteStringOrNodeList ByteStringOrNodeList::fromByteString(const String& value) {
+  ByteStringOrNodeList container;
+  container.setByteString(value);
+  return container;
+}
+
+NodeList* ByteStringOrNodeList::getAsNodeList() const {
+  DCHECK(isNodeList());
+  return node_list_;
+}
+
+void ByteStringOrNodeList::setNodeList(NodeList* value) {
+  DCHECK(isNull());
+  node_list_ = value;
+  type_ = SpecificTypeNodeList;
+}
+
+ByteStringOrNodeList ByteStringOrNodeList::fromNodeList(NodeList* value) {
+  ByteStringOrNodeList container;
+  container.setNodeList(value);
+  return container;
+}
+
+ByteStringOrNodeList::ByteStringOrNodeList(const ByteStringOrNodeList&) = default;
+ByteStringOrNodeList::~ByteStringOrNodeList() = default;
+ByteStringOrNodeList& ByteStringOrNodeList::operator=(const ByteStringOrNodeList&) = default;
+
+DEFINE_TRACE(ByteStringOrNodeList) {
+  visitor->Trace(node_list_);
+}
+
+void V8ByteStringOrNodeList::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ByteStringOrNodeList& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8NodeList::hasInstance(v8Value, isolate)) {
+    NodeList* cppValue = V8NodeList::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setNodeList(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = NativeValueTraits<IDLByteString>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setByteString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const ByteStringOrNodeList& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case ByteStringOrNodeList::SpecificTypeNone:
+      return v8::Null(isolate);
+    case ByteStringOrNodeList::SpecificTypeByteString:
+      return V8String(isolate, impl.getAsByteString());
+    case ByteStringOrNodeList::SpecificTypeNodeList:
+      return ToV8(impl.getAsNodeList(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+ByteStringOrNodeList NativeValueTraits<ByteStringOrNodeList>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  ByteStringOrNodeList impl;
+  V8ByteStringOrNodeList::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ByteStringOrNodeList.h b/third_party/WebKit/Source/bindings/tests/results/core/byte_string_or_node_list.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/ByteStringOrNodeList.h
rename to third_party/WebKit/Source/bindings/tests/results/core/byte_string_or_node_list.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/byte_string_sequence_sequence_or_byte_string_byte_string_record.cc b/third_party/WebKit/Source/bindings/tests/results/core/byte_string_sequence_sequence_or_byte_string_byte_string_record.cc
new file mode 100644
index 0000000..e4f8291
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/byte_string_sequence_sequence_or_byte_string_byte_string_record.cc
@@ -0,0 +1,109 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+ByteStringSequenceSequenceOrByteStringByteStringRecord::ByteStringSequenceSequenceOrByteStringByteStringRecord() : type_(SpecificTypeNone) {}
+
+const Vector<std::pair<String, String>>& ByteStringSequenceSequenceOrByteStringByteStringRecord::getAsByteStringByteStringRecord() const {
+  DCHECK(isByteStringByteStringRecord());
+  return byte_string_byte_string_record_;
+}
+
+void ByteStringSequenceSequenceOrByteStringByteStringRecord::setByteStringByteStringRecord(const Vector<std::pair<String, String>>& value) {
+  DCHECK(isNull());
+  byte_string_byte_string_record_ = value;
+  type_ = SpecificTypeByteStringByteStringRecord;
+}
+
+ByteStringSequenceSequenceOrByteStringByteStringRecord ByteStringSequenceSequenceOrByteStringByteStringRecord::fromByteStringByteStringRecord(const Vector<std::pair<String, String>>& value) {
+  ByteStringSequenceSequenceOrByteStringByteStringRecord container;
+  container.setByteStringByteStringRecord(value);
+  return container;
+}
+
+const Vector<Vector<String>>& ByteStringSequenceSequenceOrByteStringByteStringRecord::getAsByteStringSequenceSequence() const {
+  DCHECK(isByteStringSequenceSequence());
+  return byte_string_sequence_sequence_;
+}
+
+void ByteStringSequenceSequenceOrByteStringByteStringRecord::setByteStringSequenceSequence(const Vector<Vector<String>>& value) {
+  DCHECK(isNull());
+  byte_string_sequence_sequence_ = value;
+  type_ = SpecificTypeByteStringSequenceSequence;
+}
+
+ByteStringSequenceSequenceOrByteStringByteStringRecord ByteStringSequenceSequenceOrByteStringByteStringRecord::fromByteStringSequenceSequence(const Vector<Vector<String>>& value) {
+  ByteStringSequenceSequenceOrByteStringByteStringRecord container;
+  container.setByteStringSequenceSequence(value);
+  return container;
+}
+
+ByteStringSequenceSequenceOrByteStringByteStringRecord::ByteStringSequenceSequenceOrByteStringByteStringRecord(const ByteStringSequenceSequenceOrByteStringByteStringRecord&) = default;
+ByteStringSequenceSequenceOrByteStringByteStringRecord::~ByteStringSequenceSequenceOrByteStringByteStringRecord() = default;
+ByteStringSequenceSequenceOrByteStringByteStringRecord& ByteStringSequenceSequenceOrByteStringByteStringRecord::operator=(const ByteStringSequenceSequenceOrByteStringByteStringRecord&) = default;
+
+DEFINE_TRACE(ByteStringSequenceSequenceOrByteStringByteStringRecord) {
+}
+
+void V8ByteStringSequenceSequenceOrByteStringByteStringRecord::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ByteStringSequenceSequenceOrByteStringByteStringRecord& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    Vector<Vector<String>> cppValue = NativeValueTraits<IDLSequence<IDLSequence<IDLByteString>>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setByteStringSequenceSequence(cppValue);
+    return;
+  }
+
+  if (v8Value->IsObject()) {
+    Vector<std::pair<String, String>> cppValue = NativeValueTraits<IDLRecord<IDLByteString, IDLByteString>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setByteStringByteStringRecord(cppValue);
+    return;
+  }
+
+  exceptionState.ThrowTypeError("The provided value is not of type '(sequence<sequence<ByteString>> or record<ByteString, ByteString>)'");
+}
+
+v8::Local<v8::Value> ToV8(const ByteStringSequenceSequenceOrByteStringByteStringRecord& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case ByteStringSequenceSequenceOrByteStringByteStringRecord::SpecificTypeNone:
+      return v8::Null(isolate);
+    case ByteStringSequenceSequenceOrByteStringByteStringRecord::SpecificTypeByteStringByteStringRecord:
+      return ToV8(impl.getAsByteStringByteStringRecord(), creationContext, isolate);
+    case ByteStringSequenceSequenceOrByteStringByteStringRecord::SpecificTypeByteStringSequenceSequence:
+      return ToV8(impl.getAsByteStringSequenceSequence(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+ByteStringSequenceSequenceOrByteStringByteStringRecord NativeValueTraits<ByteStringSequenceSequenceOrByteStringByteStringRecord>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  ByteStringSequenceSequenceOrByteStringByteStringRecord impl;
+  V8ByteStringSequenceSequenceOrByteStringByteStringRecord::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ByteStringSequenceSequenceOrByteStringByteStringRecord.h b/third_party/WebKit/Source/bindings/tests/results/core/byte_string_sequence_sequence_or_byte_string_byte_string_record.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/ByteStringSequenceSequenceOrByteStringByteStringRecord.h
rename to third_party/WebKit/Source/bindings/tests/results/core/byte_string_sequence_sequence_or_byte_string_byte_string_record.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/double_or_long_or_boolean_sequence.cc b/third_party/WebKit/Source/bindings/tests/results/core/double_or_long_or_boolean_sequence.cc
new file mode 100644
index 0000000..2dd3504
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/double_or_long_or_boolean_sequence.cc
@@ -0,0 +1,117 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "double_or_long_or_boolean_sequence.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/long_or_boolean.h"
+
+namespace blink {
+
+DoubleOrLongOrBooleanSequence::DoubleOrLongOrBooleanSequence() : type_(SpecificTypeNone) {}
+
+double DoubleOrLongOrBooleanSequence::getAsDouble() const {
+  DCHECK(isDouble());
+  return double_;
+}
+
+void DoubleOrLongOrBooleanSequence::setDouble(double value) {
+  DCHECK(isNull());
+  double_ = value;
+  type_ = SpecificTypeDouble;
+}
+
+DoubleOrLongOrBooleanSequence DoubleOrLongOrBooleanSequence::fromDouble(double value) {
+  DoubleOrLongOrBooleanSequence container;
+  container.setDouble(value);
+  return container;
+}
+
+const HeapVector<LongOrBoolean>& DoubleOrLongOrBooleanSequence::getAsLongOrBooleanSequence() const {
+  DCHECK(isLongOrBooleanSequence());
+  return long_or_boolean_sequence_;
+}
+
+void DoubleOrLongOrBooleanSequence::setLongOrBooleanSequence(const HeapVector<LongOrBoolean>& value) {
+  DCHECK(isNull());
+  long_or_boolean_sequence_ = value;
+  type_ = SpecificTypeLongOrBooleanSequence;
+}
+
+DoubleOrLongOrBooleanSequence DoubleOrLongOrBooleanSequence::fromLongOrBooleanSequence(const HeapVector<LongOrBoolean>& value) {
+  DoubleOrLongOrBooleanSequence container;
+  container.setLongOrBooleanSequence(value);
+  return container;
+}
+
+DoubleOrLongOrBooleanSequence::DoubleOrLongOrBooleanSequence(const DoubleOrLongOrBooleanSequence&) = default;
+DoubleOrLongOrBooleanSequence::~DoubleOrLongOrBooleanSequence() = default;
+DoubleOrLongOrBooleanSequence& DoubleOrLongOrBooleanSequence::operator=(const DoubleOrLongOrBooleanSequence&) = default;
+
+DEFINE_TRACE(DoubleOrLongOrBooleanSequence) {
+  visitor->Trace(long_or_boolean_sequence_);
+}
+
+void V8DoubleOrLongOrBooleanSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, DoubleOrLongOrBooleanSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    HeapVector<LongOrBoolean> cppValue = NativeValueTraits<IDLSequence<LongOrBoolean>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setLongOrBooleanSequence(cppValue);
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDouble(cppValue);
+    return;
+  }
+
+  {
+    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDouble(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const DoubleOrLongOrBooleanSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case DoubleOrLongOrBooleanSequence::SpecificTypeNone:
+      return v8::Null(isolate);
+    case DoubleOrLongOrBooleanSequence::SpecificTypeDouble:
+      return v8::Number::New(isolate, impl.getAsDouble());
+    case DoubleOrLongOrBooleanSequence::SpecificTypeLongOrBooleanSequence:
+      return ToV8(impl.getAsLongOrBooleanSequence(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+DoubleOrLongOrBooleanSequence NativeValueTraits<DoubleOrLongOrBooleanSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  DoubleOrLongOrBooleanSequence impl;
+  V8DoubleOrLongOrBooleanSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrLongOrBooleanSequence.h b/third_party/WebKit/Source/bindings/tests/results/core/double_or_long_or_boolean_sequence.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/DoubleOrLongOrBooleanSequence.h
rename to third_party/WebKit/Source/bindings/tests/results/core/double_or_long_or_boolean_sequence.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/double_or_string.cc b/third_party/WebKit/Source/bindings/tests/results/core/double_or_string.cc
new file mode 100644
index 0000000..38ec799b
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/double_or_string.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "double_or_string.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+DoubleOrString::DoubleOrString() : type_(SpecificTypeNone) {}
+
+double DoubleOrString::getAsDouble() const {
+  DCHECK(isDouble());
+  return double_;
+}
+
+void DoubleOrString::setDouble(double value) {
+  DCHECK(isNull());
+  double_ = value;
+  type_ = SpecificTypeDouble;
+}
+
+DoubleOrString DoubleOrString::fromDouble(double value) {
+  DoubleOrString container;
+  container.setDouble(value);
+  return container;
+}
+
+const String& DoubleOrString::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void DoubleOrString::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+DoubleOrString DoubleOrString::fromString(const String& value) {
+  DoubleOrString container;
+  container.setString(value);
+  return container;
+}
+
+DoubleOrString::DoubleOrString(const DoubleOrString&) = default;
+DoubleOrString::~DoubleOrString() = default;
+DoubleOrString& DoubleOrString::operator=(const DoubleOrString&) = default;
+
+DEFINE_TRACE(DoubleOrString) {
+}
+
+void V8DoubleOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, DoubleOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsNumber()) {
+    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDouble(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const DoubleOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case DoubleOrString::SpecificTypeNone:
+      return v8::Null(isolate);
+    case DoubleOrString::SpecificTypeDouble:
+      return v8::Number::New(isolate, impl.getAsDouble());
+    case DoubleOrString::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+DoubleOrString NativeValueTraits<DoubleOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  DoubleOrString impl;
+  V8DoubleOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrString.h b/third_party/WebKit/Source/bindings/tests/results/core/double_or_string.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/DoubleOrString.h
rename to third_party/WebKit/Source/bindings/tests/results/core/double_or_string.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/double_or_string_or_double_or_string_sequence.cc b/third_party/WebKit/Source/bindings/tests/results/core/double_or_string_or_double_or_string_sequence.cc
new file mode 100644
index 0000000..078dd367
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/double_or_string_or_double_or_string_sequence.cc
@@ -0,0 +1,136 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "double_or_string_or_double_or_string_sequence.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/double_or_string.h"
+
+namespace blink {
+
+DoubleOrStringOrDoubleOrStringSequence::DoubleOrStringOrDoubleOrStringSequence() : type_(SpecificTypeNone) {}
+
+double DoubleOrStringOrDoubleOrStringSequence::getAsDouble() const {
+  DCHECK(isDouble());
+  return double_;
+}
+
+void DoubleOrStringOrDoubleOrStringSequence::setDouble(double value) {
+  DCHECK(isNull());
+  double_ = value;
+  type_ = SpecificTypeDouble;
+}
+
+DoubleOrStringOrDoubleOrStringSequence DoubleOrStringOrDoubleOrStringSequence::fromDouble(double value) {
+  DoubleOrStringOrDoubleOrStringSequence container;
+  container.setDouble(value);
+  return container;
+}
+
+const HeapVector<DoubleOrString>& DoubleOrStringOrDoubleOrStringSequence::getAsDoubleOrStringSequence() const {
+  DCHECK(isDoubleOrStringSequence());
+  return double_or_string_sequence_;
+}
+
+void DoubleOrStringOrDoubleOrStringSequence::setDoubleOrStringSequence(const HeapVector<DoubleOrString>& value) {
+  DCHECK(isNull());
+  double_or_string_sequence_ = value;
+  type_ = SpecificTypeDoubleOrStringSequence;
+}
+
+DoubleOrStringOrDoubleOrStringSequence DoubleOrStringOrDoubleOrStringSequence::fromDoubleOrStringSequence(const HeapVector<DoubleOrString>& value) {
+  DoubleOrStringOrDoubleOrStringSequence container;
+  container.setDoubleOrStringSequence(value);
+  return container;
+}
+
+const String& DoubleOrStringOrDoubleOrStringSequence::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void DoubleOrStringOrDoubleOrStringSequence::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+DoubleOrStringOrDoubleOrStringSequence DoubleOrStringOrDoubleOrStringSequence::fromString(const String& value) {
+  DoubleOrStringOrDoubleOrStringSequence container;
+  container.setString(value);
+  return container;
+}
+
+DoubleOrStringOrDoubleOrStringSequence::DoubleOrStringOrDoubleOrStringSequence(const DoubleOrStringOrDoubleOrStringSequence&) = default;
+DoubleOrStringOrDoubleOrStringSequence::~DoubleOrStringOrDoubleOrStringSequence() = default;
+DoubleOrStringOrDoubleOrStringSequence& DoubleOrStringOrDoubleOrStringSequence::operator=(const DoubleOrStringOrDoubleOrStringSequence&) = default;
+
+DEFINE_TRACE(DoubleOrStringOrDoubleOrStringSequence) {
+  visitor->Trace(double_or_string_sequence_);
+}
+
+void V8DoubleOrStringOrDoubleOrStringSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, DoubleOrStringOrDoubleOrStringSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    HeapVector<DoubleOrString> cppValue = NativeValueTraits<IDLSequence<DoubleOrString>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDoubleOrStringSequence(cppValue);
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDouble(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const DoubleOrStringOrDoubleOrStringSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeNone:
+      return v8::Null(isolate);
+    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeDouble:
+      return v8::Number::New(isolate, impl.getAsDouble());
+    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeDoubleOrStringSequence:
+      return ToV8(impl.getAsDoubleOrStringSequence(), creationContext, isolate);
+    case DoubleOrStringOrDoubleOrStringSequence::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+DoubleOrStringOrDoubleOrStringSequence NativeValueTraits<DoubleOrStringOrDoubleOrStringSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  DoubleOrStringOrDoubleOrStringSequence impl;
+  V8DoubleOrStringOrDoubleOrStringSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/DoubleOrStringOrDoubleOrStringSequence.h b/third_party/WebKit/Source/bindings/tests/results/core/double_or_string_or_double_or_string_sequence.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/DoubleOrStringOrDoubleOrStringSequence.h
rename to third_party/WebKit/Source/bindings/tests/results/core/double_or_string_or_double_or_string_sequence.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/element_sequence_or_byte_string_double_or_string_record.cc b/third_party/WebKit/Source/bindings/tests/results/core/element_sequence_or_byte_string_double_or_string_record.cc
new file mode 100644
index 0000000..2fb81e42a
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/element_sequence_or_byte_string_double_or_string_record.cc
@@ -0,0 +1,118 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "element_sequence_or_byte_string_double_or_string_record.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8Element.h"
+#include "bindings/core/v8/double_or_string.h"
+#include "core/animation/ElementAnimation.h"
+#include "core/dom/ChildNode.h"
+#include "core/dom/NonDocumentTypeChildNode.h"
+#include "core/dom/ParentNode.h"
+#include "core/fullscreen/ElementFullscreen.h"
+
+namespace blink {
+
+ElementSequenceOrByteStringDoubleOrStringRecord::ElementSequenceOrByteStringDoubleOrStringRecord() : type_(SpecificTypeNone) {}
+
+const HeapVector<std::pair<String, DoubleOrString>>& ElementSequenceOrByteStringDoubleOrStringRecord::getAsByteStringDoubleOrStringRecord() const {
+  DCHECK(isByteStringDoubleOrStringRecord());
+  return byte_string_double_or_string_record_;
+}
+
+void ElementSequenceOrByteStringDoubleOrStringRecord::setByteStringDoubleOrStringRecord(const HeapVector<std::pair<String, DoubleOrString>>& value) {
+  DCHECK(isNull());
+  byte_string_double_or_string_record_ = value;
+  type_ = SpecificTypeByteStringDoubleOrStringRecord;
+}
+
+ElementSequenceOrByteStringDoubleOrStringRecord ElementSequenceOrByteStringDoubleOrStringRecord::fromByteStringDoubleOrStringRecord(const HeapVector<std::pair<String, DoubleOrString>>& value) {
+  ElementSequenceOrByteStringDoubleOrStringRecord container;
+  container.setByteStringDoubleOrStringRecord(value);
+  return container;
+}
+
+const HeapVector<Member<Element>>& ElementSequenceOrByteStringDoubleOrStringRecord::getAsElementSequence() const {
+  DCHECK(isElementSequence());
+  return element_sequence_;
+}
+
+void ElementSequenceOrByteStringDoubleOrStringRecord::setElementSequence(const HeapVector<Member<Element>>& value) {
+  DCHECK(isNull());
+  element_sequence_ = value;
+  type_ = SpecificTypeElementSequence;
+}
+
+ElementSequenceOrByteStringDoubleOrStringRecord ElementSequenceOrByteStringDoubleOrStringRecord::fromElementSequence(const HeapVector<Member<Element>>& value) {
+  ElementSequenceOrByteStringDoubleOrStringRecord container;
+  container.setElementSequence(value);
+  return container;
+}
+
+ElementSequenceOrByteStringDoubleOrStringRecord::ElementSequenceOrByteStringDoubleOrStringRecord(const ElementSequenceOrByteStringDoubleOrStringRecord&) = default;
+ElementSequenceOrByteStringDoubleOrStringRecord::~ElementSequenceOrByteStringDoubleOrStringRecord() = default;
+ElementSequenceOrByteStringDoubleOrStringRecord& ElementSequenceOrByteStringDoubleOrStringRecord::operator=(const ElementSequenceOrByteStringDoubleOrStringRecord&) = default;
+
+DEFINE_TRACE(ElementSequenceOrByteStringDoubleOrStringRecord) {
+  visitor->Trace(byte_string_double_or_string_record_);
+  visitor->Trace(element_sequence_);
+}
+
+void V8ElementSequenceOrByteStringDoubleOrStringRecord::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, ElementSequenceOrByteStringDoubleOrStringRecord& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    HeapVector<Member<Element>> cppValue = NativeValueTraits<IDLSequence<Element>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setElementSequence(cppValue);
+    return;
+  }
+
+  if (v8Value->IsObject()) {
+    HeapVector<std::pair<String, DoubleOrString>> cppValue = NativeValueTraits<IDLRecord<IDLByteString, DoubleOrString>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setByteStringDoubleOrStringRecord(cppValue);
+    return;
+  }
+
+  exceptionState.ThrowTypeError("The provided value is not of type '(sequence<Element> or record<ByteString, (double or DOMString)>)'");
+}
+
+v8::Local<v8::Value> ToV8(const ElementSequenceOrByteStringDoubleOrStringRecord& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case ElementSequenceOrByteStringDoubleOrStringRecord::SpecificTypeNone:
+      return v8::Null(isolate);
+    case ElementSequenceOrByteStringDoubleOrStringRecord::SpecificTypeByteStringDoubleOrStringRecord:
+      return ToV8(impl.getAsByteStringDoubleOrStringRecord(), creationContext, isolate);
+    case ElementSequenceOrByteStringDoubleOrStringRecord::SpecificTypeElementSequence:
+      return ToV8(impl.getAsElementSequence(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+ElementSequenceOrByteStringDoubleOrStringRecord NativeValueTraits<ElementSequenceOrByteStringDoubleOrStringRecord>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  ElementSequenceOrByteStringDoubleOrStringRecord impl;
+  V8ElementSequenceOrByteStringDoubleOrStringRecord::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/ElementSequenceOrByteStringDoubleOrStringRecord.h b/third_party/WebKit/Source/bindings/tests/results/core/element_sequence_or_byte_string_double_or_string_record.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/ElementSequenceOrByteStringDoubleOrStringRecord.h
rename to third_party/WebKit/Source/bindings/tests/results/core/element_sequence_or_byte_string_double_or_string_record.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/float_or_boolean.cc b/third_party/WebKit/Source/bindings/tests/results/core/float_or_boolean.cc
new file mode 100644
index 0000000..cf1c0cfb
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/float_or_boolean.cc
@@ -0,0 +1,112 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "float_or_boolean.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+FloatOrBoolean::FloatOrBoolean() : type_(SpecificTypeNone) {}
+
+bool FloatOrBoolean::getAsBoolean() const {
+  DCHECK(isBoolean());
+  return boolean_;
+}
+
+void FloatOrBoolean::setBoolean(bool value) {
+  DCHECK(isNull());
+  boolean_ = value;
+  type_ = SpecificTypeBoolean;
+}
+
+FloatOrBoolean FloatOrBoolean::fromBoolean(bool value) {
+  FloatOrBoolean container;
+  container.setBoolean(value);
+  return container;
+}
+
+float FloatOrBoolean::getAsFloat() const {
+  DCHECK(isFloat());
+  return float_;
+}
+
+void FloatOrBoolean::setFloat(float value) {
+  DCHECK(isNull());
+  float_ = value;
+  type_ = SpecificTypeFloat;
+}
+
+FloatOrBoolean FloatOrBoolean::fromFloat(float value) {
+  FloatOrBoolean container;
+  container.setFloat(value);
+  return container;
+}
+
+FloatOrBoolean::FloatOrBoolean(const FloatOrBoolean&) = default;
+FloatOrBoolean::~FloatOrBoolean() = default;
+FloatOrBoolean& FloatOrBoolean::operator=(const FloatOrBoolean&) = default;
+
+DEFINE_TRACE(FloatOrBoolean) {
+}
+
+void V8FloatOrBoolean::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, FloatOrBoolean& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsBoolean()) {
+    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    float cppValue = NativeValueTraits<IDLFloat>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setFloat(cppValue);
+    return;
+  }
+
+  {
+    float cppValue = NativeValueTraits<IDLFloat>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setFloat(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const FloatOrBoolean& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case FloatOrBoolean::SpecificTypeNone:
+      return v8::Null(isolate);
+    case FloatOrBoolean::SpecificTypeBoolean:
+      return v8::Boolean::New(isolate, impl.getAsBoolean());
+    case FloatOrBoolean::SpecificTypeFloat:
+      return v8::Number::New(isolate, impl.getAsFloat());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+FloatOrBoolean NativeValueTraits<FloatOrBoolean>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  FloatOrBoolean impl;
+  V8FloatOrBoolean::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/FloatOrBoolean.h b/third_party/WebKit/Source/bindings/tests/results/core/float_or_boolean.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/FloatOrBoolean.h
rename to third_party/WebKit/Source/bindings/tests/results/core/float_or_boolean.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/long_callback_function.cc b/third_party/WebKit/Source/bindings/tests/results/core/long_callback_function.cc
new file mode 100644
index 0000000..92b4313
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/long_callback_function.cc
@@ -0,0 +1,99 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "long_callback_function.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+LongCallbackFunction* LongCallbackFunction::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new LongCallbackFunction(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+LongCallbackFunction::LongCallbackFunction(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(LongCallbackFunction) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool LongCallbackFunction::call(ScriptWrappable* scriptWrappable, int32_t num1, int32_t num2, int32_t& returnValue) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_num1 = v8::Integer::New(script_state_->GetIsolate(), num1);
+  v8::Local<v8::Value> v8_num2 = v8::Integer::New(script_state_->GetIsolate(), num2);
+  v8::Local<v8::Value> argv[] = { v8_num1, v8_num2 };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    2,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(script_state_->GetIsolate(), v8ReturnValue, exceptionState, kNormalConversion);
+  if (exceptionState.HadException())
+    return false;
+  returnValue = cppValue;
+  return true;
+}
+
+LongCallbackFunction* NativeValueTraits<LongCallbackFunction>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  LongCallbackFunction* nativeValue = LongCallbackFunction::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "LongCallbackFunction"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.h b/third_party/WebKit/Source/bindings/tests/results/core/long_callback_function.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/LongCallbackFunction.h
rename to third_party/WebKit/Source/bindings/tests/results/core/long_callback_function.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/long_or_boolean.cc b/third_party/WebKit/Source/bindings/tests/results/core/long_or_boolean.cc
new file mode 100644
index 0000000..fecc17a
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/long_or_boolean.cc
@@ -0,0 +1,112 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "long_or_boolean.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+LongOrBoolean::LongOrBoolean() : type_(SpecificTypeNone) {}
+
+bool LongOrBoolean::getAsBoolean() const {
+  DCHECK(isBoolean());
+  return boolean_;
+}
+
+void LongOrBoolean::setBoolean(bool value) {
+  DCHECK(isNull());
+  boolean_ = value;
+  type_ = SpecificTypeBoolean;
+}
+
+LongOrBoolean LongOrBoolean::fromBoolean(bool value) {
+  LongOrBoolean container;
+  container.setBoolean(value);
+  return container;
+}
+
+int32_t LongOrBoolean::getAsLong() const {
+  DCHECK(isLong());
+  return long_;
+}
+
+void LongOrBoolean::setLong(int32_t value) {
+  DCHECK(isNull());
+  long_ = value;
+  type_ = SpecificTypeLong;
+}
+
+LongOrBoolean LongOrBoolean::fromLong(int32_t value) {
+  LongOrBoolean container;
+  container.setLong(value);
+  return container;
+}
+
+LongOrBoolean::LongOrBoolean(const LongOrBoolean&) = default;
+LongOrBoolean::~LongOrBoolean() = default;
+LongOrBoolean& LongOrBoolean::operator=(const LongOrBoolean&) = default;
+
+DEFINE_TRACE(LongOrBoolean) {
+}
+
+void V8LongOrBoolean::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, LongOrBoolean& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsBoolean()) {
+    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setLong(cppValue);
+    return;
+  }
+
+  {
+    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setLong(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const LongOrBoolean& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case LongOrBoolean::SpecificTypeNone:
+      return v8::Null(isolate);
+    case LongOrBoolean::SpecificTypeBoolean:
+      return v8::Boolean::New(isolate, impl.getAsBoolean());
+    case LongOrBoolean::SpecificTypeLong:
+      return v8::Integer::New(isolate, impl.getAsLong());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+LongOrBoolean NativeValueTraits<LongOrBoolean>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  LongOrBoolean impl;
+  V8LongOrBoolean::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongOrBoolean.h b/third_party/WebKit/Source/bindings/tests/results/core/long_or_boolean.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/LongOrBoolean.h
rename to third_party/WebKit/Source/bindings/tests/results/core/long_or_boolean.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/long_or_test_dictionary.cc b/third_party/WebKit/Source/bindings/tests/results/core/long_or_test_dictionary.cc
new file mode 100644
index 0000000..2d233bd
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/long_or_test_dictionary.cc
@@ -0,0 +1,126 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "long_or_test_dictionary.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+LongOrTestDictionary::LongOrTestDictionary() : type_(SpecificTypeNone) {}
+
+int32_t LongOrTestDictionary::getAsLong() const {
+  DCHECK(isLong());
+  return long_;
+}
+
+void LongOrTestDictionary::setLong(int32_t value) {
+  DCHECK(isNull());
+  long_ = value;
+  type_ = SpecificTypeLong;
+}
+
+LongOrTestDictionary LongOrTestDictionary::fromLong(int32_t value) {
+  LongOrTestDictionary container;
+  container.setLong(value);
+  return container;
+}
+
+const TestDictionary& LongOrTestDictionary::getAsTestDictionary() const {
+  DCHECK(isTestDictionary());
+  return test_dictionary_;
+}
+
+void LongOrTestDictionary::setTestDictionary(const TestDictionary& value) {
+  DCHECK(isNull());
+  test_dictionary_ = value;
+  type_ = SpecificTypeTestDictionary;
+}
+
+LongOrTestDictionary LongOrTestDictionary::fromTestDictionary(const TestDictionary& value) {
+  LongOrTestDictionary container;
+  container.setTestDictionary(value);
+  return container;
+}
+
+LongOrTestDictionary::LongOrTestDictionary(const LongOrTestDictionary&) = default;
+LongOrTestDictionary::~LongOrTestDictionary() = default;
+LongOrTestDictionary& LongOrTestDictionary::operator=(const LongOrTestDictionary&) = default;
+
+DEFINE_TRACE(LongOrTestDictionary) {
+  visitor->Trace(test_dictionary_);
+}
+
+void V8LongOrTestDictionary::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, LongOrTestDictionary& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (IsUndefinedOrNull(v8Value)) {
+    TestDictionary cppValue;
+    V8TestDictionary::toImpl(isolate, v8Value, cppValue, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setTestDictionary(cppValue);
+    return;
+  }
+
+  if (v8Value->IsObject()) {
+    TestDictionary cppValue;
+    V8TestDictionary::toImpl(isolate, v8Value, cppValue, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setTestDictionary(cppValue);
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setLong(cppValue);
+    return;
+  }
+
+  {
+    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setLong(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const LongOrTestDictionary& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case LongOrTestDictionary::SpecificTypeNone:
+      return v8::Null(isolate);
+    case LongOrTestDictionary::SpecificTypeLong:
+      return v8::Integer::New(isolate, impl.getAsLong());
+    case LongOrTestDictionary::SpecificTypeTestDictionary:
+      return ToV8(impl.getAsTestDictionary(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+LongOrTestDictionary NativeValueTraits<LongOrTestDictionary>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  LongOrTestDictionary impl;
+  V8LongOrTestDictionary::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongOrTestDictionary.h b/third_party/WebKit/Source/bindings/tests/results/core/long_or_test_dictionary.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/LongOrTestDictionary.h
rename to third_party/WebKit/Source/bindings/tests/results/core/long_or_test_dictionary.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/long_sequence_or_event.cc b/third_party/WebKit/Source/bindings/tests/results/core/long_sequence_or_event.cc
new file mode 100644
index 0000000..7961da9
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/long_sequence_or_event.cc
@@ -0,0 +1,109 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "long_sequence_or_event.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8Event.h"
+
+namespace blink {
+
+LongSequenceOrEvent::LongSequenceOrEvent() : type_(SpecificTypeNone) {}
+
+Event* LongSequenceOrEvent::getAsEvent() const {
+  DCHECK(isEvent());
+  return event_;
+}
+
+void LongSequenceOrEvent::setEvent(Event* value) {
+  DCHECK(isNull());
+  event_ = value;
+  type_ = SpecificTypeEvent;
+}
+
+LongSequenceOrEvent LongSequenceOrEvent::fromEvent(Event* value) {
+  LongSequenceOrEvent container;
+  container.setEvent(value);
+  return container;
+}
+
+const Vector<int32_t>& LongSequenceOrEvent::getAsLongSequence() const {
+  DCHECK(isLongSequence());
+  return long_sequence_;
+}
+
+void LongSequenceOrEvent::setLongSequence(const Vector<int32_t>& value) {
+  DCHECK(isNull());
+  long_sequence_ = value;
+  type_ = SpecificTypeLongSequence;
+}
+
+LongSequenceOrEvent LongSequenceOrEvent::fromLongSequence(const Vector<int32_t>& value) {
+  LongSequenceOrEvent container;
+  container.setLongSequence(value);
+  return container;
+}
+
+LongSequenceOrEvent::LongSequenceOrEvent(const LongSequenceOrEvent&) = default;
+LongSequenceOrEvent::~LongSequenceOrEvent() = default;
+LongSequenceOrEvent& LongSequenceOrEvent::operator=(const LongSequenceOrEvent&) = default;
+
+DEFINE_TRACE(LongSequenceOrEvent) {
+  visitor->Trace(event_);
+}
+
+void V8LongSequenceOrEvent::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, LongSequenceOrEvent& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8Event::hasInstance(v8Value, isolate)) {
+    Event* cppValue = V8Event::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setEvent(cppValue);
+    return;
+  }
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    Vector<int32_t> cppValue = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setLongSequence(cppValue);
+    return;
+  }
+
+  exceptionState.ThrowTypeError("The provided value is not of type '(sequence<long> or Event)'");
+}
+
+v8::Local<v8::Value> ToV8(const LongSequenceOrEvent& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case LongSequenceOrEvent::SpecificTypeNone:
+      return v8::Null(isolate);
+    case LongSequenceOrEvent::SpecificTypeEvent:
+      return ToV8(impl.getAsEvent(), creationContext, isolate);
+    case LongSequenceOrEvent::SpecificTypeLongSequence:
+      return ToV8(impl.getAsLongSequence(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+LongSequenceOrEvent NativeValueTraits<LongSequenceOrEvent>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  LongSequenceOrEvent impl;
+  V8LongSequenceOrEvent::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/LongSequenceOrEvent.h b/third_party/WebKit/Source/bindings/tests/results/core/long_sequence_or_event.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/LongSequenceOrEvent.h
rename to third_party/WebKit/Source/bindings/tests/results/core/long_sequence_or_event.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/nested_union_type.cc b/third_party/WebKit/Source/bindings/tests/results/core/nested_union_type.cc
new file mode 100644
index 0000000..5f361a47
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/nested_union_type.cc
@@ -0,0 +1,222 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "nested_union_type.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8Event.h"
+#include "bindings/core/v8/V8Node.h"
+#include "bindings/core/v8/V8NodeList.h"
+#include "bindings/core/v8/V8XMLHttpRequest.h"
+#include "bindings/core/v8/byte_string_or_node_list.h"
+#include "core/dom/NameNodeList.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/StaticNodeList.h"
+#include "core/html/LabelsNodeList.h"
+
+namespace blink {
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord() : type_(SpecificTypeNone) {}
+
+Event* NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsEvent() const {
+  DCHECK(isEvent());
+  return event_;
+}
+
+void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setEvent(Event* value) {
+  DCHECK(isNull());
+  event_ = value;
+  type_ = SpecificTypeEvent;
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromEvent(Event* value) {
+  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
+  container.setEvent(value);
+  return container;
+}
+
+const Vector<int32_t>& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsLongSequence() const {
+  DCHECK(isLongSequence());
+  return long_sequence_;
+}
+
+void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setLongSequence(const Vector<int32_t>& value) {
+  DCHECK(isNull());
+  long_sequence_ = value;
+  type_ = SpecificTypeLongSequence;
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromLongSequence(const Vector<int32_t>& value) {
+  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
+  container.setLongSequence(value);
+  return container;
+}
+
+Node* NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsNode() const {
+  DCHECK(isNode());
+  return node_;
+}
+
+void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setNode(Node* value) {
+  DCHECK(isNull());
+  node_ = value;
+  type_ = SpecificTypeNode;
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromNode(Node* value) {
+  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
+  container.setNode(value);
+  return container;
+}
+
+const String& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromString(const String& value) {
+  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
+  container.setString(value);
+  return container;
+}
+
+const HeapVector<std::pair<String, ByteStringOrNodeList>>& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsStringByteStringOrNodeListRecord() const {
+  DCHECK(isStringByteStringOrNodeListRecord());
+  return string_byte_string_or_node_list_record_;
+}
+
+void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setStringByteStringOrNodeListRecord(const HeapVector<std::pair<String, ByteStringOrNodeList>>& value) {
+  DCHECK(isNull());
+  string_byte_string_or_node_list_record_ = value;
+  type_ = SpecificTypeStringByteStringOrNodeListRecord;
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromStringByteStringOrNodeListRecord(const HeapVector<std::pair<String, ByteStringOrNodeList>>& value) {
+  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
+  container.setStringByteStringOrNodeListRecord(value);
+  return container;
+}
+
+XMLHttpRequest* NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::getAsXMLHttpRequest() const {
+  DCHECK(isXMLHttpRequest());
+  return xml_http_request_;
+}
+
+void NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::setXMLHttpRequest(XMLHttpRequest* value) {
+  DCHECK(isNull());
+  xml_http_request_ = value;
+  type_ = SpecificTypeXMLHttpRequest;
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::fromXMLHttpRequest(XMLHttpRequest* value) {
+  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord container;
+  container.setXMLHttpRequest(value);
+  return container;
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord(const NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord&) = default;
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::~NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord() = default;
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord& NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::operator=(const NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord&) = default;
+
+DEFINE_TRACE(NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord) {
+  visitor->Trace(event_);
+  visitor->Trace(node_);
+  visitor->Trace(string_byte_string_or_node_list_record_);
+  visitor->Trace(xml_http_request_);
+}
+
+void V8NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8Event::hasInstance(v8Value, isolate)) {
+    Event* cppValue = V8Event::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setEvent(cppValue);
+    return;
+  }
+
+  if (V8Node::hasInstance(v8Value, isolate)) {
+    Node* cppValue = V8Node::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setNode(cppValue);
+    return;
+  }
+
+  if (V8XMLHttpRequest::hasInstance(v8Value, isolate)) {
+    XMLHttpRequest* cppValue = V8XMLHttpRequest::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setXMLHttpRequest(cppValue);
+    return;
+  }
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    Vector<int32_t> cppValue = NativeValueTraits<IDLSequence<IDLLong>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setLongSequence(cppValue);
+    return;
+  }
+
+  if (v8Value->IsObject()) {
+    HeapVector<std::pair<String, ByteStringOrNodeList>> cppValue = NativeValueTraits<IDLRecord<IDLString, ByteStringOrNodeList>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setStringByteStringOrNodeListRecord(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeNone:
+      return v8::Null(isolate);
+    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeEvent:
+      return ToV8(impl.getAsEvent(), creationContext, isolate);
+    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeLongSequence:
+      return ToV8(impl.getAsLongSequence(), creationContext, isolate);
+    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeNode:
+      return ToV8(impl.getAsNode(), creationContext, isolate);
+    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeStringByteStringOrNodeListRecord:
+      return ToV8(impl.getAsStringByteStringOrNodeListRecord(), creationContext, isolate);
+    case NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::SpecificTypeXMLHttpRequest:
+      return ToV8(impl.getAsXMLHttpRequest(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord NativeValueTraits<NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord impl;
+  V8NodeOrLongSequenceOrEventOrXMLHttpRequestOrStringOrStringByteStringOrNodeListRecord::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/NestedUnionType.h b/third_party/WebKit/Source/bindings/tests/results/core/nested_union_type.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/NestedUnionType.h
rename to third_party/WebKit/Source/bindings/tests/results/core/nested_union_type.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/node_or_node_list.cc b/third_party/WebKit/Source/bindings/tests/results/core/node_or_node_list.cc
new file mode 100644
index 0000000..74f6883
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/node_or_node_list.cc
@@ -0,0 +1,111 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "node_or_node_list.h"
+
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8Node.h"
+#include "bindings/core/v8/V8NodeList.h"
+#include "core/dom/NameNodeList.h"
+#include "core/dom/NodeList.h"
+#include "core/dom/StaticNodeList.h"
+#include "core/html/LabelsNodeList.h"
+
+namespace blink {
+
+NodeOrNodeList::NodeOrNodeList() : type_(SpecificTypeNone) {}
+
+Node* NodeOrNodeList::getAsNode() const {
+  DCHECK(isNode());
+  return node_;
+}
+
+void NodeOrNodeList::setNode(Node* value) {
+  DCHECK(isNull());
+  node_ = value;
+  type_ = SpecificTypeNode;
+}
+
+NodeOrNodeList NodeOrNodeList::fromNode(Node* value) {
+  NodeOrNodeList container;
+  container.setNode(value);
+  return container;
+}
+
+NodeList* NodeOrNodeList::getAsNodeList() const {
+  DCHECK(isNodeList());
+  return node_list_;
+}
+
+void NodeOrNodeList::setNodeList(NodeList* value) {
+  DCHECK(isNull());
+  node_list_ = value;
+  type_ = SpecificTypeNodeList;
+}
+
+NodeOrNodeList NodeOrNodeList::fromNodeList(NodeList* value) {
+  NodeOrNodeList container;
+  container.setNodeList(value);
+  return container;
+}
+
+NodeOrNodeList::NodeOrNodeList(const NodeOrNodeList&) = default;
+NodeOrNodeList::~NodeOrNodeList() = default;
+NodeOrNodeList& NodeOrNodeList::operator=(const NodeOrNodeList&) = default;
+
+DEFINE_TRACE(NodeOrNodeList) {
+  visitor->Trace(node_);
+  visitor->Trace(node_list_);
+}
+
+void V8NodeOrNodeList::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, NodeOrNodeList& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8Node::hasInstance(v8Value, isolate)) {
+    Node* cppValue = V8Node::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setNode(cppValue);
+    return;
+  }
+
+  if (V8NodeList::hasInstance(v8Value, isolate)) {
+    NodeList* cppValue = V8NodeList::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setNodeList(cppValue);
+    return;
+  }
+
+  exceptionState.ThrowTypeError("The provided value is not of type '(Node or NodeList)'");
+}
+
+v8::Local<v8::Value> ToV8(const NodeOrNodeList& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case NodeOrNodeList::SpecificTypeNone:
+      return v8::Null(isolate);
+    case NodeOrNodeList::SpecificTypeNode:
+      return ToV8(impl.getAsNode(), creationContext, isolate);
+    case NodeOrNodeList::SpecificTypeNodeList:
+      return ToV8(impl.getAsNodeList(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+NodeOrNodeList NativeValueTraits<NodeOrNodeList>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  NodeOrNodeList impl;
+  V8NodeOrNodeList::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/NodeOrNodeList.h b/third_party/WebKit/Source/bindings/tests/results/core/node_or_node_list.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/NodeOrNodeList.h
rename to third_party/WebKit/Source/bindings/tests/results/core/node_or_node_list.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/string_or_array_buffer_or_array_buffer_view.cc b/third_party/WebKit/Source/bindings/tests/results/core/string_or_array_buffer_or_array_buffer_view.cc
new file mode 100644
index 0000000..75f3a18
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/string_or_array_buffer_or_array_buffer_view.cc
@@ -0,0 +1,135 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "string_or_array_buffer_or_array_buffer_view.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8ArrayBuffer.h"
+
+namespace blink {
+
+StringOrArrayBufferOrArrayBufferView::StringOrArrayBufferOrArrayBufferView() : type_(SpecificTypeNone) {}
+
+TestArrayBuffer* StringOrArrayBufferOrArrayBufferView::getAsArrayBuffer() const {
+  DCHECK(isArrayBuffer());
+  return array_buffer_;
+}
+
+void StringOrArrayBufferOrArrayBufferView::setArrayBuffer(TestArrayBuffer* value) {
+  DCHECK(isNull());
+  array_buffer_ = value;
+  type_ = SpecificTypeArrayBuffer;
+}
+
+StringOrArrayBufferOrArrayBufferView StringOrArrayBufferOrArrayBufferView::fromArrayBuffer(TestArrayBuffer* value) {
+  StringOrArrayBufferOrArrayBufferView container;
+  container.setArrayBuffer(value);
+  return container;
+}
+
+NotShared<TestArrayBufferView> StringOrArrayBufferOrArrayBufferView::getAsArrayBufferView() const {
+  DCHECK(isArrayBufferView());
+  return array_buffer_view_;
+}
+
+void StringOrArrayBufferOrArrayBufferView::setArrayBufferView(NotShared<TestArrayBufferView> value) {
+  DCHECK(isNull());
+  array_buffer_view_ = Member<TestArrayBufferView>(value.View());
+  type_ = SpecificTypeArrayBufferView;
+}
+
+StringOrArrayBufferOrArrayBufferView StringOrArrayBufferOrArrayBufferView::fromArrayBufferView(NotShared<TestArrayBufferView> value) {
+  StringOrArrayBufferOrArrayBufferView container;
+  container.setArrayBufferView(value);
+  return container;
+}
+
+const String& StringOrArrayBufferOrArrayBufferView::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void StringOrArrayBufferOrArrayBufferView::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+StringOrArrayBufferOrArrayBufferView StringOrArrayBufferOrArrayBufferView::fromString(const String& value) {
+  StringOrArrayBufferOrArrayBufferView container;
+  container.setString(value);
+  return container;
+}
+
+StringOrArrayBufferOrArrayBufferView::StringOrArrayBufferOrArrayBufferView(const StringOrArrayBufferOrArrayBufferView&) = default;
+StringOrArrayBufferOrArrayBufferView::~StringOrArrayBufferOrArrayBufferView() = default;
+StringOrArrayBufferOrArrayBufferView& StringOrArrayBufferOrArrayBufferView::operator=(const StringOrArrayBufferOrArrayBufferView&) = default;
+
+DEFINE_TRACE(StringOrArrayBufferOrArrayBufferView) {
+  visitor->Trace(array_buffer_);
+  visitor->Trace(array_buffer_view_);
+}
+
+void V8StringOrArrayBufferOrArrayBufferView::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, StringOrArrayBufferOrArrayBufferView& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsArrayBuffer()) {
+    TestArrayBuffer* cppValue = V8ArrayBuffer::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setArrayBuffer(cppValue);
+    return;
+  }
+
+  if (v8Value->IsArrayBufferView()) {
+    NotShared<TestArrayBufferView> cppValue = ToNotShared<NotShared<TestArrayBufferView>>(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setArrayBufferView(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const StringOrArrayBufferOrArrayBufferView& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case StringOrArrayBufferOrArrayBufferView::SpecificTypeNone:
+      return v8::Null(isolate);
+    case StringOrArrayBufferOrArrayBufferView::SpecificTypeArrayBuffer:
+      return ToV8(impl.getAsArrayBuffer(), creationContext, isolate);
+    case StringOrArrayBufferOrArrayBufferView::SpecificTypeArrayBufferView:
+      return ToV8(impl.getAsArrayBufferView(), creationContext, isolate);
+    case StringOrArrayBufferOrArrayBufferView::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+StringOrArrayBufferOrArrayBufferView NativeValueTraits<StringOrArrayBufferOrArrayBufferView>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  StringOrArrayBufferOrArrayBufferView impl;
+  V8StringOrArrayBufferOrArrayBufferView::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringOrArrayBufferOrArrayBufferView.h b/third_party/WebKit/Source/bindings/tests/results/core/string_or_array_buffer_or_array_buffer_view.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/StringOrArrayBufferOrArrayBufferView.h
rename to third_party/WebKit/Source/bindings/tests/results/core/string_or_array_buffer_or_array_buffer_view.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/string_or_double.cc b/third_party/WebKit/Source/bindings/tests/results/core/string_or_double.cc
new file mode 100644
index 0000000..380e916e
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/string_or_double.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "string_or_double.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+StringOrDouble::StringOrDouble() : type_(SpecificTypeNone) {}
+
+double StringOrDouble::getAsDouble() const {
+  DCHECK(isDouble());
+  return double_;
+}
+
+void StringOrDouble::setDouble(double value) {
+  DCHECK(isNull());
+  double_ = value;
+  type_ = SpecificTypeDouble;
+}
+
+StringOrDouble StringOrDouble::fromDouble(double value) {
+  StringOrDouble container;
+  container.setDouble(value);
+  return container;
+}
+
+const String& StringOrDouble::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void StringOrDouble::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+StringOrDouble StringOrDouble::fromString(const String& value) {
+  StringOrDouble container;
+  container.setString(value);
+  return container;
+}
+
+StringOrDouble::StringOrDouble(const StringOrDouble&) = default;
+StringOrDouble::~StringOrDouble() = default;
+StringOrDouble& StringOrDouble::operator=(const StringOrDouble&) = default;
+
+DEFINE_TRACE(StringOrDouble) {
+}
+
+void V8StringOrDouble::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, StringOrDouble& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsNumber()) {
+    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDouble(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const StringOrDouble& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case StringOrDouble::SpecificTypeNone:
+      return v8::Null(isolate);
+    case StringOrDouble::SpecificTypeDouble:
+      return v8::Number::New(isolate, impl.getAsDouble());
+    case StringOrDouble::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+StringOrDouble NativeValueTraits<StringOrDouble>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  StringOrDouble impl;
+  V8StringOrDouble::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringOrDouble.h b/third_party/WebKit/Source/bindings/tests/results/core/string_or_double.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/StringOrDouble.h
rename to third_party/WebKit/Source/bindings/tests/results/core/string_or_double.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/string_or_string_sequence.cc b/third_party/WebKit/Source/bindings/tests/results/core/string_or_string_sequence.cc
new file mode 100644
index 0000000..ef155b25
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/string_or_string_sequence.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "string_or_string_sequence.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+StringOrStringSequence::StringOrStringSequence() : type_(SpecificTypeNone) {}
+
+const String& StringOrStringSequence::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void StringOrStringSequence::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+StringOrStringSequence StringOrStringSequence::fromString(const String& value) {
+  StringOrStringSequence container;
+  container.setString(value);
+  return container;
+}
+
+const Vector<String>& StringOrStringSequence::getAsStringSequence() const {
+  DCHECK(isStringSequence());
+  return string_sequence_;
+}
+
+void StringOrStringSequence::setStringSequence(const Vector<String>& value) {
+  DCHECK(isNull());
+  string_sequence_ = value;
+  type_ = SpecificTypeStringSequence;
+}
+
+StringOrStringSequence StringOrStringSequence::fromStringSequence(const Vector<String>& value) {
+  StringOrStringSequence container;
+  container.setStringSequence(value);
+  return container;
+}
+
+StringOrStringSequence::StringOrStringSequence(const StringOrStringSequence&) = default;
+StringOrStringSequence::~StringOrStringSequence() = default;
+StringOrStringSequence& StringOrStringSequence::operator=(const StringOrStringSequence&) = default;
+
+DEFINE_TRACE(StringOrStringSequence) {
+}
+
+void V8StringOrStringSequence::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, StringOrStringSequence& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (HasCallableIteratorSymbol(isolate, v8Value, exceptionState)) {
+    Vector<String> cppValue = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setStringSequence(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const StringOrStringSequence& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case StringOrStringSequence::SpecificTypeNone:
+      return v8::Null(isolate);
+    case StringOrStringSequence::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    case StringOrStringSequence::SpecificTypeStringSequence:
+      return ToV8(impl.getAsStringSequence(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+StringOrStringSequence NativeValueTraits<StringOrStringSequence>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  StringOrStringSequence impl;
+  V8StringOrStringSequence::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringOrStringSequence.h b/third_party/WebKit/Source/bindings/tests/results/core/string_or_string_sequence.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/StringOrStringSequence.h
rename to third_party/WebKit/Source/bindings/tests/results/core/string_or_string_sequence.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/string_sequence_callback_function_long_sequence_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/string_sequence_callback_function_long_sequence_arg.cc
new file mode 100644
index 0000000..2ddd71e7
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/string_sequence_callback_function_long_sequence_arg.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "string_sequence_callback_function_long_sequence_arg.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+StringSequenceCallbackFunctionLongSequenceArg* StringSequenceCallbackFunctionLongSequenceArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new StringSequenceCallbackFunctionLongSequenceArg(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+StringSequenceCallbackFunctionLongSequenceArg::StringSequenceCallbackFunctionLongSequenceArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(StringSequenceCallbackFunctionLongSequenceArg) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool StringSequenceCallbackFunctionLongSequenceArg::call(ScriptWrappable* scriptWrappable, const Vector<int32_t>& arg, Vector<String>& returnValue) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate());
+  v8::Local<v8::Value> argv[] = { v8_arg };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    1,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  Vector<String> cppValue = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(script_state_->GetIsolate(), v8ReturnValue, exceptionState);
+  if (exceptionState.HadException())
+    return false;
+  returnValue = cppValue;
+  return true;
+}
+
+StringSequenceCallbackFunctionLongSequenceArg* NativeValueTraits<StringSequenceCallbackFunctionLongSequenceArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  StringSequenceCallbackFunctionLongSequenceArg* nativeValue = StringSequenceCallbackFunctionLongSequenceArg::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "StringSequenceCallbackFunctionLongSequenceArg"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.h b/third_party/WebKit/Source/bindings/tests/results/core/string_sequence_callback_function_long_sequence_arg.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/StringSequenceCallbackFunctionLongSequenceArg.h
rename to third_party/WebKit/Source/bindings/tests/results/core/string_sequence_callback_function_long_sequence_arg.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/test_enum_or_double.cc b/third_party/WebKit/Source/bindings/tests/results/core/test_enum_or_double.cc
new file mode 100644
index 0000000..b283760
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/test_enum_or_double.cc
@@ -0,0 +1,126 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "test_enum_or_double.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+TestEnumOrDouble::TestEnumOrDouble() : type_(SpecificTypeNone) {}
+
+double TestEnumOrDouble::getAsDouble() const {
+  DCHECK(isDouble());
+  return double_;
+}
+
+void TestEnumOrDouble::setDouble(double value) {
+  DCHECK(isNull());
+  double_ = value;
+  type_ = SpecificTypeDouble;
+}
+
+TestEnumOrDouble TestEnumOrDouble::fromDouble(double value) {
+  TestEnumOrDouble container;
+  container.setDouble(value);
+  return container;
+}
+
+const String& TestEnumOrDouble::getAsTestEnum() const {
+  DCHECK(isTestEnum());
+  return test_enum_;
+}
+
+void TestEnumOrDouble::setTestEnum(const String& value) {
+  DCHECK(isNull());
+  NonThrowableExceptionState exceptionState;
+  const char* validValues[] = {
+      "",
+      "EnumValue1",
+      "EnumValue2",
+      "EnumValue3",
+  };
+  if (!IsValidEnum(value, validValues, WTF_ARRAY_LENGTH(validValues), "TestEnum", exceptionState)) {
+    NOTREACHED();
+    return;
+  }
+  test_enum_ = value;
+  type_ = SpecificTypeTestEnum;
+}
+
+TestEnumOrDouble TestEnumOrDouble::fromTestEnum(const String& value) {
+  TestEnumOrDouble container;
+  container.setTestEnum(value);
+  return container;
+}
+
+TestEnumOrDouble::TestEnumOrDouble(const TestEnumOrDouble&) = default;
+TestEnumOrDouble::~TestEnumOrDouble() = default;
+TestEnumOrDouble& TestEnumOrDouble::operator=(const TestEnumOrDouble&) = default;
+
+DEFINE_TRACE(TestEnumOrDouble) {
+}
+
+void V8TestEnumOrDouble::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestEnumOrDouble& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsNumber()) {
+    double cppValue = NativeValueTraits<IDLDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setDouble(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    const char* validValues[] = {
+        "",
+        "EnumValue1",
+        "EnumValue2",
+        "EnumValue3",
+    };
+    if (!IsValidEnum(cppValue, validValues, WTF_ARRAY_LENGTH(validValues), "TestEnum", exceptionState))
+      return;
+    impl.setTestEnum(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const TestEnumOrDouble& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case TestEnumOrDouble::SpecificTypeNone:
+      return v8::Null(isolate);
+    case TestEnumOrDouble::SpecificTypeDouble:
+      return v8::Number::New(isolate, impl.getAsDouble());
+    case TestEnumOrDouble::SpecificTypeTestEnum:
+      return V8String(isolate, impl.getAsTestEnum());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+TestEnumOrDouble NativeValueTraits<TestEnumOrDouble>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  TestEnumOrDouble impl;
+  V8TestEnumOrDouble::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestEnumOrDouble.h b/third_party/WebKit/Source/bindings/tests/results/core/test_enum_or_double.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/TestEnumOrDouble.h
rename to third_party/WebKit/Source/bindings/tests/results/core/test_enum_or_double.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/test_interface_2_or_uint8_array.cc b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_2_or_uint8_array.cc
new file mode 100644
index 0000000..4d1b6cd
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_2_or_uint8_array.cc
@@ -0,0 +1,108 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "test_interface_2_or_uint8_array.h"
+
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8TestInterface2.h"
+
+namespace blink {
+
+TestInterface2OrUint8Array::TestInterface2OrUint8Array() : type_(SpecificTypeNone) {}
+
+TestInterface2* TestInterface2OrUint8Array::getAsTestInterface2() const {
+  DCHECK(isTestInterface2());
+  return test_interface_2_;
+}
+
+void TestInterface2OrUint8Array::setTestInterface2(TestInterface2* value) {
+  DCHECK(isNull());
+  test_interface_2_ = value;
+  type_ = SpecificTypeTestInterface2;
+}
+
+TestInterface2OrUint8Array TestInterface2OrUint8Array::fromTestInterface2(TestInterface2* value) {
+  TestInterface2OrUint8Array container;
+  container.setTestInterface2(value);
+  return container;
+}
+
+NotShared<DOMUint8Array> TestInterface2OrUint8Array::getAsUint8Array() const {
+  DCHECK(isUint8Array());
+  return uint8_array_;
+}
+
+void TestInterface2OrUint8Array::setUint8Array(NotShared<DOMUint8Array> value) {
+  DCHECK(isNull());
+  uint8_array_ = Member<DOMUint8Array>(value.View());
+  type_ = SpecificTypeUint8Array;
+}
+
+TestInterface2OrUint8Array TestInterface2OrUint8Array::fromUint8Array(NotShared<DOMUint8Array> value) {
+  TestInterface2OrUint8Array container;
+  container.setUint8Array(value);
+  return container;
+}
+
+TestInterface2OrUint8Array::TestInterface2OrUint8Array(const TestInterface2OrUint8Array&) = default;
+TestInterface2OrUint8Array::~TestInterface2OrUint8Array() = default;
+TestInterface2OrUint8Array& TestInterface2OrUint8Array::operator=(const TestInterface2OrUint8Array&) = default;
+
+DEFINE_TRACE(TestInterface2OrUint8Array) {
+  visitor->Trace(test_interface_2_);
+  visitor->Trace(uint8_array_);
+}
+
+void V8TestInterface2OrUint8Array::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterface2OrUint8Array& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8TestInterface2::hasInstance(v8Value, isolate)) {
+    TestInterface2* cppValue = V8TestInterface2::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setTestInterface2(cppValue);
+    return;
+  }
+
+  if (v8Value->IsUint8Array()) {
+    NotShared<DOMUint8Array> cppValue = ToNotShared<NotShared<DOMUint8Array>>(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setUint8Array(cppValue);
+    return;
+  }
+
+  exceptionState.ThrowTypeError("The provided value is not of type '(TestInterface2 or Uint8Array)'");
+}
+
+v8::Local<v8::Value> ToV8(const TestInterface2OrUint8Array& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case TestInterface2OrUint8Array::SpecificTypeNone:
+      return v8::Null(isolate);
+    case TestInterface2OrUint8Array::SpecificTypeTestInterface2:
+      return ToV8(impl.getAsTestInterface2(), creationContext, isolate);
+    case TestInterface2OrUint8Array::SpecificTypeUint8Array:
+      return ToV8(impl.getAsUint8Array(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+TestInterface2OrUint8Array NativeValueTraits<TestInterface2OrUint8Array>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  TestInterface2OrUint8Array impl;
+  V8TestInterface2OrUint8Array::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.h b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_2_or_uint8_array.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/TestInterface2OrUint8Array.h
rename to third_party/WebKit/Source/bindings/tests/results/core/test_interface_2_or_uint8_array.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/test_interface_garbage_collected_or_string.cc b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_garbage_collected_or_string.cc
new file mode 100644
index 0000000..7f5b6dd
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_garbage_collected_or_string.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "test_interface_garbage_collected_or_string.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8TestInterfaceGarbageCollected.h"
+
+namespace blink {
+
+TestInterfaceGarbageCollectedOrString::TestInterfaceGarbageCollectedOrString() : type_(SpecificTypeNone) {}
+
+const String& TestInterfaceGarbageCollectedOrString::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void TestInterfaceGarbageCollectedOrString::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+TestInterfaceGarbageCollectedOrString TestInterfaceGarbageCollectedOrString::fromString(const String& value) {
+  TestInterfaceGarbageCollectedOrString container;
+  container.setString(value);
+  return container;
+}
+
+TestInterfaceGarbageCollected* TestInterfaceGarbageCollectedOrString::getAsTestInterfaceGarbageCollected() const {
+  DCHECK(isTestInterfaceGarbageCollected());
+  return test_interface_garbage_collected_;
+}
+
+void TestInterfaceGarbageCollectedOrString::setTestInterfaceGarbageCollected(TestInterfaceGarbageCollected* value) {
+  DCHECK(isNull());
+  test_interface_garbage_collected_ = value;
+  type_ = SpecificTypeTestInterfaceGarbageCollected;
+}
+
+TestInterfaceGarbageCollectedOrString TestInterfaceGarbageCollectedOrString::fromTestInterfaceGarbageCollected(TestInterfaceGarbageCollected* value) {
+  TestInterfaceGarbageCollectedOrString container;
+  container.setTestInterfaceGarbageCollected(value);
+  return container;
+}
+
+TestInterfaceGarbageCollectedOrString::TestInterfaceGarbageCollectedOrString(const TestInterfaceGarbageCollectedOrString&) = default;
+TestInterfaceGarbageCollectedOrString::~TestInterfaceGarbageCollectedOrString() = default;
+TestInterfaceGarbageCollectedOrString& TestInterfaceGarbageCollectedOrString::operator=(const TestInterfaceGarbageCollectedOrString&) = default;
+
+DEFINE_TRACE(TestInterfaceGarbageCollectedOrString) {
+  visitor->Trace(test_interface_garbage_collected_);
+}
+
+void V8TestInterfaceGarbageCollectedOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterfaceGarbageCollectedOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8TestInterfaceGarbageCollected::hasInstance(v8Value, isolate)) {
+    TestInterfaceGarbageCollected* cppValue = V8TestInterfaceGarbageCollected::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setTestInterfaceGarbageCollected(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const TestInterfaceGarbageCollectedOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case TestInterfaceGarbageCollectedOrString::SpecificTypeNone:
+      return v8::Null(isolate);
+    case TestInterfaceGarbageCollectedOrString::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    case TestInterfaceGarbageCollectedOrString::SpecificTypeTestInterfaceGarbageCollected:
+      return ToV8(impl.getAsTestInterfaceGarbageCollected(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+TestInterfaceGarbageCollectedOrString NativeValueTraits<TestInterfaceGarbageCollectedOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  TestInterfaceGarbageCollectedOrString impl;
+  V8TestInterfaceGarbageCollectedOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceGarbageCollectedOrString.h b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_garbage_collected_or_string.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceGarbageCollectedOrString.h
rename to third_party/WebKit/Source/bindings/tests/results/core/test_interface_garbage_collected_or_string.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_long.cc b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_long.cc
new file mode 100644
index 0000000..3120b40
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_long.cc
@@ -0,0 +1,120 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "test_interface_or_long.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8TestInterface.h"
+#include "bindings/tests/idls/core/TestImplements2.h"
+#include "bindings/tests/idls/core/TestImplements3Implementation.h"
+#include "bindings/tests/idls/core/TestInterfacePartial.h"
+#include "bindings/tests/idls/core/TestInterfacePartial2Implementation.h"
+#include "bindings/tests/idls/core/TestInterfacePartialSecureContext.h"
+
+namespace blink {
+
+TestInterfaceOrLong::TestInterfaceOrLong() : type_(SpecificTypeNone) {}
+
+int32_t TestInterfaceOrLong::getAsLong() const {
+  DCHECK(isLong());
+  return long_;
+}
+
+void TestInterfaceOrLong::setLong(int32_t value) {
+  DCHECK(isNull());
+  long_ = value;
+  type_ = SpecificTypeLong;
+}
+
+TestInterfaceOrLong TestInterfaceOrLong::fromLong(int32_t value) {
+  TestInterfaceOrLong container;
+  container.setLong(value);
+  return container;
+}
+
+TestInterfaceImplementation* TestInterfaceOrLong::getAsTestInterface() const {
+  DCHECK(isTestInterface());
+  return test_interface_;
+}
+
+void TestInterfaceOrLong::setTestInterface(TestInterfaceImplementation* value) {
+  DCHECK(isNull());
+  test_interface_ = value;
+  type_ = SpecificTypeTestInterface;
+}
+
+TestInterfaceOrLong TestInterfaceOrLong::fromTestInterface(TestInterfaceImplementation* value) {
+  TestInterfaceOrLong container;
+  container.setTestInterface(value);
+  return container;
+}
+
+TestInterfaceOrLong::TestInterfaceOrLong(const TestInterfaceOrLong&) = default;
+TestInterfaceOrLong::~TestInterfaceOrLong() = default;
+TestInterfaceOrLong& TestInterfaceOrLong::operator=(const TestInterfaceOrLong&) = default;
+
+DEFINE_TRACE(TestInterfaceOrLong) {
+  visitor->Trace(test_interface_);
+}
+
+void V8TestInterfaceOrLong::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterfaceOrLong& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8TestInterface::hasInstance(v8Value, isolate)) {
+    TestInterfaceImplementation* cppValue = V8TestInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setTestInterface(cppValue);
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setLong(cppValue);
+    return;
+  }
+
+  {
+    int32_t cppValue = NativeValueTraits<IDLLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setLong(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const TestInterfaceOrLong& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case TestInterfaceOrLong::SpecificTypeNone:
+      return v8::Null(isolate);
+    case TestInterfaceOrLong::SpecificTypeLong:
+      return v8::Integer::New(isolate, impl.getAsLong());
+    case TestInterfaceOrLong::SpecificTypeTestInterface:
+      return ToV8(impl.getAsTestInterface(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+TestInterfaceOrLong NativeValueTraits<TestInterfaceOrLong>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  TestInterfaceOrLong impl;
+  V8TestInterfaceOrLong::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrLong.h b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_long.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrLong.h
rename to third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_long.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_test_interface_empty.cc b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_test_interface_empty.cc
new file mode 100644
index 0000000..4b2b3017
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_test_interface_empty.cc
@@ -0,0 +1,112 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "test_interface_or_test_interface_empty.h"
+
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8TestInterface.h"
+#include "bindings/core/v8/V8TestInterfaceEmpty.h"
+#include "bindings/tests/idls/core/TestImplements2.h"
+#include "bindings/tests/idls/core/TestImplements3Implementation.h"
+#include "bindings/tests/idls/core/TestInterfacePartial.h"
+#include "bindings/tests/idls/core/TestInterfacePartial2Implementation.h"
+#include "bindings/tests/idls/core/TestInterfacePartialSecureContext.h"
+
+namespace blink {
+
+TestInterfaceOrTestInterfaceEmpty::TestInterfaceOrTestInterfaceEmpty() : type_(SpecificTypeNone) {}
+
+TestInterfaceImplementation* TestInterfaceOrTestInterfaceEmpty::getAsTestInterface() const {
+  DCHECK(isTestInterface());
+  return test_interface_;
+}
+
+void TestInterfaceOrTestInterfaceEmpty::setTestInterface(TestInterfaceImplementation* value) {
+  DCHECK(isNull());
+  test_interface_ = value;
+  type_ = SpecificTypeTestInterface;
+}
+
+TestInterfaceOrTestInterfaceEmpty TestInterfaceOrTestInterfaceEmpty::fromTestInterface(TestInterfaceImplementation* value) {
+  TestInterfaceOrTestInterfaceEmpty container;
+  container.setTestInterface(value);
+  return container;
+}
+
+TestInterfaceEmpty* TestInterfaceOrTestInterfaceEmpty::getAsTestInterfaceEmpty() const {
+  DCHECK(isTestInterfaceEmpty());
+  return test_interface_empty_;
+}
+
+void TestInterfaceOrTestInterfaceEmpty::setTestInterfaceEmpty(TestInterfaceEmpty* value) {
+  DCHECK(isNull());
+  test_interface_empty_ = value;
+  type_ = SpecificTypeTestInterfaceEmpty;
+}
+
+TestInterfaceOrTestInterfaceEmpty TestInterfaceOrTestInterfaceEmpty::fromTestInterfaceEmpty(TestInterfaceEmpty* value) {
+  TestInterfaceOrTestInterfaceEmpty container;
+  container.setTestInterfaceEmpty(value);
+  return container;
+}
+
+TestInterfaceOrTestInterfaceEmpty::TestInterfaceOrTestInterfaceEmpty(const TestInterfaceOrTestInterfaceEmpty&) = default;
+TestInterfaceOrTestInterfaceEmpty::~TestInterfaceOrTestInterfaceEmpty() = default;
+TestInterfaceOrTestInterfaceEmpty& TestInterfaceOrTestInterfaceEmpty::operator=(const TestInterfaceOrTestInterfaceEmpty&) = default;
+
+DEFINE_TRACE(TestInterfaceOrTestInterfaceEmpty) {
+  visitor->Trace(test_interface_);
+  visitor->Trace(test_interface_empty_);
+}
+
+void V8TestInterfaceOrTestInterfaceEmpty::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, TestInterfaceOrTestInterfaceEmpty& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8TestInterface::hasInstance(v8Value, isolate)) {
+    TestInterfaceImplementation* cppValue = V8TestInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setTestInterface(cppValue);
+    return;
+  }
+
+  if (V8TestInterfaceEmpty::hasInstance(v8Value, isolate)) {
+    TestInterfaceEmpty* cppValue = V8TestInterfaceEmpty::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setTestInterfaceEmpty(cppValue);
+    return;
+  }
+
+  exceptionState.ThrowTypeError("The provided value is not of type '(TestInterface or TestInterfaceEmpty)'");
+}
+
+v8::Local<v8::Value> ToV8(const TestInterfaceOrTestInterfaceEmpty& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case TestInterfaceOrTestInterfaceEmpty::SpecificTypeNone:
+      return v8::Null(isolate);
+    case TestInterfaceOrTestInterfaceEmpty::SpecificTypeTestInterface:
+      return ToV8(impl.getAsTestInterface(), creationContext, isolate);
+    case TestInterfaceOrTestInterfaceEmpty::SpecificTypeTestInterfaceEmpty:
+      return ToV8(impl.getAsTestInterfaceEmpty(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+TestInterfaceOrTestInterfaceEmpty NativeValueTraits<TestInterfaceOrTestInterfaceEmpty>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  TestInterfaceOrTestInterfaceEmpty impl;
+  V8TestInterfaceOrTestInterfaceEmpty::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrTestInterfaceEmpty.h b/third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_test_interface_empty.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/TestInterfaceOrTestInterfaceEmpty.h
rename to third_party/WebKit/Source/bindings/tests/results/core/test_interface_or_test_interface_empty.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/unrestricted_double_or_string.cc b/third_party/WebKit/Source/bindings/tests/results/core/unrestricted_double_or_string.cc
new file mode 100644
index 0000000..835447e2
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/unrestricted_double_or_string.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "unrestricted_double_or_string.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+UnrestrictedDoubleOrString::UnrestrictedDoubleOrString() : type_(SpecificTypeNone) {}
+
+const String& UnrestrictedDoubleOrString::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void UnrestrictedDoubleOrString::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+UnrestrictedDoubleOrString UnrestrictedDoubleOrString::fromString(const String& value) {
+  UnrestrictedDoubleOrString container;
+  container.setString(value);
+  return container;
+}
+
+double UnrestrictedDoubleOrString::getAsUnrestrictedDouble() const {
+  DCHECK(isUnrestrictedDouble());
+  return unrestricted_double_;
+}
+
+void UnrestrictedDoubleOrString::setUnrestrictedDouble(double value) {
+  DCHECK(isNull());
+  unrestricted_double_ = value;
+  type_ = SpecificTypeUnrestrictedDouble;
+}
+
+UnrestrictedDoubleOrString UnrestrictedDoubleOrString::fromUnrestrictedDouble(double value) {
+  UnrestrictedDoubleOrString container;
+  container.setUnrestrictedDouble(value);
+  return container;
+}
+
+UnrestrictedDoubleOrString::UnrestrictedDoubleOrString(const UnrestrictedDoubleOrString&) = default;
+UnrestrictedDoubleOrString::~UnrestrictedDoubleOrString() = default;
+UnrestrictedDoubleOrString& UnrestrictedDoubleOrString::operator=(const UnrestrictedDoubleOrString&) = default;
+
+DEFINE_TRACE(UnrestrictedDoubleOrString) {
+}
+
+void V8UnrestrictedDoubleOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, UnrestrictedDoubleOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsNumber()) {
+    double cppValue = NativeValueTraits<IDLUnrestrictedDouble>::NativeValue(isolate, v8Value, exceptionState);
+    if (exceptionState.HadException())
+      return;
+    impl.setUnrestrictedDouble(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const UnrestrictedDoubleOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case UnrestrictedDoubleOrString::SpecificTypeNone:
+      return v8::Null(isolate);
+    case UnrestrictedDoubleOrString::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    case UnrestrictedDoubleOrString::SpecificTypeUnrestrictedDouble:
+      return v8::Number::New(isolate, impl.getAsUnrestrictedDouble());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+UnrestrictedDoubleOrString NativeValueTraits<UnrestrictedDoubleOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  UnrestrictedDoubleOrString impl;
+  V8UnrestrictedDoubleOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/UnrestrictedDoubleOrString.h b/third_party/WebKit/Source/bindings/tests/results/core/unrestricted_double_or_string.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/UnrestrictedDoubleOrString.h
rename to third_party/WebKit/Source/bindings/tests/results/core/unrestricted_double_or_string.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/unsigned_long_long_or_boolean_or_test_callback_interface.cc b/third_party/WebKit/Source/bindings/tests/results/core/unsigned_long_long_or_boolean_or_test_callback_interface.cc
new file mode 100644
index 0000000..70dabd7
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/unsigned_long_long_or_boolean_or_test_callback_interface.cc
@@ -0,0 +1,139 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "unsigned_long_long_or_boolean_or_test_callback_interface.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8TestCallbackInterface.h"
+
+namespace blink {
+
+UnsignedLongLongOrBooleanOrTestCallbackInterface::UnsignedLongLongOrBooleanOrTestCallbackInterface() : type_(SpecificTypeNone) {}
+
+bool UnsignedLongLongOrBooleanOrTestCallbackInterface::getAsBoolean() const {
+  DCHECK(isBoolean());
+  return boolean_;
+}
+
+void UnsignedLongLongOrBooleanOrTestCallbackInterface::setBoolean(bool value) {
+  DCHECK(isNull());
+  boolean_ = value;
+  type_ = SpecificTypeBoolean;
+}
+
+UnsignedLongLongOrBooleanOrTestCallbackInterface UnsignedLongLongOrBooleanOrTestCallbackInterface::fromBoolean(bool value) {
+  UnsignedLongLongOrBooleanOrTestCallbackInterface container;
+  container.setBoolean(value);
+  return container;
+}
+
+TestCallbackInterface* UnsignedLongLongOrBooleanOrTestCallbackInterface::getAsTestCallbackInterface() const {
+  DCHECK(isTestCallbackInterface());
+  return test_callback_interface_;
+}
+
+void UnsignedLongLongOrBooleanOrTestCallbackInterface::setTestCallbackInterface(TestCallbackInterface* value) {
+  DCHECK(isNull());
+  test_callback_interface_ = value;
+  type_ = SpecificTypeTestCallbackInterface;
+}
+
+UnsignedLongLongOrBooleanOrTestCallbackInterface UnsignedLongLongOrBooleanOrTestCallbackInterface::fromTestCallbackInterface(TestCallbackInterface* value) {
+  UnsignedLongLongOrBooleanOrTestCallbackInterface container;
+  container.setTestCallbackInterface(value);
+  return container;
+}
+
+uint64_t UnsignedLongLongOrBooleanOrTestCallbackInterface::getAsUnsignedLongLong() const {
+  DCHECK(isUnsignedLongLong());
+  return unsigned_long_long_;
+}
+
+void UnsignedLongLongOrBooleanOrTestCallbackInterface::setUnsignedLongLong(uint64_t value) {
+  DCHECK(isNull());
+  unsigned_long_long_ = value;
+  type_ = SpecificTypeUnsignedLongLong;
+}
+
+UnsignedLongLongOrBooleanOrTestCallbackInterface UnsignedLongLongOrBooleanOrTestCallbackInterface::fromUnsignedLongLong(uint64_t value) {
+  UnsignedLongLongOrBooleanOrTestCallbackInterface container;
+  container.setUnsignedLongLong(value);
+  return container;
+}
+
+UnsignedLongLongOrBooleanOrTestCallbackInterface::UnsignedLongLongOrBooleanOrTestCallbackInterface(const UnsignedLongLongOrBooleanOrTestCallbackInterface&) = default;
+UnsignedLongLongOrBooleanOrTestCallbackInterface::~UnsignedLongLongOrBooleanOrTestCallbackInterface() = default;
+UnsignedLongLongOrBooleanOrTestCallbackInterface& UnsignedLongLongOrBooleanOrTestCallbackInterface::operator=(const UnsignedLongLongOrBooleanOrTestCallbackInterface&) = default;
+
+DEFINE_TRACE(UnsignedLongLongOrBooleanOrTestCallbackInterface) {
+  visitor->Trace(test_callback_interface_);
+}
+
+void V8UnsignedLongLongOrBooleanOrTestCallbackInterface::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, UnsignedLongLongOrBooleanOrTestCallbackInterface& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8TestCallbackInterface::hasInstance(v8Value, isolate)) {
+    TestCallbackInterface* cppValue = V8TestCallbackInterface::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setTestCallbackInterface(cppValue);
+    return;
+  }
+
+  if (v8Value->IsBoolean()) {
+    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
+    return;
+  }
+
+  if (v8Value->IsNumber()) {
+    uint64_t cppValue = NativeValueTraits<IDLUnsignedLongLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setUnsignedLongLong(cppValue);
+    return;
+  }
+
+  {
+    uint64_t cppValue = NativeValueTraits<IDLUnsignedLongLong>::NativeValue(isolate, v8Value, exceptionState, kNormalConversion);
+    if (exceptionState.HadException())
+      return;
+    impl.setUnsignedLongLong(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const UnsignedLongLongOrBooleanOrTestCallbackInterface& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeNone:
+      return v8::Null(isolate);
+    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeBoolean:
+      return v8::Boolean::New(isolate, impl.getAsBoolean());
+    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeTestCallbackInterface:
+      return ToV8(impl.getAsTestCallbackInterface(), creationContext, isolate);
+    case UnsignedLongLongOrBooleanOrTestCallbackInterface::SpecificTypeUnsignedLongLong:
+      return v8::Number::New(isolate, static_cast<double>(impl.getAsUnsignedLongLong()));
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+UnsignedLongLongOrBooleanOrTestCallbackInterface NativeValueTraits<UnsignedLongLongOrBooleanOrTestCallbackInterface>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  UnsignedLongLongOrBooleanOrTestCallbackInterface impl;
+  V8UnsignedLongLongOrBooleanOrTestCallbackInterface::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/UnsignedLongLongOrBooleanOrTestCallbackInterface.h b/third_party/WebKit/Source/bindings/tests/results/core/unsigned_long_long_or_boolean_or_test_callback_interface.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/UnsignedLongLongOrBooleanOrTestCallbackInterface.h
rename to third_party/WebKit/Source/bindings/tests/results/core/unsigned_long_long_or_boolean_or_test_callback_interface.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function.cc b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function.cc
new file mode 100644
index 0000000..152f817
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function.cc
@@ -0,0 +1,92 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "void_callback_function.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+VoidCallbackFunction* VoidCallbackFunction::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new VoidCallbackFunction(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+VoidCallbackFunction::VoidCallbackFunction(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(VoidCallbackFunction) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool VoidCallbackFunction::call(ScriptWrappable* scriptWrappable) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> *argv = nullptr;
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    0,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  return true;
+}
+
+VoidCallbackFunction* NativeValueTraits<VoidCallbackFunction>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  VoidCallbackFunction* nativeValue = VoidCallbackFunction::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "VoidCallbackFunction"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.h b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunction.h
rename to third_party/WebKit/Source/bindings/tests/results/core/void_callback_function.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_dictionary_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_dictionary_arg.cc
new file mode 100644
index 0000000..2b38df0
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_dictionary_arg.cc
@@ -0,0 +1,94 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "void_callback_function_dictionary_arg.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/V8TestDictionary.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+VoidCallbackFunctionDictionaryArg* VoidCallbackFunctionDictionaryArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new VoidCallbackFunctionDictionaryArg(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+VoidCallbackFunctionDictionaryArg::VoidCallbackFunctionDictionaryArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionDictionaryArg) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool VoidCallbackFunctionDictionaryArg::call(ScriptWrappable* scriptWrappable, const TestDictionary& arg) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate());
+  v8::Local<v8::Value> argv[] = { v8_arg };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    1,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  return true;
+}
+
+VoidCallbackFunctionDictionaryArg* NativeValueTraits<VoidCallbackFunctionDictionaryArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  VoidCallbackFunctionDictionaryArg* nativeValue = VoidCallbackFunctionDictionaryArg::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "VoidCallbackFunctionDictionaryArg"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.h b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_dictionary_arg.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionDictionaryArg.h
rename to third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_dictionary_arg.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_enum_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_enum_arg.cc
new file mode 100644
index 0000000..59b9759
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_enum_arg.cc
@@ -0,0 +1,105 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "void_callback_function_enum_arg.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+VoidCallbackFunctionEnumArg* VoidCallbackFunctionEnumArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new VoidCallbackFunctionEnumArg(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+VoidCallbackFunctionEnumArg::VoidCallbackFunctionEnumArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionEnumArg) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool VoidCallbackFunctionEnumArg::call(ScriptWrappable* scriptWrappable, const String& arg) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  const char* valid_arg_values[] = {
+      "",
+      "EnumValue1",
+      "EnumValue2",
+      "EnumValue3",
+  };
+  if (!IsValidEnum(arg, valid_arg_values, WTF_ARRAY_LENGTH(valid_arg_values), "TestEnum", exceptionState)) {
+    NOTREACHED();
+    return false;
+  }
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_arg = V8String(script_state_->GetIsolate(), arg);
+  v8::Local<v8::Value> argv[] = { v8_arg };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    1,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  return true;
+}
+
+VoidCallbackFunctionEnumArg* NativeValueTraits<VoidCallbackFunctionEnumArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  VoidCallbackFunctionEnumArg* nativeValue = VoidCallbackFunctionEnumArg::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "VoidCallbackFunctionEnumArg"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.h b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_enum_arg.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionEnumArg.h
rename to third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_enum_arg.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_interface_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_interface_arg.cc
new file mode 100644
index 0000000..de2495d
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_interface_arg.cc
@@ -0,0 +1,94 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "void_callback_function_interface_arg.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/V8HTMLDivElement.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+VoidCallbackFunctionInterfaceArg* VoidCallbackFunctionInterfaceArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new VoidCallbackFunctionInterfaceArg(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+VoidCallbackFunctionInterfaceArg::VoidCallbackFunctionInterfaceArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionInterfaceArg) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool VoidCallbackFunctionInterfaceArg::call(ScriptWrappable* scriptWrappable, HTMLDivElement* divElement) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_divElement = ToV8(divElement, script_state_->GetContext()->Global(), script_state_->GetIsolate());
+  v8::Local<v8::Value> argv[] = { v8_divElement };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    1,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  return true;
+}
+
+VoidCallbackFunctionInterfaceArg* NativeValueTraits<VoidCallbackFunctionInterfaceArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  VoidCallbackFunctionInterfaceArg* nativeValue = VoidCallbackFunctionInterfaceArg::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "VoidCallbackFunctionInterfaceArg"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.h b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_interface_arg.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionInterfaceArg.h
rename to third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_interface_arg.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_test_interface_sequence_arg.cc b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_test_interface_sequence_arg.cc
new file mode 100644
index 0000000..864adf6
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_test_interface_sequence_arg.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "void_callback_function_test_interface_sequence_arg.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/V8TestInterface.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+VoidCallbackFunctionTestInterfaceSequenceArg* VoidCallbackFunctionTestInterfaceSequenceArg::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new VoidCallbackFunctionTestInterfaceSequenceArg(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+VoidCallbackFunctionTestInterfaceSequenceArg::VoidCallbackFunctionTestInterfaceSequenceArg(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionTestInterfaceSequenceArg) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool VoidCallbackFunctionTestInterfaceSequenceArg::call(ScriptWrappable* scriptWrappable, const HeapVector<Member<TestInterfaceImplementation>>& arg) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_arg = ToV8(arg, script_state_->GetContext()->Global(), script_state_->GetIsolate());
+  v8::Local<v8::Value> argv[] = { v8_arg };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    1,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  return true;
+}
+
+VoidCallbackFunctionTestInterfaceSequenceArg* NativeValueTraits<VoidCallbackFunctionTestInterfaceSequenceArg>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  VoidCallbackFunctionTestInterfaceSequenceArg* nativeValue = VoidCallbackFunctionTestInterfaceSequenceArg::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "VoidCallbackFunctionTestInterfaceSequenceArg"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.h b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_test_interface_sequence_arg.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTestInterfaceSequenceArg.h
rename to third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_test_interface_sequence_arg.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_typedef.cc b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_typedef.cc
new file mode 100644
index 0000000..7e97c5e
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_typedef.cc
@@ -0,0 +1,94 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "void_callback_function_typedef.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+VoidCallbackFunctionTypedef* VoidCallbackFunctionTypedef::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new VoidCallbackFunctionTypedef(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+VoidCallbackFunctionTypedef::VoidCallbackFunctionTypedef(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionTypedef) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool VoidCallbackFunctionTypedef::call(ScriptWrappable* scriptWrappable, const String& arg) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> v8_arg = V8String(script_state_->GetIsolate(), arg);
+  v8::Local<v8::Value> argv[] = { v8_arg };
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    1,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  return true;
+}
+
+VoidCallbackFunctionTypedef* NativeValueTraits<VoidCallbackFunctionTypedef>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  VoidCallbackFunctionTypedef* nativeValue = VoidCallbackFunctionTypedef::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "VoidCallbackFunctionTypedef"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.h b/third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_typedef.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/VoidCallbackFunctionTypedef.h
rename to third_party/WebKit/Source/bindings/tests/results/core/void_callback_function_typedef.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/xml_http_request_or_string.cc b/third_party/WebKit/Source/bindings/tests/results/core/xml_http_request_or_string.cc
new file mode 100644
index 0000000..71d9f37
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/core/xml_http_request_or_string.cc
@@ -0,0 +1,107 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "xml_http_request_or_string.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8XMLHttpRequest.h"
+
+namespace blink {
+
+XMLHttpRequestOrString::XMLHttpRequestOrString() : type_(SpecificTypeNone) {}
+
+const String& XMLHttpRequestOrString::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void XMLHttpRequestOrString::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+XMLHttpRequestOrString XMLHttpRequestOrString::fromString(const String& value) {
+  XMLHttpRequestOrString container;
+  container.setString(value);
+  return container;
+}
+
+XMLHttpRequest* XMLHttpRequestOrString::getAsXMLHttpRequest() const {
+  DCHECK(isXMLHttpRequest());
+  return xml_http_request_;
+}
+
+void XMLHttpRequestOrString::setXMLHttpRequest(XMLHttpRequest* value) {
+  DCHECK(isNull());
+  xml_http_request_ = value;
+  type_ = SpecificTypeXMLHttpRequest;
+}
+
+XMLHttpRequestOrString XMLHttpRequestOrString::fromXMLHttpRequest(XMLHttpRequest* value) {
+  XMLHttpRequestOrString container;
+  container.setXMLHttpRequest(value);
+  return container;
+}
+
+XMLHttpRequestOrString::XMLHttpRequestOrString(const XMLHttpRequestOrString&) = default;
+XMLHttpRequestOrString::~XMLHttpRequestOrString() = default;
+XMLHttpRequestOrString& XMLHttpRequestOrString::operator=(const XMLHttpRequestOrString&) = default;
+
+DEFINE_TRACE(XMLHttpRequestOrString) {
+  visitor->Trace(xml_http_request_);
+}
+
+void V8XMLHttpRequestOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, XMLHttpRequestOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (V8XMLHttpRequest::hasInstance(v8Value, isolate)) {
+    XMLHttpRequest* cppValue = V8XMLHttpRequest::toImpl(v8::Local<v8::Object>::Cast(v8Value));
+    impl.setXMLHttpRequest(cppValue);
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const XMLHttpRequestOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case XMLHttpRequestOrString::SpecificTypeNone:
+      return v8::Null(isolate);
+    case XMLHttpRequestOrString::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    case XMLHttpRequestOrString::SpecificTypeXMLHttpRequest:
+      return ToV8(impl.getAsXMLHttpRequest(), creationContext, isolate);
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+XMLHttpRequestOrString NativeValueTraits<XMLHttpRequestOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  XMLHttpRequestOrString impl;
+  V8XMLHttpRequestOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/XMLHttpRequestOrString.h b/third_party/WebKit/Source/bindings/tests/results/core/xml_http_request_or_string.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/core/XMLHttpRequestOrString.h
rename to third_party/WebKit/Source/bindings/tests/results/core/xml_http_request_or_string.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/BooleanOrString.cpp b/third_party/WebKit/Source/bindings/tests/results/modules/BooleanOrString.cpp
deleted file mode 100644
index 2d8c509..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/modules/BooleanOrString.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
-
-// clang-format off
-#include "BooleanOrString.h"
-
-#include "bindings/core/v8/IDLTypes.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-
-namespace blink {
-
-BooleanOrString::BooleanOrString() : type_(SpecificTypeNone) {}
-
-bool BooleanOrString::getAsBoolean() const {
-  DCHECK(isBoolean());
-  return boolean_;
-}
-
-void BooleanOrString::setBoolean(bool value) {
-  DCHECK(isNull());
-  boolean_ = value;
-  type_ = SpecificTypeBoolean;
-}
-
-BooleanOrString BooleanOrString::fromBoolean(bool value) {
-  BooleanOrString container;
-  container.setBoolean(value);
-  return container;
-}
-
-const String& BooleanOrString::getAsString() const {
-  DCHECK(isString());
-  return string_;
-}
-
-void BooleanOrString::setString(const String& value) {
-  DCHECK(isNull());
-  string_ = value;
-  type_ = SpecificTypeString;
-}
-
-BooleanOrString BooleanOrString::fromString(const String& value) {
-  BooleanOrString container;
-  container.setString(value);
-  return container;
-}
-
-BooleanOrString::BooleanOrString(const BooleanOrString&) = default;
-BooleanOrString::~BooleanOrString() = default;
-BooleanOrString& BooleanOrString::operator=(const BooleanOrString&) = default;
-
-DEFINE_TRACE(BooleanOrString) {
-}
-
-void V8BooleanOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
-  if (v8Value.IsEmpty())
-    return;
-
-  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
-    return;
-
-  if (v8Value->IsBoolean()) {
-    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
-    return;
-  }
-
-  {
-    V8StringResource<> cppValue = v8Value;
-    if (!cppValue.Prepare(exceptionState))
-      return;
-    impl.setString(cppValue);
-    return;
-  }
-}
-
-v8::Local<v8::Value> ToV8(const BooleanOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
-  switch (impl.type_) {
-    case BooleanOrString::SpecificTypeNone:
-      return v8::Null(isolate);
-    case BooleanOrString::SpecificTypeBoolean:
-      return v8::Boolean::New(isolate, impl.getAsBoolean());
-    case BooleanOrString::SpecificTypeString:
-      return V8String(isolate, impl.getAsString());
-    default:
-      NOTREACHED();
-  }
-  return v8::Local<v8::Value>();
-}
-
-BooleanOrString NativeValueTraits<BooleanOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  BooleanOrString impl;
-  V8BooleanOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
-  return impl;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp
index 6206c738..f2a2b29 100644
--- a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp
@@ -17,7 +17,7 @@
 #include "bindings/core/v8/V8DOMConfiguration.h"
 #include "bindings/core/v8/V8TestInterfaceEmpty.h"
 #include "bindings/modules/v8/V8TestInterface5.h"
-#include "bindings/modules/v8/VoidCallbackFunctionModules.h"
+#include "bindings/modules/v8/void_callback_function_modules.h"
 #include "core/dom/ExecutionContext.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/bindings/RuntimeCallStats.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.h b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.h
index cba881e0..88ff52d 100644
--- a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.h
+++ b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.h
@@ -12,13 +12,13 @@
 #ifndef V8TestInterface5_h
 #define V8TestInterface5_h
 
-#include "bindings/core/v8/DoubleOrString.h"
 #include "bindings/core/v8/GeneratedCodeHelper.h"
 #include "bindings/core/v8/NativeValueTraits.h"
 #include "bindings/core/v8/ToV8ForCore.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8TestInterfaceEmpty.h"
-#include "bindings/modules/v8/BooleanOrString.h"
+#include "bindings/core/v8/double_or_string.h"
+#include "bindings/modules/v8/boolean_or_string.h"
 #include "bindings/tests/idls/modules/TestInterface5Implementation.h"
 #include "modules/ModulesExport.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.h b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.h
index 110f27e1..c777498 100644
--- a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.h
+++ b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterfacePartial.h
@@ -15,8 +15,8 @@
 #include "bindings/core/v8/GeneratedCodeHelper.h"
 #include "bindings/core/v8/NativeValueTraits.h"
 #include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/UnsignedLongLongOrBooleanOrTestCallbackInterface.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/unsigned_long_long_or_boolean_or_test_callback_interface.h"
 #include "bindings/tests/idls/core/TestInterfaceImplementation.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/bindings/V8DOMWrapper.h"
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.cpp b/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.cpp
deleted file mode 100644
index 3c76983..0000000
--- a/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
-// DO NOT MODIFY!
-
-// This file has been generated from the Jinja2 template in
-// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
-
-// clang-format off
-
-#include "VoidCallbackFunctionModules.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/NativeValueTraitsImpl.h"
-#include "bindings/core/v8/ToV8ForCore.h"
-#include "bindings/core/v8/V8BindingForCore.h"
-#include "core/dom/ExecutionContext.h"
-#include "platform/bindings/ScriptState.h"
-#include "platform/wtf/Assertions.h"
-
-namespace blink {
-
-// static
-VoidCallbackFunctionModules* VoidCallbackFunctionModules::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
-  if (IsUndefinedOrNull(callback))
-    return nullptr;
-  return new VoidCallbackFunctionModules(scriptState, v8::Local<v8::Function>::Cast(callback));
-}
-
-VoidCallbackFunctionModules::VoidCallbackFunctionModules(ScriptState* scriptState, v8::Local<v8::Function> callback)
-    : script_state_(scriptState),
-    callback_(scriptState->GetIsolate(), this, callback) {
-  DCHECK(!callback_.IsEmpty());
-}
-
-DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionModules) {
-  visitor->TraceWrappers(callback_.Cast<v8::Value>());
-}
-
-bool VoidCallbackFunctionModules::call(ScriptWrappable* scriptWrappable) {
-  if (callback_.IsEmpty())
-    return false;
-
-  if (!script_state_->ContextIsValid())
-    return false;
-
-  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
-  // crbug.com/653769
-  DummyExceptionStateForTesting exceptionState;
-
-  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
-  DCHECK(context);
-  if (context->IsContextSuspended() || context->IsContextDestroyed())
-    return false;
-
-  ScriptState::Scope scope(script_state_.Get());
-  v8::Isolate* isolate = script_state_->GetIsolate();
-
-  v8::Local<v8::Value> thisValue = ToV8(
-      scriptWrappable,
-      script_state_->GetContext()->Global(),
-      isolate);
-
-  v8::Local<v8::Value> *argv = nullptr;
-  v8::TryCatch exceptionCatcher(isolate);
-  exceptionCatcher.SetVerbose(true);
-
-  v8::Local<v8::Value> v8ReturnValue;
-  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
-                                    context,
-                                    thisValue,
-                                    0,
-                                    argv,
-                                    isolate).ToLocal(&v8ReturnValue)) {
-    return false;
-  }
-
-  return true;
-}
-
-VoidCallbackFunctionModules* NativeValueTraits<VoidCallbackFunctionModules>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
-  VoidCallbackFunctionModules* nativeValue = VoidCallbackFunctionModules::Create(ScriptState::Current(isolate), value);
-  if (!nativeValue) {
-    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
-        "VoidCallbackFunctionModules"));
-  }
-  return nativeValue;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/boolean_or_string.cc b/third_party/WebKit/Source/bindings/tests/results/modules/boolean_or_string.cc
new file mode 100644
index 0000000..2dcbc4e
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/modules/boolean_or_string.cc
@@ -0,0 +1,104 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/union_container.cpp.tmpl
+
+// clang-format off
+#include "boolean_or_string.h"
+
+#include "bindings/core/v8/IDLTypes.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+
+namespace blink {
+
+BooleanOrString::BooleanOrString() : type_(SpecificTypeNone) {}
+
+bool BooleanOrString::getAsBoolean() const {
+  DCHECK(isBoolean());
+  return boolean_;
+}
+
+void BooleanOrString::setBoolean(bool value) {
+  DCHECK(isNull());
+  boolean_ = value;
+  type_ = SpecificTypeBoolean;
+}
+
+BooleanOrString BooleanOrString::fromBoolean(bool value) {
+  BooleanOrString container;
+  container.setBoolean(value);
+  return container;
+}
+
+const String& BooleanOrString::getAsString() const {
+  DCHECK(isString());
+  return string_;
+}
+
+void BooleanOrString::setString(const String& value) {
+  DCHECK(isNull());
+  string_ = value;
+  type_ = SpecificTypeString;
+}
+
+BooleanOrString BooleanOrString::fromString(const String& value) {
+  BooleanOrString container;
+  container.setString(value);
+  return container;
+}
+
+BooleanOrString::BooleanOrString(const BooleanOrString&) = default;
+BooleanOrString::~BooleanOrString() = default;
+BooleanOrString& BooleanOrString::operator=(const BooleanOrString&) = default;
+
+DEFINE_TRACE(BooleanOrString) {
+}
+
+void V8BooleanOrString::toImpl(v8::Isolate* isolate, v8::Local<v8::Value> v8Value, BooleanOrString& impl, UnionTypeConversionMode conversionMode, ExceptionState& exceptionState) {
+  if (v8Value.IsEmpty())
+    return;
+
+  if (conversionMode == UnionTypeConversionMode::kNullable && IsUndefinedOrNull(v8Value))
+    return;
+
+  if (v8Value->IsBoolean()) {
+    impl.setBoolean(v8Value.As<v8::Boolean>()->Value());
+    return;
+  }
+
+  {
+    V8StringResource<> cppValue = v8Value;
+    if (!cppValue.Prepare(exceptionState))
+      return;
+    impl.setString(cppValue);
+    return;
+  }
+}
+
+v8::Local<v8::Value> ToV8(const BooleanOrString& impl, v8::Local<v8::Object> creationContext, v8::Isolate* isolate) {
+  switch (impl.type_) {
+    case BooleanOrString::SpecificTypeNone:
+      return v8::Null(isolate);
+    case BooleanOrString::SpecificTypeBoolean:
+      return v8::Boolean::New(isolate, impl.getAsBoolean());
+    case BooleanOrString::SpecificTypeString:
+      return V8String(isolate, impl.getAsString());
+    default:
+      NOTREACHED();
+  }
+  return v8::Local<v8::Value>();
+}
+
+BooleanOrString NativeValueTraits<BooleanOrString>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  BooleanOrString impl;
+  V8BooleanOrString::toImpl(isolate, value, impl, UnionTypeConversionMode::kNotNullable, exceptionState);
+  return impl;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/BooleanOrString.h b/third_party/WebKit/Source/bindings/tests/results/modules/boolean_or_string.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/modules/BooleanOrString.h
rename to third_party/WebKit/Source/bindings/tests/results/modules/boolean_or_string.h
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/void_callback_function_modules.cc b/third_party/WebKit/Source/bindings/tests/results/modules/void_callback_function_modules.cc
new file mode 100644
index 0000000..9c307e50
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/tests/results/modules/void_callback_function_modules.cc
@@ -0,0 +1,92 @@
+// Copyright 2014 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 has been auto-generated by code_generator_v8.py.
+// DO NOT MODIFY!
+
+// This file has been generated from the Jinja2 template in
+// third_party/WebKit/Source/bindings/templates/callback_function.cpp.tmpl
+
+// clang-format off
+
+#include "void_callback_function_modules.h"
+
+#include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/NativeValueTraitsImpl.h"
+#include "bindings/core/v8/ToV8ForCore.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "core/dom/ExecutionContext.h"
+#include "platform/bindings/ScriptState.h"
+#include "platform/wtf/Assertions.h"
+
+namespace blink {
+
+// static
+VoidCallbackFunctionModules* VoidCallbackFunctionModules::Create(ScriptState* scriptState, v8::Local<v8::Value> callback) {
+  if (IsUndefinedOrNull(callback))
+    return nullptr;
+  return new VoidCallbackFunctionModules(scriptState, v8::Local<v8::Function>::Cast(callback));
+}
+
+VoidCallbackFunctionModules::VoidCallbackFunctionModules(ScriptState* scriptState, v8::Local<v8::Function> callback)
+    : script_state_(scriptState),
+    callback_(scriptState->GetIsolate(), this, callback) {
+  DCHECK(!callback_.IsEmpty());
+}
+
+DEFINE_TRACE_WRAPPERS(VoidCallbackFunctionModules) {
+  visitor->TraceWrappers(callback_.Cast<v8::Value>());
+}
+
+bool VoidCallbackFunctionModules::call(ScriptWrappable* scriptWrappable) {
+  if (callback_.IsEmpty())
+    return false;
+
+  if (!script_state_->ContextIsValid())
+    return false;
+
+  // TODO(bashi): Make sure that using DummyExceptionStateForTesting is OK.
+  // crbug.com/653769
+  DummyExceptionStateForTesting exceptionState;
+
+  ExecutionContext* context = ExecutionContext::From(script_state_.Get());
+  DCHECK(context);
+  if (context->IsContextSuspended() || context->IsContextDestroyed())
+    return false;
+
+  ScriptState::Scope scope(script_state_.Get());
+  v8::Isolate* isolate = script_state_->GetIsolate();
+
+  v8::Local<v8::Value> thisValue = ToV8(
+      scriptWrappable,
+      script_state_->GetContext()->Global(),
+      isolate);
+
+  v8::Local<v8::Value> *argv = nullptr;
+  v8::TryCatch exceptionCatcher(isolate);
+  exceptionCatcher.SetVerbose(true);
+
+  v8::Local<v8::Value> v8ReturnValue;
+  if (!V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
+                                    context,
+                                    thisValue,
+                                    0,
+                                    argv,
+                                    isolate).ToLocal(&v8ReturnValue)) {
+    return false;
+  }
+
+  return true;
+}
+
+VoidCallbackFunctionModules* NativeValueTraits<VoidCallbackFunctionModules>::NativeValue(v8::Isolate* isolate, v8::Local<v8::Value> value, ExceptionState& exceptionState) {
+  VoidCallbackFunctionModules* nativeValue = VoidCallbackFunctionModules::Create(ScriptState::Current(isolate), value);
+  if (!nativeValue) {
+    exceptionState.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
+        "VoidCallbackFunctionModules"));
+  }
+  return nativeValue;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.h b/third_party/WebKit/Source/bindings/tests/results/modules/void_callback_function_modules.h
similarity index 100%
rename from third_party/WebKit/Source/bindings/tests/results/modules/VoidCallbackFunctionModules.h
rename to third_party/WebKit/Source/bindings/tests/results/modules/void_callback_function_modules.h
diff --git a/third_party/WebKit/Source/build/scripts/cluster.py b/third_party/WebKit/Source/build/scripts/cluster.py
new file mode 100644
index 0000000..7799f3d7
--- /dev/null
+++ b/third_party/WebKit/Source/build/scripts/cluster.py
@@ -0,0 +1,83 @@
+import math
+import random as rand
+
+
+def l2_pairwise_distance(v1, v2):
+    """Euclidean distance from each point in v1 to each point in v2
+
+    Args:
+        v1: list of point 1
+        v2: list of point 2
+
+    Returns:
+        distance matrix between each point in v1 and v2
+    """
+    nrow = len(v1)
+    ncol = len(v2)
+    dist_mat = [[0 for _ in range(ncol)] for _ in range(nrow)]
+    for i in range(nrow):
+        for j in range(ncol):
+            dist_mat[i][j] = math.sqrt((v1[i] - v2[j]) ** 2)
+    return dist_mat
+
+
+def calculate_error(k_means_matrix):
+    """Calculate the sum of distance from each point to its nearest cluster center
+
+    Args:
+        k_means_matrix: distance matrix of point to cluster center
+
+    Returns:
+        Sum of distance from each point to its nearest cluster center
+    """
+    return sum([min(dist) for dist in k_means_matrix])
+
+
+def k_means(x_input, n_cluster=3, n_iter=100, n_tries=10):
+    """Perform 1-D k-means clustering on a list of numbers x_input
+
+    Args:
+        x_input: list of numbers
+        n_cluster: number of clusters
+        n_iter: number of iterations
+
+    Returns:
+        centers: list of n_cluster elements containing the cluster centers
+        min_dist_idx: list of len(x_input) elements containing the nearest cluster center's id
+        error_value: sum of all distance from each point to its nearest cluster center
+    """
+    results = []
+    for _ in range(n_tries):
+        error_value = 0
+        rand.seed(None)
+        centers = sorted([rand.uniform(0.0, 100.0) for i in range(n_cluster)])
+        min_dist_idx = [0] * len(x_input)
+        i = 0
+        while i < n_iter:
+            failed = False
+            dist_mat = l2_pairwise_distance(x_input, centers)
+            error_value = calculate_error(dist_mat)
+            min_dist_idx = [dist.index(min(dist)) for dist in dist_mat]
+            centers = [0] * n_cluster
+            count = [0] * n_cluster
+            for j in range(len(x_input)):
+                centers[min_dist_idx[j]] += x_input[j]
+                count[min_dist_idx[j]] += 1
+
+            for j in range(n_cluster):
+                if count[j] == 0:
+                    centers = sorted([rand.uniform(0.0, 100.0) for i in range(n_cluster)])
+                    failed = True
+                    break
+
+            if failed:
+                i = 0
+                continue
+
+            for j in range(n_cluster):
+                centers[j] = centers[j] / count[j]
+            i += 1
+
+        results.append((centers, min_dist_idx, error_value))
+
+    return min(results, key=lambda x: x[2])
diff --git a/third_party/WebKit/Source/build/scripts/core/css/properties/make_css_property_api_headers.py b/third_party/WebKit/Source/build/scripts/core/css/properties/make_css_property_api_headers.py
index a6629071..8924f55a 100755
--- a/third_party/WebKit/Source/build/scripts/core/css/properties/make_css_property_api_headers.py
+++ b/third_party/WebKit/Source/build/scripts/core/css/properties/make_css_property_api_headers.py
@@ -10,7 +10,7 @@
 import json5_generator
 import template_expander
 
-from collections import namedtuple, defaultdict
+from collections import namedtuple, Counter
 from make_css_property_api_base import CSSPropertyAPIWriter
 
 
@@ -35,6 +35,7 @@
                 return_type=api_method['return_type'],
                 parameters=api_method['parameters'],
             )
+        self.validate_input()
 
         self._outputs = {}
         for property_ in self.properties().values():
@@ -60,5 +61,18 @@
             }
         return generate_property_api_h
 
+    def validate_input(self):
+        classname_counts = Counter(
+            property_['api_class'] for property_ in self.properties().values()
+            if property_['api_class'] not in (None, True))
+        for property_ in self.properties().values():
+            api_class = property_['api_class']
+            if api_class not in (None, True):
+                assert classname_counts[api_class] != 1,\
+                    ("Unique api_class '" + api_class + "' defined on '" +
+                     property_['name'] + "' property. api_class as string is " +
+                     "reserved for grouped properties. Did you mean " +
+                     "'api_class: true'?")
+
 if __name__ == '__main__':
     json5_generator.Maker(CSSPropertyAPIHeadersWriter).main()
diff --git a/third_party/WebKit/Source/build/scripts/json5_generator.py b/third_party/WebKit/Source/build/scripts/json5_generator.py
index 4d9bef9f..dbfabe5 100644
--- a/third_party/WebKit/Source/build/scripts/json5_generator.py
+++ b/third_party/WebKit/Source/build/scripts/json5_generator.py
@@ -89,6 +89,14 @@
         _merge_dict("data")
 
 
+def _is_valid(valid_values, value):
+    if type(value) == str and all([type(i) == str for i in valid_values]):
+        return any([(value == valid) or (re.match("^" + valid + "$", value) is not None)
+                    for valid in valid_values])
+    else:
+        return value in valid_values
+
+
 class Json5File(object):
     def __init__(self, file_paths, doc, default_metadata=None, default_parameters=None):
         self.file_paths = file_paths
@@ -181,12 +189,12 @@
         # validate each item in the value list against valid_values.
         if valid_type == "list" and type(valid_values[0]) is not list:
             for item in value:
-                if item not in valid_values:
-                    raise Exception("Unknown value: '%s'\nKnown values: %s" %
-                                    (item, valid_values))
-        elif value not in valid_values:
-            raise Exception("Unknown value: '%s'\nKnown values: %s" %
-                            (value, valid_values))
+                if not _is_valid(valid_values, item):
+                    raise Exception("Unknown value: '%s'\nValid values: %s, \
+                        Please change your value to a valid value" % (item, valid_values))
+        elif not _is_valid(valid_values, value):
+            raise Exception("Unknown value: '%s'\nValid values: %s, \
+                Please change your value to a valid value" % (value, valid_values))
 
 
 class Writer(object):
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
index 41c1f9c..8bca49d 100755
--- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
+++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -218,7 +218,7 @@
     return list(sorted(include_paths))
 
 
-def _create_groups(properties):
+def _create_groups(properties, alias_dictionary):
     """Create a tree of groups from a list of properties.
 
     Returns:
@@ -251,7 +251,7 @@
             for group_name in property_['field_group'].split('->'):
                 current_group_dict[group_name] = current_group_dict.get(group_name, {None: []})
                 current_group_dict = current_group_dict[group_name]
-        current_group_dict[None].extend(_create_fields(property_))
+        current_group_dict[None].extend(_create_fields(property_, alias_dictionary))
 
     return _dict_to_group(None, root_group_dict)
 
@@ -326,7 +326,7 @@
     return list(sorted(enums.values(), key=lambda e: e.type_name))
 
 
-def _create_property_field(property_):
+def _create_property_field(property_, alias_dictionary):
     """
     Create a property field.
     """
@@ -336,6 +336,12 @@
         ('MakeComputedStyleBase requires an default value for all fields, none specified '
          'for property ' + property_['name'])
 
+    if property_['field_template'] in alias_dictionary:
+        alias_template = property_['field_template']
+        for field in alias_dictionary[alias_template]:
+            if field != 'name':
+                property_[field] = alias_dictionary[alias_template][field]
+
     if property_['field_template'] == 'keyword':
         type_name = property_['type_name']
         default_value = type_name + '::' + enum_value_name(property_['default_value'])
@@ -373,12 +379,6 @@
         type_name = property_['type_name']
         default_value = property_['default_value']
         size = None
-    elif property_['field_template'] == '<length>':
-        property_['field_template'] = 'external'
-        property_['type_name'] = type_name = 'Length'
-        default_value = property_['default_value']
-        property_['include_paths'] = ["platform/Length.h"]
-        size = None
     else:
         assert property_['field_template'] in ('monotonic_flag',)
         type_name = 'bool'
@@ -436,7 +436,7 @@
     )
 
 
-def _create_fields(property_):
+def _create_fields(property_, alias_dictionary):
     """
     Create ComputedStyle fields from a property and return a list of Field objects.
     """
@@ -448,7 +448,7 @@
         if property_['independent']:
             fields.append(_create_inherited_flag_field(property_))
 
-        fields.append(_create_property_field(property_))
+        fields.append(_create_property_field(property_, alias_dictionary))
 
     return fields
 
@@ -545,13 +545,18 @@
     properties_ranking = _get_properties_ranking(properties_ranking_file, partition_rule)
 
     for property_ in all_properties:
-        if property_["field_group"] is not None:
-            if "rare-non-inherited" in property_["field_group"] and property_["name"] in properties_ranking:
-                property_["field_group"] = "->".join(layers_name[0:properties_ranking[property_["name"]]])
-            elif "rare-non-inherited" in property_["field_group"] and property_["name"] not in properties_ranking:
-                group_tree = property_["field_group"].split("->")
-                group_tree = [layers_name[0]] + group_tree
-                property_["field_group"] = "->".join(group_tree)
+        if property_["field_group"] is not None and "*" in property_["field_group"] \
+           and not property_["inherited"] and property_["name"] in properties_ranking:
+
+            assert property_["field_group"] == "*", "The property " + property_["name"] \
+                + " will be automatically assigned a group, please put '*' as the field_group"
+
+            property_["field_group"] = "->".join(layers_name[0:properties_ranking[property_["name"]]])
+        elif property_["field_group"] is not None and "*" in property_["field_group"] \
+                and not property_["inherited"] and property_["name"] not in properties_ranking:
+            group_tree = property_["field_group"].split("->")[1:]
+            group_tree = [layers_name[0], layers_name[0] + "-sub"] + group_tree
+            property_["field_group"] = "->".join(group_tree)
 
 
 def _evaluate_rare_inherit_group(all_properties, properties_ranking_file,
@@ -573,13 +578,18 @@
 
     layers_name = ["rare-inherited-usage-less-than-" + str(int(round(partition_rule[i] * 100))) + "-percent"
                    for i in range(number_of_layer)]
+
     properties_ranking = _get_properties_ranking(properties_ranking_file, partition_rule)
 
     for property_ in all_properties:
-        if property_["field_group"] is not None \
-           and "rare-inherited" in property_["field_group"] \
-           and property_["name"] in properties_ranking:
-            property_["field_group"] = "->".join(["rare-inherited"] + layers_name[1:properties_ranking[property_["name"]]])
+        if property_["field_group"] is not None and "*" in property_["field_group"] \
+           and property_["inherited"] and property_["name"] in properties_ranking:
+            property_["field_group"] = "->".join(layers_name[0:properties_ranking[property_["name"]]])
+        elif property_["field_group"] is not None and "*" in property_["field_group"] \
+                and property_["inherited"] and property_["name"] not in properties_ranking:
+            group_tree = property_["field_group"].split("->")[1:]
+            group_tree = [layers_name[0], layers_name[0] + "-sub"] + group_tree
+            property_["field_group"] = "->".join(group_tree)
 
 
 class ComputedStyleBaseWriter(make_style_builder.StyleBuilderWriter):
@@ -628,14 +638,18 @@
 
         # Organise fields into a tree structure where the root group
         # is ComputedStyleBase.
+        group_parameters = dict([(conf["name"], conf["cumulative_distribution"]) for conf in
+                                 json5_generator.Json5File.load_from_files([json5_file_paths[5]]).name_dictionaries])
 
-        # [0.134, 0.327, 1.0] is the best RareNonInherited partition parameter
-        # that was found by experiments
-        _evaluate_rare_non_inherited_group(all_properties, json5_file_paths[4], 3, [0.134, 0.327, 1.0])
-        # [0.4, 1.0] is the best RareInherited partition parameter that was
-        # found by experiments
-        _evaluate_rare_inherit_group(all_properties, json5_file_paths[4], 2, [0.4, 1.0])
-        self._root_group = _create_groups(all_properties)
+        _evaluate_rare_non_inherited_group(all_properties, json5_file_paths[4],
+                                           len(group_parameters["rare_non_inherited_properties_rule"]),
+                                           group_parameters["rare_non_inherited_properties_rule"])
+        _evaluate_rare_inherit_group(all_properties, json5_file_paths[4],
+                                     len(group_parameters["rare_inherited_properties_rule"]),
+                                     group_parameters["rare_inherited_properties_rule"])
+        alias_dictionary = dict([(alias["name"], alias) for alias in
+                                 json5_generator.Json5File.load_from_files([json5_file_paths[6]]).name_dictionaries])
+        self._root_group = _create_groups(all_properties, alias_dictionary)
         self._diff_functions_map = _create_diff_groups_map(json5_generator.Json5File.load_from_files(
             [json5_file_paths[2]]
         ).name_dictionaries, self._root_group)
diff --git a/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl
index 2a1ccca..bb640712 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ElementTypeHelpers.cpp.tmpl
@@ -8,37 +8,45 @@
 #include "core/dom/Document.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/wtf/HashMap.h"
+#include "platform/wtf/StdLibExtras.h"
 
 namespace blink {
 {% if namespace == "HTML" %}
 using HTMLTypeMap = HashMap<AtomicString, HTMLElementType>;
 
-static HTMLTypeMap* html_type_map = 0;
-
-void createHTMLTypeMap() {
-  DCHECK(!html_type_map);
-  html_type_map = new HTMLTypeMap;
-  {% for tag in tags|sort %}
-  html_type_map->Set(AtomicString("{{tag.name}}"), HTMLElementType::k{{tag.interface}});
-  {% endfor %}
+HTMLTypeMap CreateHTMLTypeMap() {
+  HTMLTypeMap html_type_map;
+  html_type_map.ReserveCapacityForSize({{tags|count}});
+  static constexpr struct {
+    const char* name;
+    HTMLElementType type;
+  } kTags[] = {
+    {% for tag in tags|sort %}
+    { "{{tag.name}}", HTMLElementType::k{{tag.interface}} },
+    {% endfor %}
+  };
+  for (const auto& tag : kTags)
+    html_type_map.insert(tag.name, tag.type);
+  return html_type_map;
 }
 
 HTMLElementType htmlElementTypeForTag(const AtomicString& tagName) {
-  if (!html_type_map) createHTMLTypeMap();
-  if (html_type_map->Contains(tagName)) {
-    {% for tag in tags|sort %}
-    {% if tag.runtimeEnabled %}
-    if (tagName == "{{tag.name}}") {
-      if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled()) {
-        return HTMLElementType::kHTMLUnknownElement;
-      }
-    }
-    {% endif %}
-    {% endfor %}
-    return html_type_map->at(tagName);
-  } else {
+  DEFINE_STATIC_LOCAL(const HTMLTypeMap, html_type_map, (CreateHTMLTypeMap()));
+
+  auto it = html_type_map.find(tagName);
+  if (it == html_type_map.end())
     return HTMLElementType::kHTMLUnknownElement;
+
+  {% for tag in tags|sort %}
+  {% if tag.runtimeEnabled %}
+  if (tagName == "{{tag.name}}") {
+    if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled()) {
+      return HTMLElementType::kHTMLUnknownElement;
+    }
   }
+  {% endif %}
+  {% endfor %}
+  return it->value;
 }
 {% endif %}
 } // namespace blink
diff --git a/third_party/WebKit/Source/build/scripts/update_css_ranking.py b/third_party/WebKit/Source/build/scripts/update_css_ranking.py
new file mode 100644
index 0000000..e2b36890
--- /dev/null
+++ b/third_party/WebKit/Source/build/scripts/update_css_ranking.py
@@ -0,0 +1,129 @@
+# This script is used to update the CSS ranking. The CSS ranking will affect
+# the grouping of CSS properties in Computed Style.
+# Usage: Run `python update_css_ranking.py` to update the default
+#        CSS ranking file and API.
+#        Run `python update_css_ranking.py <ranking_file>` to update
+#        the ranking to another file with the default ranking API.
+#        Run `python update_css_ranking.py <ranking_file> <ranking_api_link>`
+#        to update the ranking from <ranking_api_link> API to <ranking_file>
+
+import urllib2
+import json
+import sys
+import cluster
+import json5_generator
+import math
+
+
+CSS_RANKING_API = "http://www.chromestatus.com/data/csspopularity"
+CSS_RANKING_FILE = "../../core/css/CSSPropertiesRanking.json5"
+CSS_PROPERTIES = "../../core/css/CSSProperties.json5"
+CONFIG_FILE = "../../core/css/CSSGroupConfig.json5"
+
+
+def reformat_properties_name(css_properties):
+    for i in range(len(css_properties)):
+        if css_properties[i][:5] == "alias":
+            css_properties[i] = css_properties[i][5:]
+        if css_properties[i][:6] == "webkit":
+            css_properties[i] = "-" + css_properties[i]
+
+
+def update_css_ranking(css_ranking_file, css_ranking_api):
+    """Create the CSSPropertiesRanking.json5 for uses in Computed Style grouping
+
+    Args:
+        css_ranking_file: file directory to CSSPropertiesRanking.json5
+        css_ranking_api: url to CSS ranking api
+
+    """
+    css_ranking = json.loads(urllib2.urlopen(css_ranking_api).read())
+    css_ranking_content = {"properties": {}, "data": []}
+    css_ranking_content["data"] = [property_["property_name"] for property_ in
+                                   sorted(css_ranking, key=lambda x: -float(x["day_percentage"]))]
+
+    reformat_properties_name(css_ranking_content["data"])
+
+    with open(css_ranking_file, "w") as fw:
+        fw.write("// The popularity ranking of all css properties the first properties is the most\n")
+        fw.write("// used property according to: https://www.chromestatus.com/metrics/css/popularity\n")
+        json.dump(css_ranking_content, fw, indent=4, sort_keys=False)
+
+
+def find_partition_rule(css_property_set, all_properties, n_cluster, transform=lambda x: x):
+    """Find partition rule for a set of CSS property based on its popularity
+
+    Args:
+        css_property_set: list of CSS properties and their popularity of form
+                          [(css_property_name, popularity_score)..]
+        n_cluster: number of cluster to divide the set into
+        all_properties: all CSS properties and its score
+        transform: data transform function to transform the popularity score,
+                   default value is the identity function
+
+    Returns:
+        partition rule for css_property_set
+    """
+    _, cluster_alloc, _ = cluster.k_means([transform(p[1]) for p in css_property_set], n_cluster=n_cluster)
+    return [all_properties[css_property_set[i][0]] for i in range(len(cluster_alloc) - 1)
+            if cluster_alloc[i] != cluster_alloc[i + 1]] + [1.0]
+
+
+def produce_partition_rule(config_file, css_ranking_api):
+    """Find the partition rule for the groups and print them to config_file
+
+    Args:
+        config_file: the file to write the parameters to
+        css_ranking_api: url to CSS ranking api
+
+    """
+    css_ranking = sorted(json.loads(urllib2.urlopen(css_ranking_api).read()),
+                         key=lambda x: -x["day_percentage"])
+    total_css_properties = len(css_ranking)
+    css_ranking_dictionary = dict([(x["property_name"], x["day_percentage"] * 100) for x in css_ranking])
+    css_ranking_cdf = dict(zip([x["property_name"] for x in css_ranking],
+                               [float(i) / total_css_properties for i in range(total_css_properties)]))
+    css_properties = json5_generator.Json5File.load_from_files([CSS_PROPERTIES]).name_dictionaries
+
+    rare_non_inherited_properties = sorted([(x["name"], css_ranking_dictionary[x["name"]])
+                                            for x in css_properties if not x["inherited"]
+                                            and x["field_group"] is not None
+                                            and "*" in x["field_group"]
+                                            and x["name"] in css_ranking_dictionary],
+                                           key=lambda x: -x[1])
+    rare_inherited_properties = sorted([(x["name"], css_ranking_dictionary[x["name"]])
+                                        for x in css_properties if x["inherited"]
+                                        and x["field_group"] is not None
+                                        and "*" in x["field_group"]
+                                        and x["name"] in css_ranking_dictionary],
+                                       key=lambda x: -x[1])
+
+    rni_properties_rule = find_partition_rule(rare_non_inherited_properties,
+                                              css_ranking_cdf, n_cluster=3)
+
+    ri_properties_rule = find_partition_rule(rare_inherited_properties,
+                                             css_ranking_cdf,
+                                             n_cluster=2, transform=lambda x: math.log(x + 10e-6))
+
+    with open(config_file, 'w') as fw:
+        fw.write("// The grouping parameter is a cumulative distribution over the whole set of ranked\n")
+        fw.write("// CSS properties.\n")
+        json.dump({
+            "parameters": {},
+            "data": [{"name": "rare_non_inherited_properties_rule", "cumulative_distribution": rni_properties_rule},
+                     {"name": "rare_inherited_properties_rule", "cumulative_distribution": ri_properties_rule}]
+        }, fw, indent=4)
+
+
+if __name__ == '__main__':
+    assert len(sys.argv) < 4, "Too many parameters"
+
+    if len(sys.argv) == 1:
+        update_css_ranking(CSS_RANKING_FILE, CSS_RANKING_API)
+        produce_partition_rule(CONFIG_FILE, CSS_RANKING_API)
+    elif len(sys.argv) == 2:
+        update_css_ranking(sys.argv[1], CSS_RANKING_API)
+        produce_partition_rule(CONFIG_FILE, CSS_RANKING_API)
+    elif len(sys.argv) == 3:
+        update_css_ranking(sys.argv[1], sys.argv[2])
+        produce_partition_rule(CONFIG_FILE, sys.argv[2])
diff --git a/third_party/WebKit/Source/config.gni b/third_party/WebKit/Source/config.gni
index b5232b2..81b1e49b 100644
--- a/third_party/WebKit/Source/config.gni
+++ b/third_party/WebKit/Source/config.gni
@@ -18,10 +18,6 @@
   # size of the binary and increasing the speed of gdb.
   remove_webcore_debug_symbols = false
 
-  # If true, enables WTF::ScopedLogger unconditionally.
-  # When false, WTF::ScopedLogger is enabled only if assertions are enabled.
-  blink_logging_always_on = false
-
   # If true, defaults image interpolation to low quality.
   use_low_quality_image_interpolation = is_android
 }
@@ -62,9 +58,6 @@
   # preference to that.
   feature_defines_list += [ "WTF_USE_DEFAULT_RENDER_THEME=1" ]
 }
-if (blink_logging_always_on) {
-  feature_defines_list += [ "LOG_DISABLED=0" ]
-}
 
 if (remove_webcore_debug_symbols) {
   if (is_win && symbol_level != 0) {
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 729c1e4..c93f57c 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -425,6 +425,8 @@
     "css/ComputedStyleDiffFunctions.json5",
     "css/CSSValueKeywords.json5",
     "css/CSSPropertiesRanking.json5",
+    "css/CSSGroupConfig.json5",
+    "css/ComputedStyleFieldAliases.json5",
   ]
   other_inputs = [
     "../build/scripts/templates/fields/field.tmpl",
@@ -633,6 +635,7 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitOriginY.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitPadding.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitTextDecorationsInEffect.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitTextEmphasisPosition.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitTextStrokeColor.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitTextStrokeWidth.h",
diff --git a/third_party/WebKit/Source/core/animation/AnimationEffectTiming.cpp b/third_party/WebKit/Source/core/animation/AnimationEffectTiming.cpp
index 63a7d34a..02fd66fd 100644
--- a/third_party/WebKit/Source/core/animation/AnimationEffectTiming.cpp
+++ b/third_party/WebKit/Source/core/animation/AnimationEffectTiming.cpp
@@ -5,7 +5,7 @@
 #include "core/animation/AnimationEffectTiming.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrString.h"
+#include "bindings/core/v8/unrestricted_double_or_string.h"
 #include "core/animation/AnimationEffectReadOnly.h"
 #include "core/animation/AnimationEffectTimingReadOnly.h"
 #include "core/animation/KeyframeEffect.h"
diff --git a/third_party/WebKit/Source/core/animation/AnimationEffectTimingReadOnly.cpp b/third_party/WebKit/Source/core/animation/AnimationEffectTimingReadOnly.cpp
index 453caf7..b6f2a5a 100644
--- a/third_party/WebKit/Source/core/animation/AnimationEffectTimingReadOnly.cpp
+++ b/third_party/WebKit/Source/core/animation/AnimationEffectTimingReadOnly.cpp
@@ -4,7 +4,7 @@
 
 #include "core/animation/AnimationEffectTimingReadOnly.h"
 
-#include "bindings/core/v8/UnrestrictedDoubleOrString.h"
+#include "bindings/core/v8/unrestricted_double_or_string.h"
 #include "core/animation/AnimationEffectReadOnly.h"
 #include "core/animation/KeyframeEffect.h"
 #include "platform/animation/TimingFunction.h"
diff --git a/third_party/WebKit/Source/core/animation/EffectInput.cpp b/third_party/WebKit/Source/core/animation/EffectInput.cpp
index 67067a33..5936041 100644
--- a/third_party/WebKit/Source/core/animation/EffectInput.cpp
+++ b/third_party/WebKit/Source/core/animation/EffectInput.cpp
@@ -32,7 +32,7 @@
 
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/DictionaryHelperForBindings.h"
-#include "bindings/core/v8/DictionarySequenceOrDictionary.h"
+#include "bindings/core/v8/dictionary_sequence_or_dictionary.h"
 #include "core/animation/AnimationInputHelpers.h"
 #include "core/animation/CompositorAnimations.h"
 #include "core/animation/KeyframeEffectModel.h"
diff --git a/third_party/WebKit/Source/core/animation/EffectInputTest.cpp b/third_party/WebKit/Source/core/animation/EffectInputTest.cpp
index be56b485..8eeda73 100644
--- a/third_party/WebKit/Source/core/animation/EffectInputTest.cpp
+++ b/third_party/WebKit/Source/core/animation/EffectInputTest.cpp
@@ -7,8 +7,8 @@
 #include <memory>
 
 #include "bindings/core/v8/Dictionary.h"
-#include "bindings/core/v8/DictionarySequenceOrDictionary.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/dictionary_sequence_or_dictionary.h"
 #include "core/animation/AnimationTestHelper.h"
 #include "core/animation/KeyframeEffectModel.h"
 #include "core/dom/Document.h"
diff --git a/third_party/WebKit/Source/core/animation/ElementAnimation.h b/third_party/WebKit/Source/core/animation/ElementAnimation.h
index ffedada..32e2935d 100644
--- a/third_party/WebKit/Source/core/animation/ElementAnimation.h
+++ b/third_party/WebKit/Source/core/animation/ElementAnimation.h
@@ -32,8 +32,8 @@
 #define ElementAnimation_h
 
 #include "base/gtest_prod_util.h"
-#include "bindings/core/v8/DictionarySequenceOrDictionary.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeAnimationOptions.h"
+#include "bindings/core/v8/dictionary_sequence_or_dictionary.h"
+#include "bindings/core/v8/unrestricted_double_or_keyframe_animation_options.h"
 #include "core/animation/DocumentTimeline.h"
 #include "core/animation/EffectInput.h"
 #include "core/animation/ElementAnimations.h"
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
index ec087542..94ee5c5a 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffect.cpp
@@ -32,7 +32,7 @@
 
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeEffectOptions.h"
+#include "bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
 #include "core/animation/AnimationEffectTiming.h"
 #include "core/animation/EffectInput.h"
 #include "core/animation/KeyframeEffectOptions.h"
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp
index 3d04010..79ac444 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffectReadOnly.cpp
@@ -6,7 +6,7 @@
 
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeEffectOptions.h"
+#include "bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
 #include "core/animation/Animation.h"
 #include "core/animation/EffectInput.h"
 #include "core/animation/ElementAnimations.h"
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp
index ef883d9..2cbf4be 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp
@@ -7,10 +7,10 @@
 #include <memory>
 
 #include "bindings/core/v8/Dictionary.h"
-#include "bindings/core/v8/DictionarySequenceOrDictionary.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeEffectOptions.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
 #include "bindings/core/v8/V8KeyframeEffectOptions.h"
+#include "bindings/core/v8/dictionary_sequence_or_dictionary.h"
+#include "bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
 #include "core/animation/Animation.h"
 #include "core/animation/AnimationClock.h"
 #include "core/animation/AnimationEffectTiming.h"
diff --git a/third_party/WebKit/Source/core/animation/TimingInput.cpp b/third_party/WebKit/Source/core/animation/TimingInput.cpp
index e6e6414..f2b3930 100644
--- a/third_party/WebKit/Source/core/animation/TimingInput.cpp
+++ b/third_party/WebKit/Source/core/animation/TimingInput.cpp
@@ -5,8 +5,8 @@
 #include "core/animation/TimingInput.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeAnimationOptions.h"
-#include "bindings/core/v8/UnrestrictedDoubleOrKeyframeEffectOptions.h"
+#include "bindings/core/v8/unrestricted_double_or_keyframe_animation_options.h"
+#include "bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
 #include "core/animation/AnimationInputHelpers.h"
 #include "core/animation/KeyframeEffectOptions.h"
 
diff --git a/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp b/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp
index 566e674..5a21d523 100644
--- a/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp
+++ b/third_party/WebKit/Source/core/clipboard/DataTransferItem.cpp
@@ -30,8 +30,8 @@
 
 #include "core/clipboard/DataTransferItem.h"
 
-#include "bindings/core/v8/FunctionStringCallback.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/function_string_callback.h"
 #include "core/clipboard/DataObjectItem.h"
 #include "core/clipboard/DataTransfer.h"
 #include "core/dom/ExecutionContext.h"
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index 4ec64b5c..b2c7058 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -117,8 +117,6 @@
                     "dom/ShadowRoot.idl",
                     "dom/StaticRange.idl",
                     "dom/Text.idl",
-                    "dom/Touch.idl",
-                    "dom/TouchList.idl",
                     "dom/TreeWalker.idl",
                     "dom/XMLDocument.idl",
                     "dom/events/CustomEvent.idl",
@@ -268,6 +266,8 @@
                     "html/track/vtt/VTTRegion.idl",
                     "imagebitmap/ImageBitmap.idl",
                     "input/InputDeviceCapabilities.idl",
+                    "input/Touch.idl",
+                    "input/TouchList.idl",
                     "inspector/InspectorOverlayHost.idl",
                     "intersection_observer/IntersectionObserver.idl",
                     "intersection_observer/IntersectionObserverEntry.idl",
@@ -533,7 +533,6 @@
                     "dom/IdleRequestOptions.idl",
                     "dom/MutationObserverInit.idl",
                     "dom/ShadowRootInit.idl",
-                    "dom/TouchInit.idl",
                     "dom/events/AddEventListenerOptions.idl",
                     "dom/events/CustomEventInit.idl",
                     "dom/events/EventInit.idl",
@@ -577,6 +576,7 @@
                     "html/track/TrackEventInit.idl",
                     "imagebitmap/ImageBitmapOptions.idl",
                     "input/InputDeviceCapabilitiesInit.idl",
+                    "input/TouchInit.idl",
                     "intersection_observer/IntersectionObserverInit.idl",
                     "mojo/MojoCreateDataPipeOptions.idl",
                     "mojo/MojoCreateDataPipeResult.idl",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 7a91ae05..9b0f903 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -514,7 +514,6 @@
     "properties/CSSPropertyAPITextDecorationColor.cpp",
     "properties/CSSPropertyAPITextDecorationLine.cpp",
     "properties/CSSPropertyAPITextDecorationSkip.cpp",
-    "properties/CSSPropertyAPITextEmphasisPosition.cpp",
     "properties/CSSPropertyAPITextIndent.cpp",
     "properties/CSSPropertyAPITextShadow.cpp",
     "properties/CSSPropertyAPITextSizeAdjust.cpp",
@@ -547,6 +546,7 @@
     "properties/CSSPropertyAPIWebkitOriginY.cpp",
     "properties/CSSPropertyAPIWebkitPadding.cpp",
     "properties/CSSPropertyAPIWebkitTextDecorationsInEffect.cpp",
+    "properties/CSSPropertyAPIWebkitTextEmphasisPosition.cpp",
     "properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp",
     "properties/CSSPropertyAPIWebkitTextStrokeColor.cpp",
     "properties/CSSPropertyAPIWebkitTextStrokeWidth.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSGroupConfig.json5 b/third_party/WebKit/Source/core/css/CSSGroupConfig.json5
new file mode 100644
index 0000000..d1e33c0
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/CSSGroupConfig.json5
@@ -0,0 +1,22 @@
+// The grouping parameter is a cumulative distribution over the whole set of ranked
+// CSS properties.
+{
+    "data": [
+        {
+            "name": "rare_non_inherited_properties_rule",
+            "cumulative_distribution": [
+                0.134,
+                0.327,
+                1.0
+            ]
+        },
+        {
+            "name": "rare_inherited_properties_rule",
+            "cumulative_distribution": [
+                0.4,
+                1.0
+            ]
+        }
+    ],
+    "parameters": {}
+}
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 4c11e72..ec73cc07 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -58,6 +58,10 @@
     // Name of the group that this field belongs to. Fields in the same group are stored
     // together as a nested class inside ComputedStyle and dynamically allocated on use.
     // Leave this out if the field is stored directly on ComputedStyle.
+    // If you want to auto group this property use: field_group: "*[->subgroup]".
+    // If you use the auto grouping function check if your property is in CSSPropertiesRanking.json5
+    // -  If yes, only provide: field_group: "*"
+    // -  If no, you can specify a subgroup following the asterisk: field_group: "*[->subgroup]"
     field_group: {
       value_type: "str"
     },
@@ -96,10 +100,9 @@
         // Field is stored as a wrapper_pointer_name to a class.
         "pointer",
         // Preset "length" for external and Length class
-        // This preset represents:  field_template: "external"
-        //                          type_name: "Length"
-        //                          include_paths: ["platform/Length.h"]
-        "<length>"
+        // This preset represents alias templates that will be replace by entries
+        // in CSSFieldAlias.json5.
+        "<[a-z]+>",
       ],
     },
 
@@ -587,7 +590,7 @@
       field_template: "keyword",
       keywords: ["sideways", "mixed", "upright"],
       default_value: "mixed",
-      field_group: "rare-inherited",
+      field_group: "*",
       getter: "GetTextOrientation"
     },
     {
@@ -647,7 +650,7 @@
       converter: "ConvertContentAlignmentData",
       field_template: "external",
       type_name: "StyleContentAlignmentData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleContentAlignmentData(kContentPositionNormal, kContentDistributionDefault, kOverflowAlignmentDefault)",
       include_paths: ["core/style/StyleContentAlignmentData.h"],
     },
@@ -658,7 +661,7 @@
       converter: "ConvertSelfOrDefaultAlignmentData",
       field_template: "external",
       type_name: "StyleSelfAlignmentData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleSelfAlignmentData(RuntimeEnabledFeatures::CSSGridLayoutEnabled() ? kItemPositionNormal : kItemPositionStretch, kOverflowAlignmentDefault)",
       include_paths: ["core/style/StyleSelfAlignmentData.h"],
     },
@@ -673,7 +676,7 @@
       converter: "ConvertSelfOrDefaultAlignmentData",
       field_template: "external",
       type_name: "StyleSelfAlignmentData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleSelfAlignmentData(kItemPositionAuto, kOverflowAlignmentDefault)",
       include_paths: ["core/style/StyleSelfAlignmentData.h"],
     },
@@ -686,7 +689,7 @@
       runtime_flag: "CSSBackdropFilter",
       field_template: "storage_only",
       type_name: "StyleFilterData",
-      field_group: "rare-non-inherited->backdrop-filter-ops",
+      field_group: "*",
       default_value: "StyleFilterData::Create()",
       wrapper_pointer_name: "Persistent",
       include_paths: ["core/style/StyleFilterData.h"],
@@ -694,7 +697,7 @@
     {
       name: "backface-visibility",
       field_template: "keyword",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "visible",
       keywords: ["visible", "hidden"],
     },
@@ -1035,7 +1038,7 @@
       interpolable: true,
       field_template: "pointer",
       type_name: "ShadowList",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
       include_paths: ["core/style/ShadowList.h"],
@@ -1101,7 +1104,7 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "clear",
@@ -1131,7 +1134,7 @@
       interpolable: true,
       field_template: "pointer",
       type_name: "ClipPathOperation",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
       include_paths: ["core/style/ClipPathOperation.h"],
@@ -1167,7 +1170,7 @@
       field_template: "keyword",
       keywords: ["balance", "auto"],
       default_value: "balance",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
       getter: "GetColumnFill",
     },
     {
@@ -1178,7 +1181,7 @@
       name_for_methods: "Contain",
       type_name: "Containment",
       field_template: "storage_only",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       field_size: 4,
       default_value: "kContainsNone",
       default_generated_functions: ["getter","setter"],
@@ -1192,7 +1195,7 @@
       typedom_types: ["Image"],
       type_name: "ContentData",
       field_template: "storage_only",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "Persistent",
       include_paths: ["core/style/ContentData.h"],
@@ -1308,7 +1311,7 @@
       interpolable: true,
       field_template: "storage_only",
       type_name : "StyleFilterData",
-      field_group: "rare-non-inherited->filter-ops",
+      field_group: "*",
       default_value: "StyleFilterData::Create()",
       wrapper_pointer_name: "Persistent",
       include_paths: ["core/style/StyleFilterData.h"],
@@ -1321,13 +1324,13 @@
       interpolable: true,
       field_template: "<length>",
       default_value: "Length(kAuto)",
-      field_group: "rare-non-inherited->flexible-box",
+      field_group: "*",
     },
     {
       name: "flex-direction",
       field_template: "keyword",
       default_value: "row",
-      field_group: "rare-non-inherited->flexible-box",
+      field_group: "*",
       keywords: ["row", "row-reverse", "column", "column-reverse"],
     },
     {
@@ -1338,7 +1341,7 @@
       type_name: "float",
       field_template: "primitive",
       default_value: "0.0f",
-      field_group: "rare-non-inherited->flexible-box",
+      field_group: "*",
     },
     {
       name: "flex-shrink",
@@ -1348,13 +1351,13 @@
       type_name: "float",
       field_template: "primitive",
       default_value: "1.0f",
-      field_group: "rare-non-inherited->flexible-box",
+      field_group: "*",
     },
     {
       name: "flex-wrap",
       field_template: "keyword",
       default_value: "nowrap",
-      field_group: "rare-non-inherited->flexible-box",
+      field_group: "*",
       keywords: ["nowrap", "wrap", "wrap-reverse"],
     },
     {
@@ -1390,7 +1393,7 @@
       type_name: "Vector<GridTrackSize>",
       field_template: "external",
       default_value: "Vector<GridTrackSize>(1, GridTrackSize(Length(kAuto)))",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*",
       include_paths: ["platform/wtf/Vector.h", "core/style/GridTrackSize.h"],
     },
     {
@@ -1403,7 +1406,7 @@
       field_template: "storage_only",
       default_value: "kAutoFlowRow",
       field_size: 4, // TODO(shend): Make this use "kGridAutoFlowBits".
-      field_group: "rare-non-inherited->grid",
+      field_group: "*",
       default_generated_functions: ["setter"],
     },
     {
@@ -1415,7 +1418,7 @@
       type_name: "Vector<GridTrackSize>",
       field_template: "external",
       default_value: "Vector<GridTrackSize>(1, GridTrackSize(Length(kAuto)))",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*",
       include_paths: ["platform/wtf/Vector.h", "core/style/GridTrackSize.h"],
     },
     {
@@ -1427,7 +1430,7 @@
       type_name: "GridPosition",
       field_template: "external",
       default_value: "GridPosition()",
-      field_group: "rare-non-inherited->grid-item",
+      field_group: "*",
       include_paths: ["core/style/GridPosition.h"],
     },
     {
@@ -1438,7 +1441,7 @@
       runtime_flag: "CSSGridLayout",
       field_template: "<length>",
       default_value: "Length(kFixed)",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*",
     },
     {
       name: "grid-column-start",
@@ -1449,7 +1452,7 @@
       type_name: "GridPosition",
       field_template: "external",
       default_value: "GridPosition()",
-      field_group: "rare-non-inherited->grid-item",
+      field_group: "*",
       include_paths: ["core/style/GridPosition.h"],
     },
     {
@@ -1461,7 +1464,7 @@
       type_name: "GridPosition",
       field_template: "external",
       default_value: "GridPosition()",
-      field_group: "rare-non-inherited->grid-item",
+      field_group: "*",
       include_paths: ["core/style/GridPosition.h"],
     },
     {
@@ -1472,7 +1475,7 @@
       runtime_flag: "CSSGridLayout",
       field_template: "<length>",
       default_value: "Length(kFixed)",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*",
     },
     {
       name: "grid-row-start",
@@ -1483,7 +1486,7 @@
       type_name: "GridPosition",
       field_template: "external",
       default_value: "GridPosition()",
-      field_group: "rare-non-inherited->grid-item",
+      field_group: "*",
       include_paths: ["core/style/GridPosition.h"],
     },
     {
@@ -1501,7 +1504,7 @@
       runtime_flag: "CSSGridLayout",
       field_template: "external",
       type_name: "Vector<GridTrackSize>",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*",
       default_value: "Vector<GridTrackSize>()",
       include_paths: ["platform/wtf/Vector.h", "core/style/GridTrackSize.h"],
     },
@@ -1513,7 +1516,7 @@
       runtime_flag: "CSSGridLayout",
       field_template: "external",
       type_name: "Vector<GridTrackSize>",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*",
       default_value: "Vector<GridTrackSize>()",
       include_paths: ["platform/wtf/Vector.h", "core/style/GridTrackSize.h"],
     },
@@ -1539,7 +1542,7 @@
       type_name: "Hyphens",
       keywords: ["none", "manual", "auto"],
       default_value: "manual",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "image-rendering",
@@ -1548,7 +1551,7 @@
       field_template: "keyword",
       keywords: ["auto", "optimizeSpeed", "optimizeQuality", "-webkit-optimize-contrast", "pixelated"],
       default_value: "auto",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "image-orientation",
@@ -1561,13 +1564,13 @@
       field_template: "primitive",
       type_name: "bool",
       default_value: "false",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "isolation",
       field_template: "keyword",
       keywords: ["auto", "isolate"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "auto",
     },
     {
@@ -1577,7 +1580,7 @@
       converter: "ConvertContentAlignmentData",
       field_template: "external",
       type_name: "StyleContentAlignmentData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleContentAlignmentData(kContentPositionNormal, kContentDistributionDefault, kOverflowAlignmentDefault)",
       include_paths: ["core/style/StyleContentAlignmentData.h"],
     },
@@ -1589,7 +1592,7 @@
       runtime_flag: "CSSGridLayout",
       field_template: "external",
       type_name: "StyleSelfAlignmentData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleSelfAlignmentData(kItemPositionAuto, kOverflowAlignmentDefault)",
       include_paths: ["core/style/StyleSelfAlignmentData.h"],
     },
@@ -1601,7 +1604,7 @@
       runtime_flag: "CSSGridLayout",
       field_template: "external",
       type_name: "StyleSelfAlignmentData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleSelfAlignmentData(kItemPositionAuto, kOverflowAlignmentDefault)",
       include_paths: ["core/style/StyleSelfAlignmentData.h"],
     },
@@ -1658,7 +1661,7 @@
       field_template: "primitive",
       type_name: "uint8_t",
       default_value: "0",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "list-style-image",
@@ -1672,7 +1675,7 @@
       type_name: "StyleImage",
       wrapper_pointer_name: "Persistent",
       default_value: "nullptr",
-      field_group: "rare-inherited",
+      field_group: "*",
       include_paths: ["core/style/StyleImage.h"],
     },
     {
@@ -1832,7 +1835,7 @@
       keywords: ["normal", "multiply", "screen", "overlay", "darken", "lighten",
        "color-dodge", "color-burn", "hard-light", "soft-light", "difference",
        "exclusion", "hue", "saturation", "color", "luminosity"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "normal",
       include_paths: ["public/platform/WebBlendMode.h"],
     },
@@ -1840,7 +1843,7 @@
       name: "object-fit",
       field_template: "keyword",
       keywords: ["fill", "contain", "cover", "none", "scale-down"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       getter: "GetObjectFit",
       default_value: "fill",
     },
@@ -1853,7 +1856,7 @@
       field_template: "external",
       type_name: "LengthPoint",
       include_paths: ["platform/LengthPoint.h"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "LengthPoint(Length(50.0, kPercent), Length(50.0, kPercent))",
     },
     {
@@ -1866,7 +1869,7 @@
       field_template: "external",
       type_name: "LengthPoint",
       include_paths: ["platform/LengthPoint.h"],
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "LengthPoint(Length(kAuto), Length(kAuto))",
     },
     {
@@ -1876,7 +1879,7 @@
       converter: "ConvertLength",
       interpolable: true,
       field_template: "<length>",
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "Length(0, kFixed)",
     },
     {
@@ -1886,7 +1889,7 @@
       converter: "ConvertOffsetPath",
       field_template: "pointer",
       type_name: "BasicShape",
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       wrapper_pointer_name: "RefPtr",
       default_value: "nullptr",
       include_paths: ["core/style/BasicShapes.h"],
@@ -1901,19 +1904,19 @@
       field_template: "external",
       type_name: "LengthPoint",
       include_paths: ["platform/LengthPoint.h"],
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "LengthPoint(Length(kAuto), Length(kAuto))",
     },
     {
       name: "offset-rotate",
-      api_class: "CSSPropertyAPIOffsetRotate",
+      api_class: true,
       api_methods: ["ParseSingleValue"],
       converter: "ConvertOffsetRotate",
       interpolable: true,
       field_template: "external",
       type_name: "StyleOffsetRotation",
       include_paths: ["core/style/StyleOffsetRotation.h"],
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "StyleOffsetRotation(0, kOffsetRotationAuto)",
     },
     // Whether or not we're transparent.
@@ -1924,7 +1927,7 @@
       interpolable: true,
       field_template: "storage_only",
       type_name: "float",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "1.0",
       default_generated_functions: ["getter"],
     },
@@ -1935,7 +1938,7 @@
       interpolable: true,
       field_template: "storage_only",
       type_name: "int",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "0",
       default_generated_functions: ["getter"],
     },
@@ -1948,7 +1951,7 @@
       type_name: "short",
       field_template: "primitive",
       default_value: "2",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "outline-color",
@@ -1958,7 +1961,7 @@
       interpolable: true,
       field_template: "storage_only",
       type_name: "Color",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "0",
       include_paths: ["platform/graphics/Color.h"],
     },
@@ -1970,7 +1973,7 @@
       interpolable: true,
       field_template: "storage_only",
       type_name: "int",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "0",
       default_generated_functions: ["setter"],
     },
@@ -1980,7 +1983,7 @@
       field_template: "keyword",
       type_name: "EBorderStyle",
       keywords: ["none", "hidden", "inset", "groove", "outset", "ridge", "dotted", "dashed", "solid", "double"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "none",
     },
     {
@@ -1993,7 +1996,7 @@
       include_paths: ["platform/LayoutUnit.h"],
       type_name: "LayoutUnit",
       default_value: "LayoutUnit(3)",
-      field_group: "rare-non-inherited",
+      field_group: "*",
     },
     {
       name: "overflow-anchor",
@@ -2012,7 +2015,7 @@
       field_template: "keyword",
       keywords: ["normal", "break-word"],
       default_value: "normal",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "overflow-x",
@@ -2088,7 +2091,7 @@
       interpolable: true,
       field_template: "primitive",
       type_name: "float",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "0.0",
     },
     {
@@ -2100,7 +2103,7 @@
       field_template: "external",
       type_name: "LengthPoint",
       include_paths: ["platform/LengthPoint.h"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "LengthPoint(Length(50.0, kPercent), Length(50.0, kPercent))",
     },
     {
@@ -2135,14 +2138,14 @@
       include_paths: ["core/style/QuotesData.h"],
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "resize",
       custom_value: true,
       field_template: "keyword",
       keywords: ["none", "both", "horizontal", "vertical"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "none",
     },
     {
@@ -2186,7 +2189,7 @@
       runtime_flag: "CSSOMSmoothScroll",
       type_name: "ScrollBehavior",
       field_template: "storage_only",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       field_size: 2, // FIXME: Convert this to a keyword field
       default_value: "kScrollBehaviorAuto",
       default_generated_functions: ["getter", "setter"],
@@ -2216,7 +2219,7 @@
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "external",
       type_name: "ScrollSnapType",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       include_paths: ["core/style/ScrollSnap.h"],
       default_value: "ScrollSnapType()",
     },
@@ -2229,7 +2232,7 @@
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "external",
       type_name: "ScrollSnapAlign",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "ScrollSnapAlign()",
       include_paths: ["core/style/ScrollSnap.h"],
     },
@@ -2248,7 +2251,7 @@
       typedom_types: ["Length", "Percent"],
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2259,7 +2262,7 @@
       typedom_types: ["Length", "Percent"],
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2270,7 +2273,7 @@
       typedom_types: ["Length", "Percent"],
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2281,7 +2284,7 @@
       typedom_types: ["Length", "Percent"],
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2339,7 +2342,7 @@
       converter: "ConvertLength",
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2349,7 +2352,7 @@
       converter: "ConvertLength",
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2359,7 +2362,7 @@
       converter: "ConvertLength",
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2369,7 +2372,7 @@
       converter: "ConvertLength",
       runtime_flag: "CSSScrollSnapPoints",
       field_template: "<length>",
-      field_group: "rare-non-inherited->scroll-snap",
+      field_group: "*",
       default_value: "Length()",
     },
     {
@@ -2423,7 +2426,7 @@
       interpolable: true,
       field_template: "storage_only",
       type_name: "float",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "0.0",
       default_generated_functions: ["getter"],
     },
@@ -2434,7 +2437,7 @@
       converter: "ConvertLength",
       interpolable: true,
       field_template: "<length>",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "Length(0, kFixed)",
     },
     {
@@ -2446,7 +2449,7 @@
       typedom_types: ["Image"],
       field_template: "storage_only",
       type_name: "ShapeValue",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "Persistent",
       include_paths: ["core/style/ShapeValue.h"],
@@ -2471,7 +2474,7 @@
       field_template: "keyword",
       keywords: ["none", "normal", "spell-out", "digits", "literal-punctuation", "no-punctuation"],
       default_value: "normal",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "stop-color",
@@ -2582,7 +2585,7 @@
       include_paths: ["platform/text/TabSize.h"],
       field_template: "external",
       default_value: "TabSize(8)",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "text-align",
@@ -2604,7 +2607,7 @@
       field_template: "keyword",
       keywords: ["auto", "start", "end", "left", "right", "center", "justify"],
       default_value: "auto",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "text-anchor",
@@ -2620,7 +2623,7 @@
       field_template: "keyword",
       keywords: ["none", "all"],
       default_value: "none",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "text-decoration-color",
@@ -2632,7 +2635,7 @@
       field_template: "external",
       type_name: "StyleColor",
       include_paths: ["core/css/StyleColor.h"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor::CurrentColor()",
     },
     {
@@ -2659,7 +2662,7 @@
       type_name: "TextDecorationSkip",
       default_value: "TextDecorationSkip::kObjects",
       field_size: 3,
-      field_group: "rare-inherited",
+      field_group: "*",
       default_generated_functions: ["getter", "setter"],
     },
     {
@@ -2667,7 +2670,7 @@
       runtime_flag: "CSS3TextDecorations",
       field_template: "keyword",
       keywords: ["solid", "double", "dotted", "dashed", "wavy"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "solid",
     },
     {
@@ -2679,7 +2682,7 @@
       interpolable: true,
       field_template: "<length>",
       default_value: "Length(kFixed)",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "text-justify",
@@ -2692,12 +2695,12 @@
       include_paths: ["platform/text/TextJustify.h"],
       default_value: "auto",
       keywords: ["auto", "none", "inter-word", "distribute"],
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "text-overflow",
       field_template: "keyword",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "clip",
       keywords: ["clip", "ellipsis"],
     },
@@ -2713,7 +2716,7 @@
       include_paths: ["core/style/ShadowList.h"],
       wrapper_pointer_name: "RefPtr",
       default_value: "nullptr",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "text-size-adjust",
@@ -2726,7 +2729,7 @@
       type_name: "TextSizeAdjust",
       include_paths: ["core/style/TextSizeAdjust.h"],
       default_value: "TextSizeAdjust::AdjustAuto()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "text-transform",
@@ -2748,7 +2751,7 @@
       type_name: "TextUnderlinePosition",
       default_value: "auto",
       keywords: ["auto", "under"],
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "top",
@@ -2769,7 +2772,7 @@
       converter: "ConvertFlags<TouchAction>",
       type_name: "TouchAction",
       field_template: "storage_only",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       field_size: 6, // TODO(shend): Make this use "kTouchActionBits".
       default_value: "TouchAction::kTouchActionAuto",
       include_paths: ["platform/graphics/TouchAction.h"],
@@ -2785,7 +2788,7 @@
       typedom_types: ["Transform"],
       field_template: "storage_only",
       type_name: "TransformOperations",
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "EmptyTransformOperations()",
       include_paths: ["platform/transforms/TransformOperations.h"],
       default_generated_functions: ["getter", "setter"],
@@ -2806,7 +2809,7 @@
       interpolable: true,
       field_template: "external",
       type_name: "TransformOrigin",
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "TransformOrigin(Length(50.0, kPercent), Length(50.0, kPercent), 0)",
       include_paths: ["core/style/TransformOrigin.h"],
     },
@@ -2815,7 +2818,7 @@
       name_for_methods: "TransformStyle3D",
       field_template: "keyword",
       keywords: ["flat", "preserve-3d"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "flat",
     },
     {
@@ -2827,7 +2830,7 @@
       runtime_flag: "CSSIndependentTransformProperties",
       field_template: "pointer",
       type_name: "TranslateTransformOperation",
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
       include_paths: ["platform/transforms/TranslateTransformOperation.h"],
@@ -2841,7 +2844,7 @@
       runtime_flag: "CSSIndependentTransformProperties",
       field_template: "pointer",
       type_name: "RotateTransformOperation",
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
       include_paths: ["platform/transforms/RotateTransformOperation.h"],
@@ -2855,7 +2858,7 @@
       runtime_flag: "CSSIndependentTransformProperties",
       field_template: "pointer",
       type_name: "ScaleTransformOperation",
-      field_group: "rare-non-inherited->transform",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
       include_paths: ["platform/transforms/ScaleTransformOperation.h"],
@@ -2912,7 +2915,7 @@
       name: "-webkit-appearance",
       type_name: "ControlPart",
       field_template: "storage_only",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "kNoControlPart",
       field_size: 6,
       default_generated_functions: ["getter", "setter"],
@@ -2922,7 +2925,7 @@
       custom_all: true,
       name_for_methods: "DraggableRegionMode",
       field_template: "keyword",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "none",
       keywords: ["none", "drag", "no-drag"],
     },
@@ -2978,7 +2981,7 @@
       field_template: "keyword",
       keywords: ["stretch", "start", "center", "end", "baseline"],
       default_value: "stretch",
-      field_group: "rare-non-inherited->deprecated-flexible-box",
+      field_group: "*",
     },
     {
       name: "-webkit-box-decoration-break",
@@ -3003,7 +3006,7 @@
       type_name: "float",
       field_template: "primitive",
       default_value: "0.0f",
-      field_group: "rare-non-inherited->deprecated-flexible-box",
+      field_group: "*",
     },
     {
       name: "-webkit-box-flex-group",
@@ -3012,14 +3015,14 @@
       type_name: "unsigned",
       field_template: "primitive",
       default_value: "1",
-      field_group: "rare-non-inherited->deprecated-flexible-box",
+      field_group: "*",
     },
     {
       name: "-webkit-box-lines",
       field_template: "keyword",
       keywords: ["single", "multiple"],
       default_value: "single",
-      field_group: "rare-non-inherited->deprecated-flexible-box",
+      field_group: "*",
     },
     {
       name: "-webkit-box-ordinal-group",
@@ -3028,7 +3031,7 @@
       type_name: "unsigned",
       field_template: "storage_only",
       default_value: "1",
-      field_group: "rare-non-inherited->deprecated-flexible-box",
+      field_group: "*",
       default_generated_functions: ["getter"],
     },
     {
@@ -3036,14 +3039,14 @@
       field_template: "keyword",
       keywords: ["horizontal", "vertical"],
       default_value: "horizontal",
-      field_group: "rare-non-inherited->deprecated-flexible-box",
+      field_group: "*",
     },
     {
       name: "-webkit-box-pack",
       field_template: "keyword",
       keywords: ["start", "center", "end", "justify"],
       default_value: "start",
-      field_group: "rare-non-inherited->deprecated-flexible-box",
+      field_group: "*",
     },
     {
       name: "-webkit-box-reflect",
@@ -3052,7 +3055,7 @@
       converter: "ConvertBoxReflect",
       field_template: "pointer",
       type_name: "StyleReflection",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
       include_paths: ["core/style/StyleReflection.h"],
@@ -3066,7 +3069,7 @@
       type_name: "unsigned short",
       field_template: "storage_only",
       default_value: "1",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
       default_generated_functions: ["getter"],
     },
     {
@@ -3079,7 +3082,7 @@
       type_name: "float",
       field_template: "storage_only",
       default_value: "0.0f",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
       default_generated_functions: ["getter"],
     },
     {
@@ -3092,7 +3095,7 @@
       include_paths: ["platform/graphics/Color.h"],
       type_name: "Color",
       default_value: "0",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
     },
     {
       name: "column-rule-style",
@@ -3100,7 +3103,7 @@
       field_template: "keyword",
       default_value: "none",
       keywords: ["none", "hidden", "inset", "groove", "outset", "ridge", "dotted", "dashed", "solid", "double"],
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
     },
     {
       name: "column-rule-width",
@@ -3112,7 +3115,7 @@
       include_paths: ["platform/LayoutUnit.h"],
       type_name: "LayoutUnit",
       default_value: "LayoutUnit(3)",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
     },
     {
       name: "column-span",
@@ -3120,7 +3123,7 @@
       api_methods: ["ParseSingleValue"],
       field_template: "keyword",
       keywords: ["none", "all"],
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
       default_value: "none",
       getter: "GetColumnSpan",
     },
@@ -3134,7 +3137,7 @@
       field_template: "storage_only",
       type_name: "float",
       default_value: "0.0f",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*",
       default_generated_functions: ["getter"],
     },
     {
@@ -3147,7 +3150,7 @@
       type_name: "AtomicString",
       include_paths: ["platform/wtf/text/AtomicString.h"],
       default_value: "g_null_atom",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-hyphenate-character",
@@ -3160,7 +3163,7 @@
       type_name: "AtomicString",
       include_paths: ["platform/wtf/text/AtomicString.h"],
       default_value: "AtomicString()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-line-break",
@@ -3170,7 +3173,7 @@
       type_name: "LineBreak",
       keywords: ["auto", "loose", "normal", "strict", "after-white-space"],
       default_value: "auto",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "line-break",
@@ -3185,7 +3188,7 @@
       api_methods: ["ParseSingleValue"],
       type_name: "LineClampValue",
       field_template: "storage_only",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "LineClampValue()",
       include_paths: ["core/style/LineClampValue.h"],
     },
@@ -3194,7 +3197,7 @@
       type_name: "EMarginCollapse",
       field_template: "keyword",
       keywords: ["collapse", "separate", "discard"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "collapse",
     },
     {
@@ -3202,7 +3205,7 @@
       type_name: "EMarginCollapse",
       field_template: "keyword",
       keywords: ["collapse", "separate", "discard"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "collapse",
     },
     {
@@ -3346,7 +3349,7 @@
       type_name: "RubyPosition",
       keywords: ["before", "after"],
       default_value: "before",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-tap-highlight-color",
@@ -3354,11 +3357,9 @@
       api_methods: ["ParseSingleValue"],
       converter: "ConvertColor",
       inherited: true,
-      field_template: "external",
-      type_name: "Color",
-      include_paths: ["platform/graphics/Color.h"],
+      field_template: "<color>",
       default_value: "LayoutTheme::TapHighlightColor()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-text-combine",
@@ -3376,11 +3377,11 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-text-emphasis-position",
-      api_class: "CSSPropertyAPITextEmphasisPosition",
+      api_class: true,
       api_methods: ["ParseSingleValue"],
       converter: "ConvertTextTextEmphasisPosition",
       inherited: true,
@@ -3388,8 +3389,8 @@
       type_name: "TextEmphasisPosition",
       default_value: "TextEmphasisPosition::kOverRight",
       field_size: 2,
-      field_group: "rare-inherited",
       default_generated_functions: ["getter", "setter"],
+      field_group: "*",
     },
     {
       name: "-webkit-text-emphasis-style",
@@ -3408,7 +3409,7 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-text-security",
@@ -3417,7 +3418,7 @@
       field_template: "keyword",
       keywords: ["none", "disc", "circle", "square"],
       default_value: "none",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-text-stroke-color",
@@ -3430,7 +3431,7 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-text-stroke-width",
@@ -3441,7 +3442,7 @@
       field_template: "primitive",
       type_name: "float",
       default_value: "0",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "-webkit-transform-origin-x",
@@ -3467,7 +3468,7 @@
     {
       name: "-webkit-user-drag",
       field_template: "keyword",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "auto",
       keywords: ["auto", "none", "element"],
     },
@@ -3478,7 +3479,7 @@
       field_template: "keyword",
       keywords: ["read-only", "read-write", "read-write-plaintext-only"],
       default_value: "read-only",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "user-select",
@@ -3487,7 +3488,7 @@
       field_template: "keyword",
       keywords: ["auto", "none", "text", "all"],
       default_value: "auto",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "white-space",
@@ -3507,7 +3508,7 @@
       field_template: "primitive",
       type_name: "short",
       default_value: "2",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "width",
@@ -3536,7 +3537,7 @@
       // Word Break Values. Matches WinIE and CSS3
       keywords: ["normal", "break-all", "keep-all", "break-word"],
       default_value: "normal",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "word-spacing",
@@ -3946,7 +3947,7 @@
     },
     {
       name: "grid",
-      longhands: ["grid-template-rows", "grid-template-columns", "grid-template-areas", "grid-auto-flow", "grid-auto-rows", "grid-auto-columns", "grid-column-gap", "grid-row-gap"],
+      longhands: ["grid-template-rows", "grid-template-columns", "grid-template-areas", "grid-auto-flow", "grid-auto-rows", "grid-auto-columns"],
       api_class: true,
       api_methods: ["ParseShorthand"],
       runtime_flag: "CSSGridLayout",
diff --git a/third_party/WebKit/Source/core/css/CSSPropertiesRanking.json5 b/third_party/WebKit/Source/core/css/CSSPropertiesRanking.json5
index cbb6347..3d25d6b 100644
--- a/third_party/WebKit/Source/core/css/CSSPropertiesRanking.json5
+++ b/third_party/WebKit/Source/core/css/CSSPropertiesRanking.json5
@@ -1,577 +1,578 @@
+// The popularity ranking of all css properties the first properties is the most
+// used property according to: https://www.chromestatus.com/metrics/css/popularity
 {
-  // The popularity ranking of all css properties the first properties is the most
-  // used property according to: https://www.chromestatus.com/metrics/css/popularity
-  properties: {
-  },
-  data: [
-      "display",
-      "width",
-      "margin",
-      "height",
-      "overflow",
-      "font-size",
-      "color",
-      "background-color",
-      "padding",
-      "position",
-      "font-family",
-      "text-align",
-      "opacity",
-      "font-weight",
-      "max-width",
-      "box-sizing",
-      "max-height",
-      "webkit-user-select",
-      "webkit-user-select",
-      "border",
-      "cursor",
-      "top",
-      "margin-top",
-      "left",
-      "background",
-      "margin-left",
-      "padding-left",
-      "text-decoration",
-      "line-height",
-      "float",
-      "z-index",
-      "padding-top",
-      "background-image",
-      "vertical-align",
-      "margin-bottom",
-      "white-space",
-      "margin-right",
-      "border-bottom",
-      "padding-bottom",
-      "border-radius",
-      "right",
-      "align-items",
-      "padding-right",
-      "visibility",
-      "border-top",
-      "bottom",
-      "background-repeat",
-      "min-height",
-      "background-position",
-      "outline",
-      "content",
-      "justify-content",
-      "box-shadow",
-      "clear",
-      "border-color",
-      "min-width",
-      "border-left",
-      "font-style",
-      "background-size",
-      "border-right",
-      "font",
-      "list-style",
-      "transition",
-      "text-overflow",
-      "border-width",
-      "transform",
-      "border-style",
-      "border-collapse",
-      "text-transform",
-      "overflow-y",
-      "flex-direction",
-      "text-shadow",
-      "alias-webkit-transform",
-      "text-indent",
-      "zoom",
-      "alias-webkit-border-radius",
-      "alias-webkit-box-shadow",
-      "alias-webkit-box-sizing",
-      "webkit-appearance",
-      "alias-webkit-transition",
-      "word-wrap",
-      "pointer-events",
-      "border-bottom-left-radius",
-      "border-spacing",
-      "overflow-x",
-      "list-style-type",
-      "border-top-left-radius",
-      "border-bottom-right-radius",
-      "alias-webkit-animation",
-      "border-top-right-radius",
-      "border-top-color",
-      "animation",
-      "border-bottom-color",
-      "letter-spacing",
-      "fill",
-      "alias-webkit-text-size-adjust",
-      "webkit-font-smoothing",
-      "src",
-      "border-right-width",
-      "clip",
-      "user-select",
-      "border-bottom-width",
-      "webkit-tap-highlight-color",
-      "direction",
-      "border-top-width",
-      "border-right-color",
-      "border-left-width",
-      "border-left-color",
-      "word-break",
-      "table-layout",
-      "background-clip",
-      "transform-origin",
-      "filter",
-      "flex",
-      "alias-webkit-background-size",
-      "resize",
-      "webkit-box-orient",
-      "alias-webkit-transform-origin",
-      "webkit-filter",
-      "webkit-filter",
-      "alias-webkit-align-items",
-      "alias-webkit-backface-visibility",
-      "transition-property",
-      "alias-webkit-justify-content",
-      "text-rendering",
-      "font-variant",
-      "transition-duration",
-      "outline-offset",
-      "unicode-range",
-      "transition-timing-function",
-      "alias-webkit-animation-duration",
-      "alias-webkit-flex",
-      "alias-webkit-animation-name",
-      "flex-grow",
-      "alias-webkit-animation-timing-function",
-      "alias-webkit-transition-property",
-      "order",
-      "webkit-line-clamp",
-      "word-spacing",
-      "alias-webkit-border-top-right-radius",
-      "webkit-box-align",
-      "touch-action",
-      "transition-delay",
-      "animation-duration",
-      "alias-webkit-border-top-left-radius",
-      "backface-visibility",
-      "animation-name",
-      "stroke",
-      "alias-webkit-transition-duration",
-      "flex-wrap",
-      "alias-webkit-transition-timing-function",
-      "border-bottom-style",
-      "webkit-background-clip",
-      "webkit-box-pack",
-      "quotes",
-      "outline-width",
-      "alias-webkit-border-bottom-right-radius",
-      "alias-webkit-border-bottom-left-radius",
-      "alias-webkit-animation-fill-mode",
-      "alias-webkit-animation-delay",
-      "animation-timing-function",
-      "alias-webkit-flex-direction",
-      "webkit-box-flex",
-      "animation-delay",
-      "animation-fill-mode",
-      "flex-shrink",
-      "unicode-bidi",
-      "page-break-inside",
-      "alias-webkit-perspective",
-      "border-top-style",
-      "page-break-after",
-      "will-change",
-      "list-style-position",
-      "speak",
-      "alias-webkit-order",
-      "alias-webkit-flex-wrap",
-      "orphans",
-      "widows",
-      "outline-style",
-      "list-style-image",
-      "align-self",
-      "image-rendering",
-      "background-origin",
-      "alias-webkit-animation-iteration-count",
-      "border-left-style",
-      "fill-opacity",
-      "perspective",
-      "border-right-style",
-      "alias-webkit-transition-delay",
-      "outline-color",
-      "overflow-wrap",
-      "animation-iteration-count",
-      "webkit-animation-direction",
-      "webkit-animation-direction",
-      "stroke-width",
-      "stroke-width",
-      "align-content",
-      "webkit-box-direction",
-      "background-attachment",
-      "alias-webkit-animation-play-state",
-      "transform-style",
-      "flex-basis",
-      "alias-webkit-transform-style",
-      "alias-webkit-flex-grow",
-      "counter-increment",
-      "webkit-box-ordinal-group",
-      "counter-reset",
-      "alias-webkit-opacity",
-      "alias-webkit-flex-shrink",
-      "webkit-mask-image",
-      "webkit-margin-start",
-      "perspective-origin",
-      "alias-webkit-flex-flow",
-      "alias-webkit-perspective-origin",
-      "flex-flow",
-      "alias-webkit-align-self",
-      "background-position-x",
-      "background-position-y",
-      "border-image",
-      "font-stretch",
-      "webkit-user-drag",
-      "object-fit",
-      "alias-webkit-align-content",
-      "text-size-adjust",
-      "alias-webkit-flex-basis",
-      "animation-direction",
-      "column-count",
-      "webkit-font-feature-settings",
-      "webkit-font-feature-settings",
-      "webkit-margin-after",
-      "alias-webkit-column-count",
-      "webkit-margin-end",
-      "contain",
-      "animation-play-state",
-      "webkit-text-fill-color",
-      "stroke-opacity",
-      "empty-cells",
-      "webkit-mask-size",
-      "column-gap",
-      "hyphens",
-      "alias-webkit-column-gap",
-      "line-break",
-      "line-break",
-      "webkit-mask-repeat",
-      "stroke-dasharray",
-      "font-feature-settings",
-      "webkit-mask-position",
-      "fill-rule",
-      "webkit-padding-end",
-      "webkit-user-modify",
-      "stroke-linecap",
-      "stroke-dashoffset",
-      "columns",
-      "tab-size",
-      "stroke-miterlimit",
-      "webkit-border-image",
-      "stroke-linejoin",
-      "border-image-slice",
-      "webkit-padding-start",
-      "webkit-box-lines",
-      "webkit-margin-before",
-      "webkit-column-break-inside",
-      "alias-webkit-columns",
-      "page-break-before",
-      "break-inside",
-      "clip-path",
-      "webkit-app-region",
-      "column-width",
-      "webkit-text-stroke-width",
-      "caption-side",
-      "webkit-margin-top-collapse",
-      "border-image-width",
-      "size",
-      "font-kerning",
-      "stop-color",
-      "alias-webkit-column-width",
-      "border-image-repeat",
-      "text-decoration-color",
-      "border-image-outset",
-      "webkit-text-stroke-color",
-      "webkit-text-stroke",
-      "clip-rule",
-      "text-align-last",
-      "border-image-source",
-      "writing-mode",
-      "mix-blend-mode",
-      "webkit-print-color-adjust",
-      "webkit-clip-path",
-      "webkit-clip-path",
-      "shape-rendering",
-      "webkit-column-break-before",
-      "column-rule",
-      "font-variant-ligatures",
-      "text-anchor",
-      "overflow-anchor",
-      "webkit-line-break",
-      "webkit-box-decoration-break",
-      "column-fill",
-      "webkit-writing-mode",
-      "stop-opacity",
-      "column-rule-color",
-      "alias-webkit-column-rule",
-      "webkit-perspective-origin-x",
-      "webkit-perspective-origin-y",
-      "object-position",
-      "webkit-text-security",
-      "webkit-mask",
-      "text-decoration-style",
-      "background-blend-mode",
-      "column-rule-style",
-      "dominant-baseline",
-      "webkit-mask-box-image",
-      "alias-webkit-column-rule-color",
-      "text-decoration-line",
-      "font-variant-caps",
-      "webkit-background-origin",
-      "webkit-padding-before",
-      "shape-outside",
-      "webkit-padding-after",
-      "all",
-      "webkit-text-emphasis-color",
-      "mask",
-      "font-variant-numeric",
-      "isolation",
-      "column-rule-width",
-      "break-after",
-      "webkit-column-break-after",
-      "webkit-border-horizontal-spacing",
-      "break-before",
-      "alignment-baseline",
-      "webkit-box-reflect",
-      "page",
-      "baseline-shift",
-      "text-orientation",
-      "alias-webkit-column-rule-style",
-      "webkit-text-orientation",
-      "rx",
-      "ry",
-      "alias-webkit-column-rule-width",
-      "justify-self",
-      "webkit-highlight",
-      "background-repeat-y",
-      "webkit-rtl-ordering",
-      "background-repeat-x",
-      "webkit-transform-origin-x",
-      "column-span",
-      "webkit-transform-origin-y",
-      "webkit-text-emphasis",
-      "webkit-border-vertical-spacing",
-      "x",
-      "alias-webkit-column-span",
-      "text-decoration-skip",
-      "webkit-margin-collapse",
-      "y",
-      "r",
-      "grid-template-columns",
-      "webkit-text-combine",
-      "caret-color",
-      "color-rendering",
-      "vector-effect",
-      "color-interpolation-filters",
-      "mask-type",
-      "color-interpolation",
-      "webkit-mask-clip",
-      "marker",
-      "webkit-box-flex-group",
-      "justify-items",
-      "text-underline-position",
-      "marker-end",
-      "marker-start",
-      "webkit-border-start-width",
-      "marker-mid",
-      "webkit-border-start-color",
-      "flood-color",
-      "cy",
-      "shape-margin",
-      "flood-opacity",
-      "webkit-text-decorations-in-effect",
-      "cx",
-      "webkit-border-after-width",
-      "webkit-border-end-width",
-      "webkit-border-before-width",
-      "grid-template-rows",
-      "webkit-hyphenate-character",
-      "paint-order",
-      "webkit-border-end-color",
-      "webkit-border-before-color",
-      "webkit-border-after-color",
-      "webkit-border-end",
-      "webkit-locale",
-      "webkit-mask-composite",
-      "lighting-color",
-      "grid-auto-flow",
-      "d",
-      "shape-image-threshold",
-      "grid-column-gap",
-      "buffered-rendering",
-      "webkit-text-emphasis-position",
-      "grid-gap",
-      "grid-column-start",
-      "grid-auto-columns",
-      "webkit-mask-box-image-source",
-      "webkit-mask-box-image-outset",
-      "grid-template-areas",
-      "webkit-margin-bottom-collapse",
-      "webkit-mask-box-image-width",
-      "webkit-mask-box-image-repeat",
-      "webkit-mask-box-image-slice",
-      "offset-rotate",
-      "grid-auto-rows",
-      "grid-column-end",
-      "grid-column",
-      "webkit-text-emphasis-style",
-      "webkit-border-start",
-      "grid-row",
-      "grid-row-gap",
-      "webkit-mask-origin",
-      "grid-row-start",
-      "grid-row-end",
-      "webkit-margin-before-collapse",
-      "webkit-margin-after-collapse",
-      "offset-path",
-      "offset-distance",
-      "offset-rotation",
-      "grid-template",
-      "alias-webkit-shape-outside",
-      "webkit-border-end-style",
-      "grid-area",
-      "webkit-min-logical-width",
-      "alias-webkit-shape-margin",
-      "place-content",
-      "alias-epub-word-break",
-      "motion",
-      "place-items",
-      "font-display",
-      "webkit-mask-position-x",
-      "enable-background",
-      "text-combine-upright",
-      "webkit-mask-position-y",
-      "inline-size",
-      "block-size",
-      "min-block-size",
-      "webkit-border-after",
-      "webkit-border-before",
-      "max-inline-size",
-      "min-inline-size",
-      "max-block-size",
-      "webkit-max-logical-width",
-      "webkit-transform-origin-z",
-      "webkit-min-logical-height",
-      "webkit-logical-height",
-      "grid",
-      "webkit-max-logical-height",
-      "webkit-logical-width",
-      "webkit-font-size-delta",
-      "motion-path",
-      "motion-path",
-      "offset",
-      "webkit-ruby-position",
-      "text-justify",
-      "motion-offset",
-      "motion-offset",
-      "motion-rotation",
-      "motion-rotation",
-      "webkit-background-composite",
-      "alias-webkit-shape-image-threshold",
-      "scroll-behavior",
-      "webkit-border-start-style",
-      "font-size-adjust",
-      "glyph-orientation-vertical",
-      "glyph-orientation-horizontal",
-      "webkit-line-box-contain",
-      "webkit-border-fit",
-      "alias-epub-text-transform",
-      "alias-epub-writing-mode",
-      "webkit-border-after-style",
-      "webkit-border-before-style",
-      "place-self",
-      "max-zoom",
-      "min-zoom",
-      "backdrop-filter",
-      "webkit-region-break-inside",
-      "user-zoom",
-      "color-profile",
-      "rotate",
-      "translate",
-      "scale",
-      "alias-epub-text-combine",
-      "touch-action-delay",
-      "snap-height",
-      "snap-height",
-      "orientation",
-      "offset-position",
-      "mask-source-type",
-      "offset-anchor",
-      "kerning",
-      "webkit-mask-repeat-y",
-      "webkit-mask-repeat-x",
-      "alias-epub-text-emphasis-style",
-      "text-underline-style",
-      "webkit-column-progression",
-      "webkit-column-axis",
-      "webkit-line-align",
-      "webkit-line-grid",
-      "webkit-line-snap",
-      "font-variation-settings",
-      "alias-epub-text-orientation",
-      "text-overline",
-      "transform-box",
-      "text-underline-color",
-      "text-overline-width",
-      "alias-epub-text-emphasis-color",
-      "scroll-snap-destination",
-      "image-orientation",
-      "webkit-box-decoration-break",
-      "image-orientation",
-      "webkit-overflow-scrolling",
-      "webkit-dashboard-region",
-      "text-line-through",
-      "text-line-through-color",
-      "text-line-through-mode",
-      "text-line-through-style",
-      "text-line-through-width",
-      "text-overline-color",
-      "text-overline-mode",
-      "text-overline-style",
-      "text-underline",
-      "text-underline-mode",
-      "text-underline-width",
-      "webkit-aspect-ratio",
-      "webkit-color-correction",
-      "webkit-filter",
-      "webkit-hyphenate-limit-after",
-      "webkit-hyphenate-limit-before",
-      "webkit-hyphenate-limit-lines",
-      "webkit-hyphens",
-      "webkit-marquee",
-      "webkit-marquee-direction",
-      "webkit-marquee-increment",
-      "webkit-marquee-repetition",
-      "webkit-marquee-speed",
-      "webkit-marquee-style",
-      "webkit-nbsp-mode",
-      "webkit-flow-into",
-      "webkit-flow-from",
-      "webkit-region-fragment",
-      "webkit-region-break-after",
-      "webkit-region-break-before",
-      "shape-inside",
-      "shape-padding",
-      "webkit-wrap-flow",
-      "webkit-wrap-through",
-      "webkit-wrap",
-      "webkit-tap-highlight-color",
-      "webkit-app-region",
-      "webkit-svg-shadow",
-      "webkit-cursor-visibility",
-      "image-resolution",
-      "webkit-blend-mode",
-      "webkit-background-blend-mode",
-      "internal-callback",
-      "scroll-blocks-on",
-      "alias-epub-caption-side",
-      "alias-epub-text-emphasis",
-      "scroll-snap-type",
-      "scroll-snap-points-x",
-      "scroll-snap-points-y",
-      "scroll-snap-coordinate",
-      "variable",
-    ]
+    properties: {
+    },
+    data: [
+        "display",
+        "width",
+        "margin",
+        "height",
+        "overflow",
+        "font-size",
+        "color",
+        "background-color",
+        "padding",
+        "position",
+        "font-family",
+        "text-align",
+        "opacity",
+        "font-weight",
+        "max-width",
+        "box-sizing",
+        "max-height",
+        "webkit-user-select",
+        "webkit-user-select",
+        "border",
+        "cursor",
+        "top",
+        "margin-top",
+        "left",
+        "background",
+        "margin-left",
+        "padding-left",
+        "text-decoration",
+        "line-height",
+        "float",
+        "z-index",
+        "padding-top",
+        "background-image",
+        "vertical-align",
+        "margin-bottom",
+        "white-space",
+        "margin-right",
+        "border-bottom",
+        "padding-bottom",
+        "border-radius",
+        "right",
+        "align-items",
+        "padding-right",
+        "visibility",
+        "border-top",
+        "bottom",
+        "background-repeat",
+        "min-height",
+        "background-position",
+        "outline",
+        "content",
+        "justify-content",
+        "box-shadow",
+        "clear",
+        "border-color",
+        "min-width",
+        "border-left",
+        "font-style",
+        "background-size",
+        "border-right",
+        "font",
+        "list-style",
+        "transition",
+        "text-overflow",
+        "border-width",
+        "transform",
+        "border-style",
+        "border-collapse",
+        "text-transform",
+        "overflow-y",
+        "flex-direction",
+        "text-shadow",
+        "alias-webkit-transform",
+        "text-indent",
+        "zoom",
+        "alias-webkit-border-radius",
+        "alias-webkit-box-shadow",
+        "alias-webkit-box-sizing",
+        "webkit-appearance",
+        "alias-webkit-transition",
+        "word-wrap",
+        "pointer-events",
+        "border-bottom-left-radius",
+        "border-spacing",
+        "overflow-x",
+        "list-style-type",
+        "border-top-left-radius",
+        "border-bottom-right-radius",
+        "alias-webkit-animation",
+        "border-top-right-radius",
+        "border-top-color",
+        "animation",
+        "border-bottom-color",
+        "letter-spacing",
+        "fill",
+        "alias-webkit-text-size-adjust",
+        "webkit-font-smoothing",
+        "src",
+        "border-right-width",
+        "clip",
+        "user-select",
+        "border-bottom-width",
+        "webkit-tap-highlight-color",
+        "direction",
+        "border-top-width",
+        "border-right-color",
+        "border-left-width",
+        "border-left-color",
+        "word-break",
+        "table-layout",
+        "background-clip",
+        "transform-origin",
+        "filter",
+        "flex",
+        "alias-webkit-background-size",
+        "resize",
+        "webkit-box-orient",
+        "alias-webkit-transform-origin",
+        "webkit-filter",
+        "webkit-filter",
+        "alias-webkit-align-items",
+        "alias-webkit-backface-visibility",
+        "transition-property",
+        "alias-webkit-justify-content",
+        "text-rendering",
+        "font-variant",
+        "transition-duration",
+        "outline-offset",
+        "unicode-range",
+        "transition-timing-function",
+        "alias-webkit-animation-duration",
+        "alias-webkit-flex",
+        "alias-webkit-animation-name",
+        "flex-grow",
+        "alias-webkit-animation-timing-function",
+        "alias-webkit-transition-property",
+        "order",
+        "webkit-line-clamp",
+        "word-spacing",
+        "alias-webkit-border-top-right-radius",
+        "webkit-box-align",
+        "touch-action",
+        "transition-delay",
+        "animation-duration",
+        "alias-webkit-border-top-left-radius",
+        "backface-visibility",
+        "animation-name",
+        "stroke",
+        "alias-webkit-transition-duration",
+        "flex-wrap",
+        "alias-webkit-transition-timing-function",
+        "border-bottom-style",
+        "webkit-background-clip",
+        "webkit-box-pack",
+        "quotes",
+        "outline-width",
+        "alias-webkit-border-bottom-right-radius",
+        "alias-webkit-border-bottom-left-radius",
+        "alias-webkit-animation-fill-mode",
+        "alias-webkit-animation-delay",
+        "animation-timing-function",
+        "alias-webkit-flex-direction",
+        "webkit-box-flex",
+        "animation-delay",
+        "animation-fill-mode",
+        "flex-shrink",
+        "unicode-bidi",
+        "page-break-inside",
+        "alias-webkit-perspective",
+        "border-top-style",
+        "page-break-after",
+        "will-change",
+        "list-style-position",
+        "speak",
+        "alias-webkit-order",
+        "alias-webkit-flex-wrap",
+        "orphans",
+        "widows",
+        "outline-style",
+        "list-style-image",
+        "align-self",
+        "image-rendering",
+        "background-origin",
+        "alias-webkit-animation-iteration-count",
+        "border-left-style",
+        "fill-opacity",
+        "perspective",
+        "border-right-style",
+        "alias-webkit-transition-delay",
+        "outline-color",
+        "overflow-wrap",
+        "animation-iteration-count",
+        "webkit-animation-direction",
+        "webkit-animation-direction",
+        "stroke-width",
+        "stroke-width",
+        "align-content",
+        "webkit-box-direction",
+        "background-attachment",
+        "alias-webkit-animation-play-state",
+        "transform-style",
+        "flex-basis",
+        "alias-webkit-transform-style",
+        "alias-webkit-flex-grow",
+        "counter-increment",
+        "webkit-box-ordinal-group",
+        "counter-reset",
+        "alias-webkit-opacity",
+        "alias-webkit-flex-shrink",
+        "webkit-mask-image",
+        "webkit-margin-start",
+        "perspective-origin",
+        "alias-webkit-flex-flow",
+        "alias-webkit-perspective-origin",
+        "flex-flow",
+        "alias-webkit-align-self",
+        "background-position-x",
+        "background-position-y",
+        "border-image",
+        "font-stretch",
+        "webkit-user-drag",
+        "object-fit",
+        "alias-webkit-align-content",
+        "text-size-adjust",
+        "alias-webkit-flex-basis",
+        "animation-direction",
+        "column-count",
+        "webkit-font-feature-settings",
+        "webkit-font-feature-settings",
+        "webkit-margin-after",
+        "alias-webkit-column-count",
+        "webkit-margin-end",
+        "contain",
+        "animation-play-state",
+        "webkit-text-fill-color",
+        "stroke-opacity",
+        "empty-cells",
+        "webkit-mask-size",
+        "column-gap",
+        "hyphens",
+        "alias-webkit-column-gap",
+        "line-break",
+        "line-break",
+        "webkit-mask-repeat",
+        "stroke-dasharray",
+        "font-feature-settings",
+        "webkit-mask-position",
+        "fill-rule",
+        "webkit-padding-end",
+        "webkit-user-modify",
+        "stroke-linecap",
+        "stroke-dashoffset",
+        "columns",
+        "tab-size",
+        "stroke-miterlimit",
+        "webkit-border-image",
+        "stroke-linejoin",
+        "border-image-slice",
+        "webkit-padding-start",
+        "webkit-box-lines",
+        "webkit-margin-before",
+        "webkit-column-break-inside",
+        "alias-webkit-columns",
+        "page-break-before",
+        "break-inside",
+        "clip-path",
+        "webkit-app-region",
+        "column-width",
+        "webkit-text-stroke-width",
+        "caption-side",
+        "webkit-margin-top-collapse",
+        "border-image-width",
+        "size",
+        "font-kerning",
+        "stop-color",
+        "alias-webkit-column-width",
+        "border-image-repeat",
+        "text-decoration-color",
+        "border-image-outset",
+        "webkit-text-stroke-color",
+        "webkit-text-stroke",
+        "clip-rule",
+        "text-align-last",
+        "border-image-source",
+        "writing-mode",
+        "mix-blend-mode",
+        "webkit-print-color-adjust",
+        "webkit-clip-path",
+        "webkit-clip-path",
+        "shape-rendering",
+        "webkit-column-break-before",
+        "column-rule",
+        "font-variant-ligatures",
+        "text-anchor",
+        "overflow-anchor",
+        "webkit-line-break",
+        "webkit-box-decoration-break",
+        "column-fill",
+        "webkit-writing-mode",
+        "stop-opacity",
+        "column-rule-color",
+        "alias-webkit-column-rule",
+        "webkit-perspective-origin-x",
+        "webkit-perspective-origin-y",
+        "object-position",
+        "webkit-text-security",
+        "webkit-mask",
+        "text-decoration-style",
+        "background-blend-mode",
+        "column-rule-style",
+        "dominant-baseline",
+        "webkit-mask-box-image",
+        "alias-webkit-column-rule-color",
+        "text-decoration-line",
+        "font-variant-caps",
+        "webkit-background-origin",
+        "webkit-padding-before",
+        "shape-outside",
+        "webkit-padding-after",
+        "all",
+        "webkit-text-emphasis-color",
+        "mask",
+        "font-variant-numeric",
+        "isolation",
+        "column-rule-width",
+        "break-after",
+        "webkit-column-break-after",
+        "webkit-border-horizontal-spacing",
+        "break-before",
+        "alignment-baseline",
+        "webkit-box-reflect",
+        "page",
+        "baseline-shift",
+        "text-orientation",
+        "alias-webkit-column-rule-style",
+        "webkit-text-orientation",
+        "rx",
+        "ry",
+        "alias-webkit-column-rule-width",
+        "justify-self",
+        "webkit-highlight",
+        "background-repeat-y",
+        "webkit-rtl-ordering",
+        "background-repeat-x",
+        "webkit-transform-origin-x",
+        "column-span",
+        "webkit-transform-origin-y",
+        "webkit-text-emphasis",
+        "webkit-border-vertical-spacing",
+        "x",
+        "alias-webkit-column-span",
+        "text-decoration-skip",
+        "webkit-margin-collapse",
+        "y",
+        "r",
+        "grid-template-columns",
+        "webkit-text-combine",
+        "caret-color",
+        "color-rendering",
+        "vector-effect",
+        "color-interpolation-filters",
+        "mask-type",
+        "color-interpolation",
+        "webkit-mask-clip",
+        "marker",
+        "webkit-box-flex-group",
+        "justify-items",
+        "text-underline-position",
+        "marker-end",
+        "marker-start",
+        "webkit-border-start-width",
+        "marker-mid",
+        "webkit-border-start-color",
+        "flood-color",
+        "cy",
+        "shape-margin",
+        "flood-opacity",
+        "webkit-text-decorations-in-effect",
+        "cx",
+        "webkit-border-after-width",
+        "webkit-border-end-width",
+        "webkit-border-before-width",
+        "grid-template-rows",
+        "webkit-hyphenate-character",
+        "paint-order",
+        "webkit-border-end-color",
+        "webkit-border-before-color",
+        "webkit-border-after-color",
+        "webkit-border-end",
+        "webkit-locale",
+        "webkit-mask-composite",
+        "lighting-color",
+        "grid-auto-flow",
+        "d",
+        "shape-image-threshold",
+        "grid-column-gap",
+        "buffered-rendering",
+        "webkit-text-emphasis-position",
+        "grid-gap",
+        "grid-column-start",
+        "grid-auto-columns",
+        "webkit-mask-box-image-source",
+        "webkit-mask-box-image-outset",
+        "grid-template-areas",
+        "webkit-margin-bottom-collapse",
+        "webkit-mask-box-image-width",
+        "webkit-mask-box-image-repeat",
+        "webkit-mask-box-image-slice",
+        "offset-rotate",
+        "grid-auto-rows",
+        "grid-column-end",
+        "grid-column",
+        "webkit-text-emphasis-style",
+        "webkit-border-start",
+        "grid-row",
+        "grid-row-gap",
+        "webkit-mask-origin",
+        "grid-row-start",
+        "grid-row-end",
+        "webkit-margin-before-collapse",
+        "webkit-margin-after-collapse",
+        "offset-path",
+        "offset-distance",
+        "offset-rotation",
+        "grid-template",
+        "alias-webkit-shape-outside",
+        "webkit-border-end-style",
+        "grid-area",
+        "webkit-min-logical-width",
+        "alias-webkit-shape-margin",
+        "place-content",
+        "alias-epub-word-break",
+        "motion",
+        "place-items",
+        "font-display",
+        "webkit-mask-position-x",
+        "enable-background",
+        "text-combine-upright",
+        "webkit-mask-position-y",
+        "inline-size",
+        "block-size",
+        "min-block-size",
+        "webkit-border-after",
+        "webkit-border-before",
+        "max-inline-size",
+        "min-inline-size",
+        "max-block-size",
+        "webkit-max-logical-width",
+        "webkit-transform-origin-z",
+        "webkit-min-logical-height",
+        "webkit-logical-height",
+        "grid",
+        "webkit-max-logical-height",
+        "webkit-logical-width",
+        "webkit-font-size-delta",
+        "motion-path",
+        "motion-path",
+        "offset",
+        "webkit-ruby-position",
+        "text-justify",
+        "motion-offset",
+        "motion-offset",
+        "motion-rotation",
+        "motion-rotation",
+        "webkit-background-composite",
+        "alias-webkit-shape-image-threshold",
+        "scroll-behavior",
+        "webkit-border-start-style",
+        "font-size-adjust",
+        "glyph-orientation-vertical",
+        "glyph-orientation-horizontal",
+        "webkit-line-box-contain",
+        "webkit-border-fit",
+        "alias-epub-text-transform",
+        "alias-epub-writing-mode",
+        "webkit-border-after-style",
+        "webkit-border-before-style",
+        "place-self",
+        "max-zoom",
+        "min-zoom",
+        "backdrop-filter",
+        "webkit-region-break-inside",
+        "user-zoom",
+        "color-profile",
+        "rotate",
+        "translate",
+        "scale",
+        "alias-epub-text-combine",
+        "touch-action-delay",
+        "snap-height",
+        "snap-height",
+        "orientation",
+        "offset-position",
+        "mask-source-type",
+        "offset-anchor",
+        "kerning",
+        "webkit-mask-repeat-y",
+        "webkit-mask-repeat-x",
+        "alias-epub-text-emphasis-style",
+        "text-underline-style",
+        "webkit-column-progression",
+        "webkit-column-axis",
+        "webkit-line-align",
+        "webkit-line-grid",
+        "webkit-line-snap",
+        "font-variation-settings",
+        "alias-epub-text-orientation",
+        "text-overline",
+        "transform-box",
+        "text-underline-color",
+        "text-overline-width",
+        "alias-epub-text-emphasis-color",
+        "scroll-snap-destination",
+        "image-orientation",
+        "webkit-box-decoration-break",
+        "image-orientation",
+        "webkit-overflow-scrolling",
+        "webkit-dashboard-region",
+        "text-line-through",
+        "text-line-through-color",
+        "text-line-through-mode",
+        "text-line-through-style",
+        "text-line-through-width",
+        "text-overline-color",
+        "text-overline-mode",
+        "text-overline-style",
+        "text-underline",
+        "text-underline-mode",
+        "text-underline-width",
+        "webkit-aspect-ratio",
+        "webkit-color-correction",
+        "webkit-filter",
+        "webkit-hyphenate-limit-after",
+        "webkit-hyphenate-limit-before",
+        "webkit-hyphenate-limit-lines",
+        "webkit-hyphens",
+        "webkit-marquee",
+        "webkit-marquee-direction",
+        "webkit-marquee-increment",
+        "webkit-marquee-repetition",
+        "webkit-marquee-speed",
+        "webkit-marquee-style",
+        "webkit-nbsp-mode",
+        "webkit-flow-into",
+        "webkit-flow-from",
+        "webkit-region-fragment",
+        "webkit-region-break-after",
+        "webkit-region-break-before",
+        "shape-inside",
+        "shape-padding",
+        "webkit-wrap-flow",
+        "webkit-wrap-through",
+        "webkit-wrap",
+        "webkit-tap-highlight-color",
+        "webkit-app-region",
+        "webkit-svg-shadow",
+        "webkit-cursor-visibility",
+        "image-resolution",
+        "webkit-blend-mode",
+        "webkit-background-blend-mode",
+        "internal-callback",
+        "scroll-blocks-on",
+        "alias-epub-caption-side",
+        "alias-epub-text-emphasis",
+        "scroll-snap-type",
+        "scroll-snap-points-x",
+        "scroll-snap-points-y",
+        "scroll-snap-coordinate",
+        "variable",
+    ],
+    "properties": {}
 }
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index dde5dde1..cfcdedc4 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -246,9 +246,7 @@
     {
       name: "VisitedLinkColor",
       inherited: true,
-      field_template: "external",
-      include_paths: ["platform/graphics/Color.h"],
-      type_name: "Color",
+      field_template: "<color>",
       field_group: "inherited",
       default_value: "Color::kBlack",
     },
@@ -267,7 +265,7 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkTextFillColor",
@@ -276,7 +274,7 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkTextEmphasisColor",
@@ -285,7 +283,7 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkCaretColor",
@@ -294,7 +292,7 @@
       type_name: "Color",
       include_paths: ["platform/graphics/Color.h"],
       default_value: "Color()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "CursorData",
@@ -304,7 +302,7 @@
       include_paths: ["core/style/CursorList.h"],
       default_value: "nullptr",
       wrapper_pointer_name: "Persistent",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "EffectiveZoom",
@@ -312,7 +310,7 @@
       field_template: "storage_only",
       type_name: "float",
       default_value: "1.0f",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextStrokeColorIsCurrentColor",
@@ -320,7 +318,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextFillColorIsCurrentColor",
@@ -328,7 +326,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextEmphasisColorIsCurrentColor",
@@ -336,7 +334,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "CaretColorIsCurrentColor",
@@ -344,7 +342,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "false",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "CaretColorIsAuto",
@@ -352,7 +350,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkTextStrokeColorIsCurrentColor",
@@ -360,7 +358,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkTextFillColorIsCurrentColor",
@@ -368,7 +366,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkTextEmphasisColorIsCurrentColor",
@@ -376,7 +374,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkCaretColorIsCurrentColor",
@@ -384,7 +382,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "false",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkCaretColorIsAuto",
@@ -392,7 +390,7 @@
       field_template: "storage_only",
       type_name: "bool",
       default_value: "true",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextEmphasisFill",
@@ -401,7 +399,7 @@
       type_name: "TextEmphasisFill",
       default_value: "filled",
       keywords: ["filled", "open"],
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextEmphasisMark",
@@ -410,7 +408,7 @@
       type_name: "TextEmphasisMark",
       default_value: "TextEmphasisMark::kNone",
       keywords: ["none", "auto", "dot", "circle", "double-circle", "triangle", "sesame", "custom"],
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextIndentLine",
@@ -419,7 +417,7 @@
       type_name: "TextIndentLine",
       keywords: ["first-line", "each-line"],
       default_value: "first-line",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextIndentType",
@@ -428,7 +426,7 @@
       type_name: "TextIndentType",
       keywords: ["normal", "hanging"],
       default_value: "normal",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     // Though will-change is not itself an inherited property, the intent
     // expressed by 'will-change: contents' includes descendants.
@@ -438,7 +436,7 @@
       field_template: "primitive",
       type_name: "bool",
       default_value: "false",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "SelfOrAncestorHasDirAutoAttribute",
@@ -446,7 +444,7 @@
       field_template: "primitive",
       type_name: "bool",
       default_value: "false",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     // Though position: sticky is not itself an inherited property, being a
     // descendent of a sticky element changes some document lifecycle logic.
@@ -456,7 +454,7 @@
       field_template: "primitive",
       type_name: "bool",
       default_value: "false",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "HyphenationLimitBefore",
@@ -464,7 +462,7 @@
       field_template: "storage_only",
       type_name: "short",
       default_value: "-1",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "HyphenationLimitAfter",
@@ -472,7 +470,7 @@
       field_template: "storage_only",
       type_name: "short",
       default_value: "-1",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "HyphenationLimitLines",
@@ -480,7 +478,7 @@
       field_template: "storage_only",
       type_name: "short",
       default_value: "-1",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "EffectiveTouchAction",
@@ -490,7 +488,7 @@
       type_name: "TouchAction",
       field_size: 6,
       default_value: "TouchAction::kTouchActionAuto",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "TextEmphasisCustomMark",
@@ -499,7 +497,7 @@
       type_name: "AtomicString",
       include_paths: ["platform/wtf/text/AtomicString.h"],
       default_value: "AtomicString()",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "AppliedTextDecorations",
@@ -509,7 +507,7 @@
       include_paths: ["core/style/AppliedTextDecorationList.h"],
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "InheritedVariables",
@@ -519,20 +517,20 @@
       include_paths: ["core/style/StyleInheritedVariables.h"],
       default_value: "nullptr",
       wrapper_pointer_name: "RefPtr",
-      field_group: "rare-inherited",
+      field_group: "*",
     },
     {
       name: "Mask",
       field_template: "storage_only",
       type_name: "FillLayer",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "FillLayer(kMaskFillLayer, true)",
     },
     {
       name: "CounterDirectives",
       field_template: "storage_only",
       type_name: "CounterDirectiveMap",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "std::unique_ptr",
       include_paths: ["core/style/CounterDirectives.h"],
@@ -541,7 +539,7 @@
       name: "Animations",
       field_template: "storage_only",
       type_name: "CSSAnimationData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "std::unique_ptr",
       include_paths: ["core/animation/css/CSSAnimationData.h"],
@@ -550,7 +548,7 @@
       name: "Transitions",
       field_template: "storage_only",
       type_name: "CSSTransitionData",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "std::unique_ptr",
       include_paths: ["core/animation/css/CSSTransitionData.h"],
@@ -559,7 +557,7 @@
       name: "MaskBoxImage",
       field_template: "storage_only",
       type_name: "NinePieceImage",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "NinePieceImage::MaskDefaults()",
       include_paths: ["core/style/NinePieceImage.h"],
     },
@@ -567,7 +565,7 @@
       name: "PageSize",
       field_template: "external",
       type_name: "FloatSize",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "FloatSize()",
       include_paths: ["platform/geometry/FloatSize.h"],
     },
@@ -576,7 +574,7 @@
       field_template: "primitive",
       default_value: "true",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
     },
     // TODO(shend): Investigate why this doesn't interact with other outline fields.
     {
@@ -584,62 +582,62 @@
       field_template: "primitive",
       type_name: "bool",
       default_value: "false",
-      field_group: "rare-non-inherited",
+      field_group: "*",
     },
     {
       name: "VisitedLinkTextDecorationColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor::CurrentColor()",
     },
     {
       name: "VisitedLinkBackgroundColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor(Color::kTransparent)",
     },
     {
       name: "VisitedLinkOutlineColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor::CurrentColor()",
     },
     {
       name: "VisitedLinkBorderLeftColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor::CurrentColor()",
     },
     {
       name: "VisitedLinkBorderRightColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor::CurrentColor()",
     },
     {
       name: "VisitedLinkBorderTopColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor::CurrentColor()",
     },
     {
       name: "VisitedLinkBorderBottomColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "StyleColor::CurrentColor()",
     },
     {
       name: "CallbackSelectors",
       field_template: "storage_only",
       type_name: "Vector<String>",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "Vector<String>()",
       include_paths: ["platform/wtf/Vector.h", "platform/wtf/text/WTFString.h"],
     },
@@ -647,7 +645,7 @@
       name: "PaintImages",
       field_template: "storage_only",
       type_name: "PaintImages",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "std::unique_ptr",
       custom_compare: true,
@@ -657,7 +655,7 @@
       name: "NonInheritedVariables",
       field_template: "storage_only",
       type_name: "StyleNonInheritedVariables",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "nullptr",
       wrapper_pointer_name: "std::unique_ptr",
       include_paths: ["core/style/StyleNonInheritedVariables.h"],
@@ -666,42 +664,42 @@
       name: "PageSizeType",
       field_template: "keyword",
       keywords: ["auto", "landscape", "portrait", "resolved"],
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "auto",
     },
     {
       name: "HasCurrentOpacityAnimation",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     {
       name: "HasCurrentTransformAnimation",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     {
       name: "HasCurrentFilterAnimation",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     {
       name: "HasCurrentBackdropFilterAnimation",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     {
       name: "IsRunningOpacityAnimationOnCompositor",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       custom_compare: true,
       default_value: "false",
     },
@@ -709,7 +707,7 @@
       name: "IsRunningTransformAnimationOnCompositor",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       custom_compare: true,
       default_value: "false",
     },
@@ -717,7 +715,7 @@
       name: "IsRunningFilterAnimationOnCompositor",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       custom_compare: true,
       default_value: "false",
     },
@@ -725,7 +723,7 @@
       name: "IsRunningBackdropFilterAnimationOnCompositor",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       custom_compare: true,
       default_value: "false",
     },
@@ -738,7 +736,7 @@
       name: "IsStackingContext",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     // Plugins require accelerated compositing for reasons external to blink.
@@ -749,14 +747,14 @@
       name: "RequiresAcceleratedCompositingForExternalReasons",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     {
       name: "HasInlineTransform",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     // Style adjustment for appearance is disabled when certain properties are set.
@@ -764,21 +762,21 @@
       name: "HasAuthorBackground",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     {
       name: "HasAuthorBorder",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited",
+      field_group: "*",
       default_value: "false",
     },
     {
       name: "WillChangeProperties",
       field_template: "external",
       type_name: "Vector<CSSPropertyID>",
-      field_group: "rare-non-inherited->will-change",
+      field_group: "*->will-change",
       default_value: "Vector<CSSPropertyID>()",
       include_paths: ["platform/wtf/Vector.h", "core/CSSPropertyNames.h"],
     },
@@ -786,14 +784,14 @@
       name: "WillChangeContents",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited->will-change",
+      field_group: "*->will-change",
       default_value: "false",
     },
     {
       name: "WillChangeScrollPosition",
       field_template: "primitive",
       type_name: "bool",
-      field_group: "rare-non-inherited->will-change",
+      field_group: "*->will-change",
       default_value: "false",
     },
     {
@@ -801,13 +799,13 @@
       field_template: "primitive",
       default_value: "true",
       type_name: "bool",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*->multi-col",
     },
     {
       name: "VisitedLinkColumnRuleColor",
       field_template: "storage_only",
       type_name: "StyleColor",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*->multi-col",
       default_value: "StyleColor::CurrentColor()",
       include_paths: ["core/css/StyleColor.h"],
     },
@@ -815,28 +813,28 @@
       name: "ColumnAutoWidth",
       field_template: "storage_only",
       type_name: "bool",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*->multi-col",
       default_value: "true",
     },
     {
       name: "ColumnAutoCount",
       field_template: "storage_only",
       type_name: "bool",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*->multi-col",
       default_value: "true",
     },
     {
       name: "ColumnNormalGap",
       field_template: "storage_only",
       type_name: "bool",
-      field_group: "rare-non-inherited->multi-col",
+      field_group: "*->multi-col",
       default_value: "true",
     },
     {
       name: "NamedGridColumnLines",
       field_template: "external",
       type_name: "NamedGridLinesMap",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "NamedGridLinesMap()",
       include_paths: ["core/style/NamedGridLinesMap.h"],
     },
@@ -844,7 +842,7 @@
       name: "NamedGridRowLines",
       field_template: "external",
       type_name: "NamedGridLinesMap",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "NamedGridLinesMap()",
       include_paths: ["core/style/NamedGridLinesMap.h"],
     },
@@ -852,7 +850,7 @@
       name: "OrderedNamedGridColumnLines",
       field_template: "external",
       type_name: "OrderedNamedGridLines",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "OrderedNamedGridLines()",
       include_paths: ["core/style/OrderedNamedGridLines.h"],
     },
@@ -860,7 +858,7 @@
       name: "OrderedNamedGridRowLines",
       field_template: "external",
       type_name: "OrderedNamedGridLines",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "OrderedNamedGridLines()",
       include_paths: ["core/style/OrderedNamedGridLines.h"],
     },
@@ -868,7 +866,7 @@
       name: "AutoRepeatNamedGridColumnLines",
       field_template: "external",
       type_name: "NamedGridLinesMap",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "NamedGridLinesMap()",
       include_paths: ["core/style/NamedGridLinesMap.h"],
     },
@@ -876,7 +874,7 @@
       name: "AutoRepeatNamedGridRowLines",
       field_template: "external",
       type_name: "NamedGridLinesMap",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "NamedGridLinesMap()",
       include_paths: ["core/style/NamedGridLinesMap.h"],
     },
@@ -884,7 +882,7 @@
       name: "AutoRepeatOrderedNamedGridColumnLines",
       field_template: "external",
       type_name: "OrderedNamedGridLines",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "OrderedNamedGridLines()",
       include_paths: ["core/style/OrderedNamedGridLines.h"],
     },
@@ -892,7 +890,7 @@
       name: "AutoRepeatOrderedNamedGridRowLines",
       field_template: "external",
       type_name: "OrderedNamedGridLines",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "OrderedNamedGridLines()",
       include_paths: ["core/style/OrderedNamedGridLines.h"],
     },
@@ -900,7 +898,7 @@
       name: "NamedGridArea",
       field_template: "external",
       type_name: "NamedGridAreaMap",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "NamedGridAreaMap()",
       include_paths: ["core/style/GridArea.h"]
     },
@@ -908,21 +906,21 @@
       name: "NamedGridAreaRowCount",
       field_template: "primitive",
       type_name: "size_t",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "0",
     },
     {
       name: "NamedGridAreaColumnCount",
       field_template: "primitive",
       type_name: "size_t",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "0",
     },
     {
       name: "GridAutoRepeatColumns",
       field_template: "external",
       type_name: "Vector<GridTrackSize>",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "Vector<GridTrackSize>()",
       include_paths: ["platform/wtf/Vector.h", "core/style/GridTrackSize.h"],
     },
@@ -930,7 +928,7 @@
       name: "GridAutoRepeatRows",
       field_template: "external",
       type_name: "Vector<GridTrackSize>",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "Vector<GridTrackSize>()",
       include_paths: ["platform/wtf/Vector.h", "core/style/GridTrackSize.h"],
     },
@@ -938,21 +936,21 @@
       name: "GridAutoRepeatColumnsInsertionPoint",
       field_template: "primitive",
       type_name: "size_t",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "0",
     },
     {
       name: "GridAutoRepeatRowsInsertionPoint",
       field_template: "primitive",
       type_name: "size_t",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       default_value: "0",
     },
     {
       name: "GridAutoRepeatColumnsType",
       field_template: "keyword",
       type_name: "AutoRepeatType",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       keywords: ["no-auto-repeat", "auto-fill", "auto-fit"],
       default_value: "no-auto-repeat",
     },
@@ -960,7 +958,7 @@
       name: "GridAutoRepeatRowsType",
       field_template: "keyword",
       type_name: "AutoRepeatType",
-      field_group: "rare-non-inherited->grid",
+      field_group: "*->grid",
       keywords: ["no-auto-repeat", "auto-fill", "auto-fit"],
       default_value: "no-auto-repeat",
     },
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleFieldAliases.json5 b/third_party/WebKit/Source/core/css/ComputedStyleFieldAliases.json5
new file mode 100644
index 0000000..d7183d6
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/ComputedStyleFieldAliases.json5
@@ -0,0 +1,20 @@
+{
+// This file specifies all alias used in CSSProperties.json5, these alias
+// replace frequently used combination of property.
+    "parameters": {
+    },
+    "data": [
+        {
+            "name": "<length>",
+            "field_template": "external",
+            "type_name": "Length",
+            "include_paths": ["platform/Length.h"]
+        },
+        {
+            "name": "<color>",
+            "field_template": "external",
+            "type_name": "Color",
+            "include_paths": ["platform/graphics/Color.h"],
+        }
+    ]
+}
diff --git a/third_party/WebKit/Source/core/css/FontFace.cpp b/third_party/WebKit/Source/core/css/FontFace.cpp
index 58ab1ea4..5e4f853 100644
--- a/third_party/WebKit/Source/core/css/FontFace.cpp
+++ b/third_party/WebKit/Source/core/css/FontFace.cpp
@@ -31,7 +31,7 @@
 #include "core/css/FontFace.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/StringOrArrayBufferOrArrayBufferView.h"
+#include "bindings/core/v8/string_or_array_buffer_or_array_buffer_view.h"
 #include "core/CSSValueKeywords.h"
 #include "core/css/BinaryDataFontFaceSource.h"
 #include "core/css/CSSFontFace.h"
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.h b/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.h
index cd49476..f348c3a 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.h
+++ b/third_party/WebKit/Source/core/css/cssom/CSSUnparsedValue.h
@@ -5,7 +5,7 @@
 #ifndef CSSUnparsedValue_h
 #define CSSUnparsedValue_h
 
-#include "bindings/core/v8/StringOrCSSVariableReferenceValue.h"
+#include "bindings/core/v8/string_or_css_variable_reference_value.h"
 #include "core/css/CSSVariableReferenceValue.h"
 #include "core/css/cssom/CSSStyleValue.h"
 #include "platform/wtf/Vector.h"
diff --git a/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h b/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h
index aa23d8e2..6af1de8 100644
--- a/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h
+++ b/third_party/WebKit/Source/core/css/cssom/StylePropertyMapReadonly.h
@@ -5,9 +5,9 @@
 #ifndef StylePropertyMapReadonly_h
 #define StylePropertyMapReadonly_h
 
-#include "bindings/core/v8/CSSStyleValueOrCSSStyleValueSequence.h"
-#include "bindings/core/v8/CSSStyleValueOrCSSStyleValueSequenceOrString.h"
 #include "bindings/core/v8/Iterable.h"
+#include "bindings/core/v8/css_style_value_or_css_style_value_sequence.h"
+#include "bindings/core/v8/css_style_value_or_css_style_value_sequence_or_string.h"
 #include "core/CSSPropertyNames.h"
 #include "core/CoreExport.h"
 #include "core/css/cssom/CSSStyleValue.h"
diff --git a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.cpp b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.cpp
index 4e7e214..45d9605 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.cpp
@@ -4,7 +4,7 @@
 
 #include "core/css/parser/CSSLazyParsingState.h"
 #include "core/css/parser/CSSLazyPropertyParserImpl.h"
-#include "core/css/parser/CSSParserTokenRange.h"
+#include "core/css/parser/CSSParserTokenStream.h"
 #include "core/dom/Document.h"
 #include "core/frame/UseCounter.h"
 #include "platform/Histogram.h"
@@ -12,11 +12,9 @@
 namespace blink {
 
 CSSLazyParsingState::CSSLazyParsingState(const CSSParserContext* context,
-                                         Vector<String> escaped_strings,
                                          const String& sheet_text,
                                          StyleSheetContents* contents)
     : context_(context),
-      escaped_strings_(std::move(escaped_strings)),
       sheet_text_(sheet_text),
       owning_contents_(contents),
       parsed_style_rules_(0),
@@ -30,9 +28,9 @@
 }
 
 CSSLazyPropertyParserImpl* CSSLazyParsingState::CreateLazyParser(
-    const CSSParserTokenRange& block) {
+    const size_t offset) {
   ++total_style_rules_;
-  return new CSSLazyPropertyParserImpl(std::move(block), this);
+  return new CSSLazyPropertyParserImpl(offset, this);
 }
 
 const CSSParserContext* CSSLazyParsingState::Context() {
@@ -63,13 +61,13 @@
 
 bool CSSLazyParsingState::ShouldLazilyParseProperties(
     const CSSSelectorList& selectors,
-    const CSSParserTokenRange& block) const {
-  // Simple heuristic for an empty block. Note that |block| here does not
-  // include {} brackets. We avoid lazy parsing empty blocks so we can avoid
-  // considering them when possible for matching. Lazy blocks must always be
-  // considered. Three tokens is a reasonable minimum for a block:
-  // ident ':' <value>.
-  if (block.end() - block.begin() <= 2)
+    const CSSParserTokenStream& block) const {
+  // We should avoid lazy parsing empty blocks so we can avoid considering them
+  // when possible for matching. Lazy blocks must always be considered.
+  // Unfortunately, we can't tell how big the block will be, so the
+  // best we can do is to check if the next token is the end of the block.
+  // TODO(shend): Can we peek further than one token?
+  if (block.AtEnd())
     return false;
 
   //  Disallow lazy parsing for blocks which have before/after in their selector
diff --git a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h
index 6d94c4d..ed144eaa 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingState.h
@@ -14,7 +14,7 @@
 namespace blink {
 
 class CSSLazyPropertyParserImpl;
-class CSSParserTokenRange;
+class CSSParserTokenStream;
 
 // This class helps lazy parsing by retaining necessary state. It should not
 // outlive the StyleSheetContents that initiated the parse, as it retains a raw
@@ -23,7 +23,6 @@
     : public GarbageCollectedFinalized<CSSLazyParsingState> {
  public:
   CSSLazyParsingState(const CSSParserContext*,
-                      Vector<String> escaped_strings,
                       const String& sheet_text,
                       StyleSheetContents*);
 
@@ -32,14 +31,15 @@
   void FinishInitialParsing();
 
   // Helper method used to bump total_style_rules_.
-  CSSLazyPropertyParserImpl* CreateLazyParser(const CSSParserTokenRange& block);
+  CSSLazyPropertyParserImpl* CreateLazyParser(size_t offset);
 
   const CSSParserContext* Context();
+  const String& SheetText() const { return sheet_text_; }
 
   void CountRuleParsed();
 
   bool ShouldLazilyParseProperties(const CSSSelectorList&,
-                                   const CSSParserTokenRange& block) const;
+                                   const CSSParserTokenStream& block) const;
 
   DECLARE_TRACE();
 
@@ -62,7 +62,6 @@
   void RecordUsageMetrics();
 
   Member<const CSSParserContext> context_;
-  Vector<String> escaped_strings_;
   // Also referenced on the css resource.
   String sheet_text_;
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingTest.cpp b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingTest.cpp
index d5891e1..19cfc2e 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSLazyParsingTest.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSLazyParsingTest.cpp
@@ -51,7 +51,7 @@
   CSSParserContext* context = CSSParserContext::Create(kHTMLStandardMode);
   StyleSheetContents* style_sheet = StyleSheetContents::Create(context);
 
-  String sheet_text = "body {  }";
+  String sheet_text = "body {}";
   CSSParser::ParseSheet(context, style_sheet, sheet_text,
                         true /* lazy parse */);
   StyleRule* rule = RuleAt(style_sheet, 0);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.cpp b/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.cpp
index 2719adcd..1d00dfb4 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.cpp
@@ -9,19 +9,14 @@
 
 namespace blink {
 
-CSSLazyPropertyParserImpl::CSSLazyPropertyParserImpl(CSSParserTokenRange block,
+CSSLazyPropertyParserImpl::CSSLazyPropertyParserImpl(size_t offset,
                                                      CSSLazyParsingState* state)
-    : CSSLazyPropertyParser(), lazy_state_(state) {
-  // Reserve capacity to minimize heap bloat.
-  size_t length = block.end() - block.begin();
-  tokens_.ReserveCapacity(length);
-  tokens_.Append(block.begin(), length);
-}
+    : CSSLazyPropertyParser(), offset_(offset), lazy_state_(state) {}
 
 StylePropertySet* CSSLazyPropertyParserImpl::ParseProperties() {
   lazy_state_->CountRuleParsed();
   return CSSParserImpl::ParseDeclarationListForLazyStyle(
-      tokens_, lazy_state_->Context());
+      lazy_state_->SheetText(), offset_, lazy_state_->Context());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h b/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h
index 617ced96..e9d3962 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSLazyPropertyParserImpl.h
@@ -17,7 +17,7 @@
 // This class is responsible for lazily parsing a single CSS declaration list.
 class CSSLazyPropertyParserImpl : public CSSLazyPropertyParser {
  public:
-  CSSLazyPropertyParserImpl(CSSParserTokenRange block, CSSLazyParsingState*);
+  CSSLazyPropertyParserImpl(size_t offset, CSSLazyParsingState*);
 
   // CSSLazyPropertyParser:
   StylePropertySet* ParseProperties() override;
@@ -28,7 +28,7 @@
   }
 
  private:
-  Vector<CSSParserToken> tokens_;
+  size_t offset_;
   Member<CSSLazyParsingState> lazy_state_;
 };
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
index 6706fdf..326d0a9 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
@@ -56,9 +56,8 @@
   else if (declaration->CssParserMode() == kCSSFontFaceRuleMode)
     rule_type = StyleRule::kFontFace;
   CSSTokenizer tokenizer(string);
-  CSSParserTokenStream stream(tokenizer);
   // TODO(shend): Use streams instead of ranges
-  parser.ConsumeDeclarationValue(stream.MakeRangeToEOF(), unresolved_property,
+  parser.ConsumeDeclarationValue(tokenizer.TokenRange(), unresolved_property,
                                  important, rule_type);
   bool did_parse = false;
   bool did_change = false;
@@ -79,9 +78,8 @@
     bool is_animation_tainted) {
   CSSParserImpl parser(context);
   CSSTokenizer tokenizer(value);
-  CSSParserTokenStream stream(tokenizer);
   // TODO(shend): Use streams instead of ranges
-  const CSSParserTokenRange range = stream.MakeRangeToEOF();
+  const CSSParserTokenRange range = tokenizer.TokenRange();
   parser.ConsumeVariableValue(range, property_name, important,
                               is_animation_tainted);
   bool did_parse = false;
@@ -206,20 +204,18 @@
   CSSParserImpl parser(context, style_sheet);
   CSSTokenizer tokenizer(string);
   CSSParserTokenStream stream(tokenizer);
-  // TODO(shend): Use streams instead of ranges
-  CSSParserTokenRange range = stream.MakeRangeToEOF();
-  range.ConsumeWhitespace();
-  if (range.AtEnd())
+  stream.ConsumeWhitespace();
+  if (stream.AtEnd())
     return nullptr;  // Parse error, empty rule
   StyleRuleBase* rule;
-  if (range.Peek().GetType() == kAtKeywordToken)
-    rule = parser.ConsumeAtRule(range, allowed_rules);
+  if (stream.Peek().GetType() == kAtKeywordToken)
+    rule = parser.ConsumeAtRule(stream, allowed_rules);
   else
-    rule = parser.ConsumeQualifiedRule(range, allowed_rules);
+    rule = parser.ConsumeQualifiedRule(stream, allowed_rules);
   if (!rule)
     return nullptr;  // Parse error, failed to consume rule
-  range.ConsumeWhitespace();
-  if (!rule || !range.AtEnd())
+  stream.ConsumeWhitespace();
+  if (!rule || !stream.AtEnd())
     return nullptr;  // Parse error, trailing garbage
   return rule;
 }
@@ -236,17 +232,13 @@
                      "CSSParserImpl::parseStyleSheet.parse");
   CSSTokenizer tokenizer(string);
   CSSParserTokenStream stream(tokenizer);
-  // TODO(shend): Use streams instead of ranges. Streams will ruin
-  // tokenize/parse metrics as we will be tokenizing on demand.
-  const CSSParserTokenRange range = stream.MakeRangeToEOF();
-
   CSSParserImpl parser(context, style_sheet);
   if (defer_property_parsing) {
-    parser.lazy_state_ = new CSSLazyParsingState(
-        context, tokenizer.TakeEscapedStrings(), string, parser.style_sheet_);
+    parser.lazy_state_ =
+        new CSSLazyParsingState(context, string, parser.style_sheet_);
   }
   bool first_rule_valid = parser.ConsumeRuleList(
-      range, kTopLevelRuleList, [&style_sheet](StyleRuleBase* rule) {
+      stream, kTopLevelRuleList, [&style_sheet](StyleRuleBase* rule) {
         if (rule->IsCharsetRule())
           return;
         style_sheet->ParserAppendRule(rule);
@@ -318,24 +310,55 @@
   if (!range.AtEnd())
     return nullptr;
   CSSParserImpl parser(StrictCSSParserContext());
-  parser.ConsumeDeclarationList(block, StyleRule::kStyle);
-
-  // Drop nested @apply rules. Seems nicer to do this here instead of making
-  // a different StyleRule type
-  for (size_t i = parser.parsed_properties_.size(); i--;) {
-    if (parser.parsed_properties_[i].Id() == CSSPropertyApplyAtRule)
-      parser.parsed_properties_.erase(i);
-  }
+  parser.ConsumeDeclarationListForAtApply(block);
 
   return CreateStylePropertySet(parser.parsed_properties_, kHTMLStandardMode);
 }
 
+void CSSParserImpl::ConsumeDeclarationListForAtApply(
+    CSSParserTokenRange range) {
+  DCHECK(parsed_properties_.IsEmpty());
+  DCHECK(RuntimeEnabledFeatures::CSSApplyAtRulesEnabled());
+  DCHECK(!observer_wrapper_);
+
+  while (!range.AtEnd()) {
+    switch (range.Peek().GetType()) {
+      case kWhitespaceToken:
+      case kSemicolonToken:
+        range.Consume();
+        break;
+      case kIdentToken: {
+        const CSSParserToken* declaration_start = &range.Peek();
+
+        while (!range.AtEnd() && range.Peek().GetType() != kSemicolonToken)
+          range.ConsumeComponentValue();
+
+        ConsumeDeclaration(range.MakeSubRange(declaration_start, &range.Peek()),
+                           StyleRule::kStyle);
+
+        break;
+      }
+      case kAtKeywordToken: {
+        range.Consume();
+        while (!range.AtEnd() && range.Peek().GetType() != kLeftBraceToken &&
+               range.Peek().GetType() != kSemicolonToken)
+          range.ConsumeComponentValue();
+        range.ConsumeComponentValue();
+        break;
+      }
+      default:  // Parse error, unexpected token in declaration list
+        while (!range.AtEnd() && range.Peek().GetType() != kSemicolonToken)
+          range.ConsumeComponentValue();
+        break;
+    }
+  }
+}
+
 std::unique_ptr<Vector<double>> CSSParserImpl::ParseKeyframeKeyList(
     const String& key_list) {
   CSSTokenizer tokenizer(key_list);
   // TODO(shend): Use streams instead of ranges
-  return ConsumeKeyframeKeyList(
-      CSSParserTokenStream(tokenizer).MakeRangeToEOF());
+  return ConsumeKeyframeKeyList(tokenizer.TokenRange());
 }
 
 bool CSSParserImpl::SupportsDeclaration(CSSParserTokenRange& range) {
@@ -368,22 +391,25 @@
   CSSParserObserverWrapper wrapper(observer);
   parser.observer_wrapper_ = &wrapper;
   CSSTokenizer tokenizer(string, wrapper);
-  // TODO(shend): Use streams instead of ranges
-  bool first_rule_valid =
-      parser.ConsumeRuleList(tokenizer.TokenRange(), kTopLevelRuleList,
-                             [&style_sheet](StyleRuleBase* rule) {
-                               if (rule->IsCharsetRule())
-                                 return;
-                               style_sheet->ParserAppendRule(rule);
-                             });
+  CSSParserTokenStream stream(tokenizer);
+  bool first_rule_valid = parser.ConsumeRuleList(
+      stream, kTopLevelRuleList, [&style_sheet](StyleRuleBase* rule) {
+        if (rule->IsCharsetRule())
+          return;
+        style_sheet->ParserAppendRule(rule);
+      });
   style_sheet->SetHasSyntacticallyValidCSSHeader(first_rule_valid);
 }
 
 StylePropertySet* CSSParserImpl::ParseDeclarationListForLazyStyle(
-    CSSParserTokenRange block,
+    const String& string,
+    size_t offset,
     const CSSParserContext* context) {
+  CSSTokenizer tokenizer(string, offset);
+  CSSParserTokenStream stream(tokenizer);
+  CSSParserTokenStream::BlockGuard guard(stream);
   CSSParserImpl parser(context);
-  parser.ConsumeDeclarationList(std::move(block), StyleRule::kStyle);
+  parser.ConsumeDeclarationList(stream, StyleRule::kStyle);
   return CreateStylePropertySet(parser.parsed_properties_, context->Mode());
 }
 
@@ -402,7 +428,7 @@
 }
 
 template <typename T>
-bool CSSParserImpl::ConsumeRuleList(CSSParserTokenRange range,
+bool CSSParserImpl::ConsumeRuleList(CSSParserTokenStream& stream,
                                     RuleListType rule_list_type,
                                     const T callback) {
   AllowedRulesType allowed_rules = kRegularRules;
@@ -422,24 +448,24 @@
 
   bool seen_rule = false;
   bool first_rule_valid = false;
-  while (!range.AtEnd()) {
+  while (!stream.AtEnd()) {
     StyleRuleBase* rule;
-    switch (range.Peek().GetType()) {
+    switch (stream.UncheckedPeek().GetType()) {
       case kWhitespaceToken:
-        range.ConsumeWhitespace();
+        stream.ConsumeWhitespace();
         continue;
       case kAtKeywordToken:
-        rule = ConsumeAtRule(range, allowed_rules);
+        rule = ConsumeAtRule(stream, allowed_rules);
         break;
       case kCDOToken:
       case kCDCToken:
         if (rule_list_type == kTopLevelRuleList) {
-          range.Consume();
+          stream.UncheckedConsume();
           continue;
         }
       // fallthrough
       default:
-        rule = ConsumeQualifiedRule(range, allowed_rules);
+        rule = ConsumeQualifiedRule(stream, allowed_rules);
         break;
     }
     if (!seen_rule) {
@@ -487,9 +513,6 @@
     return nullptr;  // Parse error, unrecognised at-rule without block
   }
 
-  // TODO(shend): Use streams instead of ranges
-  CSSParserTokenRange range = stream.MakeRangeToEOF();
-  CSSParserTokenRange block = range.ConsumeBlock();
   CSSParserTokenStream::BlockGuard guard(stream);
 
   if (allowed_rules == kKeyframeRules)
@@ -502,101 +525,42 @@
 
   switch (id) {
     case kCSSAtRuleMedia:
-      return ConsumeMediaRule(prelude, block);
+      return ConsumeMediaRule(prelude, stream);
     case kCSSAtRuleSupports:
-      return ConsumeSupportsRule(prelude, block);
+      return ConsumeSupportsRule(prelude, stream);
     case kCSSAtRuleViewport:
-      return ConsumeViewportRule(prelude, block);
+      return ConsumeViewportRule(prelude, stream);
     case kCSSAtRuleFontFace:
       return ConsumeFontFaceRule(prelude, stream);
     case kCSSAtRuleWebkitKeyframes:
-      return ConsumeKeyframesRule(true, prelude, block);
+      return ConsumeKeyframesRule(true, prelude, stream);
     case kCSSAtRuleKeyframes:
-      return ConsumeKeyframesRule(false, prelude, block);
+      return ConsumeKeyframesRule(false, prelude, stream);
     case kCSSAtRulePage:
-      return ConsumePageRule(prelude, block);
-    default:
-      return nullptr;  // Parse error, unrecognised at-rule with block
-  }
-}
-
-StyleRuleBase* CSSParserImpl::ConsumeAtRule(CSSParserTokenRange& range,
-                                            AllowedRulesType allowed_rules) {
-  DCHECK_EQ(range.Peek().GetType(), kAtKeywordToken);
-  const StringView name = range.ConsumeIncludingWhitespace().Value();
-  const CSSParserToken* prelude_start = &range.Peek();
-  while (!range.AtEnd() && range.Peek().GetType() != kLeftBraceToken &&
-         range.Peek().GetType() != kSemicolonToken)
-    range.ConsumeComponentValue();
-
-  CSSParserTokenRange prelude =
-      range.MakeSubRange(prelude_start, &range.Peek());
-  CSSAtRuleID id = CssAtRuleID(name);
-  if (id != kCSSAtRuleInvalid && context_->IsUseCounterRecordingEnabled())
-    CountAtRule(context_, id);
-
-  if (range.AtEnd() || range.Peek().GetType() == kSemicolonToken) {
-    range.Consume();
-    if (allowed_rules == kAllowCharsetRules && id == kCSSAtRuleCharset)
-      return ConsumeCharsetRule(prelude);
-    if (allowed_rules <= kAllowImportRules && id == kCSSAtRuleImport)
-      return ConsumeImportRule(prelude);
-    if (allowed_rules <= kAllowNamespaceRules && id == kCSSAtRuleNamespace)
-      return ConsumeNamespaceRule(prelude);
-    if (allowed_rules == kApplyRules && id == kCSSAtRuleApply) {
-      ConsumeApplyRule(prelude);
-      return nullptr;  // ConsumeApplyRule just updates parsed_properties_
-    }
-    return nullptr;  // Parse error, unrecognised at-rule without block
-  }
-
-  CSSParserTokenRange block = range.ConsumeBlock();
-  if (allowed_rules == kKeyframeRules)
-    return nullptr;  // Parse error, no at-rules supported inside @keyframes
-  if (allowed_rules == kNoRules || allowed_rules == kApplyRules)
-    return nullptr;  // Parse error, no at-rules with blocks supported inside
-                     // declaration lists
-
-  DCHECK_LE(allowed_rules, kRegularRules);
-
-  switch (id) {
-    case kCSSAtRuleMedia:
-      return ConsumeMediaRule(prelude, block);
-    case kCSSAtRuleSupports:
-      return ConsumeSupportsRule(prelude, block);
-    case kCSSAtRuleViewport:
-      return ConsumeViewportRule(prelude, block);
-    case kCSSAtRuleFontFace:
-      return ConsumeFontFaceRule(prelude, block);
-    case kCSSAtRuleWebkitKeyframes:
-      return ConsumeKeyframesRule(true, prelude, block);
-    case kCSSAtRuleKeyframes:
-      return ConsumeKeyframesRule(false, prelude, block);
-    case kCSSAtRulePage:
-      return ConsumePageRule(prelude, block);
+      return ConsumePageRule(prelude, stream);
     default:
       return nullptr;  // Parse error, unrecognised at-rule with block
   }
 }
 
 StyleRuleBase* CSSParserImpl::ConsumeQualifiedRule(
-    CSSParserTokenRange& range,
+    CSSParserTokenStream& stream,
     AllowedRulesType allowed_rules) {
-  const CSSParserToken* prelude_start = &range.Peek();
-  while (!range.AtEnd() && range.Peek().GetType() != kLeftBraceToken)
-    range.ConsumeComponentValue();
+  const auto prelude_start = stream.Position();
+  while (!stream.AtEnd() && stream.UncheckedPeek().GetType() != kLeftBraceToken)
+    stream.UncheckedConsumeComponentValue();
 
-  if (range.AtEnd())
+  if (stream.AtEnd())
     return nullptr;  // Parse error, EOF instead of qualified rule block
 
   CSSParserTokenRange prelude =
-      range.MakeSubRange(prelude_start, &range.Peek());
-  CSSParserTokenRange block = range.ConsumeBlock();
+      stream.MakeSubRange(prelude_start, stream.Position());
+  CSSParserTokenStream::BlockGuard guard(stream);
 
   if (allowed_rules <= kRegularRules)
-    return ConsumeStyleRule(prelude, block);
+    return ConsumeStyleRule(prelude, stream);
   if (allowed_rules == kKeyframeRules)
-    return ConsumeKeyframeStyleRule(prelude, block);
+    return ConsumeKeyframeStyleRule(prelude, stream);
 
   NOTREACHED();
   return nullptr;
@@ -662,7 +626,7 @@
 }
 
 StyleRuleMedia* CSSParserImpl::ConsumeMediaRule(CSSParserTokenRange prelude,
-                                                CSSParserTokenRange block) {
+                                                CSSParserTokenStream& block) {
   HeapVector<Member<StyleRuleBase>> rules;
 
   if (observer_wrapper_) {
@@ -690,7 +654,7 @@
 
 StyleRuleSupports* CSSParserImpl::ConsumeSupportsRule(
     CSSParserTokenRange prelude,
-    CSSParserTokenRange block) {
+    CSSParserTokenStream& block) {
   CSSSupportsParser::SupportsResult supported =
       CSSSupportsParser::SupportsCondition(prelude, *this,
                                            CSSSupportsParser::kForAtRule);
@@ -720,7 +684,7 @@
 
 StyleRuleViewport* CSSParserImpl::ConsumeViewportRule(
     CSSParserTokenRange prelude,
-    CSSParserTokenRange block) {
+    CSSParserTokenStream& block) {
   // Allow @viewport rules from UA stylesheets even if the feature is disabled.
   if (!RuntimeEnabledFeatures::CSSViewportEnabled() &&
       !IsUASheetBehavior(context_->Mode()))
@@ -769,33 +733,10 @@
       CreateStylePropertySet(parsed_properties_, kCSSFontFaceRuleMode));
 }
 
-StyleRuleFontFace* CSSParserImpl::ConsumeFontFaceRule(
-    CSSParserTokenRange prelude,
-    CSSParserTokenRange block) {
-  if (!prelude.AtEnd())
-    return nullptr;  // Parse error; @font-face prelude should be empty
-
-  if (observer_wrapper_) {
-    unsigned end_offset = observer_wrapper_->EndOffset(prelude);
-    observer_wrapper_->Observer().StartRuleHeader(
-        StyleRule::kFontFace, observer_wrapper_->StartOffset(prelude));
-    observer_wrapper_->Observer().EndRuleHeader(end_offset);
-    observer_wrapper_->Observer().StartRuleBody(end_offset);
-    observer_wrapper_->Observer().EndRuleBody(end_offset);
-  }
-
-  if (style_sheet_)
-    style_sheet_->SetHasFontFaceRule();
-
-  ConsumeDeclarationList(block, StyleRule::kFontFace);
-  return StyleRuleFontFace::Create(
-      CreateStylePropertySet(parsed_properties_, kCSSFontFaceRuleMode));
-}
-
 StyleRuleKeyframes* CSSParserImpl::ConsumeKeyframesRule(
     bool webkit_prefixed,
     CSSParserTokenRange prelude,
-    CSSParserTokenRange block) {
+    CSSParserTokenStream& block) {
   CSSParserTokenRange range_copy = prelude;  // For inspector callbacks
   const CSSParserToken& name_token = prelude.ConsumeIncludingWhitespace();
   if (!prelude.AtEnd())
@@ -834,7 +775,7 @@
 }
 
 StyleRulePage* CSSParserImpl::ConsumePageRule(CSSParserTokenRange prelude,
-                                              CSSParserTokenRange block) {
+                                              CSSParserTokenStream& block) {
   CSSSelectorList selector_list = ParsePageSelector(prelude, style_sheet_);
   if (!selector_list.IsValid())
     return nullptr;  // Parse error, invalid @page selector
@@ -866,7 +807,7 @@
 
 StyleRuleKeyframe* CSSParserImpl::ConsumeKeyframeStyleRule(
     CSSParserTokenRange prelude,
-    CSSParserTokenRange block) {
+    CSSParserTokenStream& block) {
   std::unique_ptr<Vector<double>> key_list = ConsumeKeyframeKeyList(prelude);
   if (!key_list)
     return nullptr;
@@ -908,7 +849,7 @@
 }
 
 StyleRule* CSSParserImpl::ConsumeStyleRule(CSSParserTokenRange prelude,
-                                           CSSParserTokenRange block) {
+                                           CSSParserTokenStream& block) {
   CSSSelectorList selector_list =
       CSSSelectorParser::ParseSelector(prelude, context_, style_sheet_);
   if (!selector_list.IsValid())
@@ -920,8 +861,9 @@
   } else if (lazy_state_ &&
              lazy_state_->ShouldLazilyParseProperties(selector_list, block)) {
     DCHECK(style_sheet_);
-    return StyleRule::CreateLazy(std::move(selector_list),
-                                 lazy_state_->CreateLazyParser(block));
+    return StyleRule::CreateLazy(
+        std::move(selector_list),
+        lazy_state_->CreateLazyParser(block.Offset() - 1));
   }
   ConsumeDeclarationList(block, StyleRule::kStyle);
 
@@ -993,65 +935,6 @@
   }
 }
 
-void CSSParserImpl::ConsumeDeclarationList(CSSParserTokenRange range,
-                                           StyleRule::RuleType rule_type) {
-  DCHECK(parsed_properties_.IsEmpty());
-
-  bool use_observer = observer_wrapper_ && (rule_type == StyleRule::kStyle ||
-                                            rule_type == StyleRule::kKeyframe);
-  if (use_observer) {
-    observer_wrapper_->Observer().StartRuleBody(
-        observer_wrapper_->PreviousTokenStartOffset(range));
-    observer_wrapper_->SkipCommentsBefore(range, true);
-  }
-
-  while (!range.AtEnd()) {
-    switch (range.Peek().GetType()) {
-      case kWhitespaceToken:
-      case kSemicolonToken:
-        range.Consume();
-        break;
-      case kIdentToken: {
-        const CSSParserToken* declaration_start = &range.Peek();
-
-        if (use_observer)
-          observer_wrapper_->YieldCommentsBefore(range);
-
-        while (!range.AtEnd() && range.Peek().GetType() != kSemicolonToken)
-          range.ConsumeComponentValue();
-
-        ConsumeDeclaration(range.MakeSubRange(declaration_start, &range.Peek()),
-                           rule_type);
-
-        if (use_observer)
-          observer_wrapper_->SkipCommentsBefore(range, false);
-        break;
-      }
-      case kAtKeywordToken: {
-        AllowedRulesType allowed_rules =
-            rule_type == StyleRule::kStyle &&
-                    RuntimeEnabledFeatures::CSSApplyAtRulesEnabled()
-                ? kApplyRules
-                : kNoRules;
-        StyleRuleBase* rule = ConsumeAtRule(range, allowed_rules);
-        DCHECK(!rule);
-        break;
-      }
-      default:  // Parse error, unexpected token in declaration list
-        while (!range.AtEnd() && range.Peek().GetType() != kSemicolonToken)
-          range.ConsumeComponentValue();
-        break;
-    }
-  }
-
-  // Yield remaining comments
-  if (use_observer) {
-    observer_wrapper_->YieldCommentsBefore(range);
-    observer_wrapper_->Observer().EndRuleBody(
-        observer_wrapper_->EndOffset(range));
-  }
-}
-
 void CSSParserImpl::ConsumeDeclaration(CSSParserTokenRange range,
                                        StyleRule::RuleType rule_type) {
   CSSParserTokenRange range_copy = range;  // For inspector callbacks
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
index f7499de..9d22c4c78 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
@@ -89,6 +89,10 @@
                                            StyleSheetContents*);
 
   static ImmutableStylePropertySet* ParseCustomPropertySet(CSSParserTokenRange);
+  // TODO(shend): Remove this when crbug.com/661854 is fixed. We need to use a
+  // stream for parsing @apply blocks so we can correctly store custom
+  // property values.
+  void ConsumeDeclarationListForAtApply(CSSParserTokenRange);
 
   static std::unique_ptr<Vector<double>> ParseKeyframeKeyList(const String&);
 
@@ -103,7 +107,8 @@
                                           CSSParserObserver&);
 
   static StylePropertySet* ParseDeclarationListForLazyStyle(
-      CSSParserTokenRange block,
+      const String&,
+      size_t offset,
       const CSSParserContext*);
 
  private:
@@ -111,44 +116,37 @@
 
   // Returns whether the first encountered rule was valid
   template <typename T>
-  bool ConsumeRuleList(CSSParserTokenRange, RuleListType, T callback);
+  bool ConsumeRuleList(CSSParserTokenStream&, RuleListType, T callback);
 
   // These functions update the range/stream they're given
   StyleRuleBase* ConsumeAtRule(CSSParserTokenStream&, AllowedRulesType);
-  // TODO(shend): Remove this overload once we switch over to streams.
-  StyleRuleBase* ConsumeAtRule(CSSParserTokenRange&, AllowedRulesType);
-  StyleRuleBase* ConsumeQualifiedRule(CSSParserTokenRange&, AllowedRulesType);
+  StyleRuleBase* ConsumeQualifiedRule(CSSParserTokenStream&, AllowedRulesType);
 
   static StyleRuleCharset* ConsumeCharsetRule(CSSParserTokenRange prelude);
   StyleRuleImport* ConsumeImportRule(CSSParserTokenRange prelude);
   StyleRuleNamespace* ConsumeNamespaceRule(CSSParserTokenRange prelude);
   StyleRuleMedia* ConsumeMediaRule(CSSParserTokenRange prelude,
-                                   CSSParserTokenRange block);
+                                   CSSParserTokenStream& block);
   StyleRuleSupports* ConsumeSupportsRule(CSSParserTokenRange prelude,
-                                         CSSParserTokenRange block);
+                                         CSSParserTokenStream& block);
   StyleRuleViewport* ConsumeViewportRule(CSSParserTokenRange prelude,
-                                         CSSParserTokenRange block);
+                                         CSSParserTokenStream& block);
   StyleRuleFontFace* ConsumeFontFaceRule(CSSParserTokenRange prelude,
                                          CSSParserTokenStream& block);
-  // TODO(shend): Remove this overload once we switch over to streams.
-  StyleRuleFontFace* ConsumeFontFaceRule(CSSParserTokenRange prelude,
-                                         CSSParserTokenRange block);
   StyleRuleKeyframes* ConsumeKeyframesRule(bool webkit_prefixed,
                                            CSSParserTokenRange prelude,
-                                           CSSParserTokenRange block);
+                                           CSSParserTokenStream& block);
   StyleRulePage* ConsumePageRule(CSSParserTokenRange prelude,
-                                 CSSParserTokenRange block);
+                                 CSSParserTokenStream& block);
   // Updates parsed_properties_
   void ConsumeApplyRule(CSSParserTokenRange prelude);
 
   StyleRuleKeyframe* ConsumeKeyframeStyleRule(CSSParserTokenRange prelude,
-                                              CSSParserTokenRange block);
+                                              CSSParserTokenStream& block);
   StyleRule* ConsumeStyleRule(CSSParserTokenRange prelude,
-                              CSSParserTokenRange block);
+                              CSSParserTokenStream& block);
 
   void ConsumeDeclarationList(CSSParserTokenStream&, StyleRule::RuleType);
-  // TODO(shend): Remove this overload once we switch over to streams.
-  void ConsumeDeclarationList(CSSParserTokenRange, StyleRule::RuleType);
   void ConsumeDeclaration(CSSParserTokenRange, StyleRule::RuleType);
   void ConsumeDeclarationValue(CSSParserTokenRange,
                                CSSPropertyID,
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index dc54b42..fe08ed1 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -41,20 +41,6 @@
   range_.ConsumeWhitespace();
 }
 
-// AddProperty takes implicit as an enum, below we're using a bool because
-// AddParsedProperty will be removed after we finish implemenation of property
-// APIs.
-void CSSPropertyParser::AddParsedProperty(CSSPropertyID resolved_property,
-                                          CSSPropertyID current_shorthand,
-                                          const CSSValue& value,
-                                          bool important,
-                                          bool implicit) {
-  AddProperty(resolved_property, current_shorthand, value, important,
-              implicit ? IsImplicitProperty::kImplicit
-                       : IsImplicitProperty::kNotImplicit,
-              *parsed_properties_);
-}
-
 bool CSSPropertyParser::ParseValue(
     CSSPropertyID unresolved_property,
     bool important,
@@ -117,8 +103,8 @@
   } else {
     if (const CSSValue* parsed_value = ParseSingleValue(unresolved_property)) {
       if (range_.AtEnd()) {
-        AddParsedProperty(property_id, CSSPropertyInvalid, *parsed_value,
-                          important);
+        AddProperty(property_id, CSSPropertyInvalid, *parsed_value, important,
+                    IsImplicitProperty::kNotImplicit, *parsed_properties_);
         return true;
       }
     }
@@ -136,7 +122,8 @@
       AddExpandedPropertyForValue(property_id, pending_value, important,
                                   *parsed_properties_);
     } else {
-      AddParsedProperty(property_id, CSSPropertyInvalid, *variable, important);
+      AddProperty(property_id, CSSPropertyInvalid, *variable, important,
+                  IsImplicitProperty::kNotImplicit, *parsed_properties_);
     }
     return true;
   }
@@ -239,7 +226,8 @@
   if (!shorthand.length()) {
     if (!CSSPropertyAPI::Get(property).IsProperty())
       return false;
-    AddParsedProperty(property, CSSPropertyInvalid, *value, important);
+    AddProperty(property, CSSPropertyInvalid, *value, important,
+                IsImplicitProperty::kNotImplicit, *parsed_properties_);
   } else {
     AddExpandedPropertyForValue(property, *value, important,
                                 *parsed_properties_);
@@ -410,7 +398,8 @@
   if (!parsed_value || !range_.AtEnd())
     return false;
 
-  AddParsedProperty(prop_id, CSSPropertyInvalid, *parsed_value, false);
+  AddProperty(prop_id, CSSPropertyInvalid, *parsed_value, false,
+              IsImplicitProperty::kNotImplicit, *parsed_properties_);
   return true;
 }
 
@@ -470,10 +459,12 @@
       }
       if (!max_width || !range_.AtEnd())
         return false;
-      AddParsedProperty(CSSPropertyMinWidth, CSSPropertyInvalid, *min_width,
-                        important);
-      AddParsedProperty(CSSPropertyMaxWidth, CSSPropertyInvalid, *max_width,
-                        important);
+      AddProperty(CSSPropertyMinWidth, CSSPropertyInvalid, *min_width,
+                  important, IsImplicitProperty::kNotImplicit,
+                  *parsed_properties_);
+      AddProperty(CSSPropertyMaxWidth, CSSPropertyInvalid, *max_width,
+                  important, IsImplicitProperty::kNotImplicit,
+                  *parsed_properties_);
       return true;
     }
     case CSSPropertyHeight: {
@@ -488,10 +479,12 @@
       }
       if (!max_height || !range_.AtEnd())
         return false;
-      AddParsedProperty(CSSPropertyMinHeight, CSSPropertyInvalid, *min_height,
-                        important);
-      AddParsedProperty(CSSPropertyMaxHeight, CSSPropertyInvalid, *max_height,
-                        important);
+      AddProperty(CSSPropertyMinHeight, CSSPropertyInvalid, *min_height,
+                  important, IsImplicitProperty::kNotImplicit,
+                  *parsed_properties_);
+      AddProperty(CSSPropertyMaxHeight, CSSPropertyInvalid, *max_height,
+                  important, IsImplicitProperty::kNotImplicit,
+                  *parsed_properties_);
       return true;
     }
     case CSSPropertyMinWidth:
@@ -507,7 +500,8 @@
           ConsumeSingleViewportDescriptor(range_, prop_id, context_->Mode());
       if (!parsed_value || !range_.AtEnd())
         return false;
-      AddParsedProperty(prop_id, CSSPropertyInvalid, *parsed_value, important);
+      AddProperty(prop_id, CSSPropertyInvalid, *parsed_value, important,
+                  IsImplicitProperty::kNotImplicit, *parsed_properties_);
       return true;
     }
     default:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index 94e178c3..6a32b8a 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -71,11 +71,6 @@
   bool ParseViewportDescriptor(CSSPropertyID prop_id, bool important);
   bool ParseFontFaceDescriptor(CSSPropertyID);
 
-  void AddParsedProperty(CSSPropertyID resolved_property,
-                         CSSPropertyID current_shorthand,
-                         const CSSValue&,
-                         bool important,
-                         bool implicit = false);
   bool ParseShorthand(CSSPropertyID, bool important);
  private:
   // Inputs:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp
index 2475d33..16241a9 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.cpp
@@ -16,7 +16,8 @@
 
 namespace blink {
 
-CSSTokenizer::CSSTokenizer(const String& string) : input_(string) {
+CSSTokenizer::CSSTokenizer(const String& string, size_t offset)
+    : input_(string) {
   // According to the spec, we should perform preprocessing here.
   // See: http://dev.w3.org/csswg/css-syntax/#input-preprocessing
   //
@@ -29,9 +30,11 @@
   if (string.IsEmpty())
     return;
 
+  input_.Advance(offset);
+
   // To avoid resizing we err on the side of reserving too much space.
   // Most strings we tokenize have about 3.5 to 5 characters per token.
-  tokens_.ReserveInitialCapacity(string.length() / 3);
+  tokens_.ReserveInitialCapacity((string.length() - offset) / 3);
 }
 
 CSSTokenizer::CSSTokenizer(const String& string,
diff --git a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.h b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.h
index f2ccc11..48149e7 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSTokenizer.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSTokenizer.h
@@ -26,14 +26,12 @@
   DISALLOW_NEW();
 
  public:
-  CSSTokenizer(const String&);
+  CSSTokenizer(const String&, size_t offset = 0);
   CSSTokenizer(const String&, CSSParserObserverWrapper&);  // For the inspector
 
   CSSParserTokenRange TokenRange();
   unsigned TokenCount();
 
-  Vector<String> TakeEscapedStrings() { return std::move(string_pool_); }
-
  private:
   CSSParserToken TokenizeSingle();
   void EnsureTokenizedToEOF();
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextEmphasisPosition.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextEmphasisPosition.cpp
deleted file mode 100644
index 146d7f1..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextEmphasisPosition.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/css/properties/CSSPropertyAPITextEmphasisPosition.h"
-
-#include "core/css/CSSIdentifierValue.h"
-#include "core/css/CSSValueList.h"
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-
-class CSSParserLocalContext;
-namespace blink {
-
-// [ over | under ] && [ right | left ]?
-// If [ right | left ] is omitted, it defaults to right.
-const CSSValue* CSSPropertyAPITextEmphasisPosition::ParseSingleValue(
-    CSSPropertyID,
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    const CSSParserLocalContext&) const {
-  CSSIdentifierValue* values[2] = {
-      CSSPropertyParserHelpers::ConsumeIdent<CSSValueOver, CSSValueUnder,
-                                             CSSValueRight, CSSValueLeft>(
-          range),
-      nullptr};
-  if (!values[0])
-    return nullptr;
-  values[1] = CSSPropertyParserHelpers::ConsumeIdent<
-      CSSValueOver, CSSValueUnder, CSSValueRight, CSSValueLeft>(range);
-  CSSIdentifierValue* over_under = nullptr;
-  CSSIdentifierValue* left_right = nullptr;
-
-  for (auto value : values) {
-    if (!value)
-      break;
-    switch (value->GetValueID()) {
-      case CSSValueOver:
-      case CSSValueUnder:
-        if (over_under)
-          return nullptr;
-        over_under = value;
-        break;
-      case CSSValueLeft:
-      case CSSValueRight:
-        if (left_right)
-          return nullptr;
-        left_right = value;
-        break;
-      default:
-        NOTREACHED();
-        break;
-    }
-  }
-  if (!over_under)
-    return nullptr;
-  if (!left_right)
-    left_right = CSSIdentifierValue::Create(CSSValueRight);
-  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
-  list->Append(*over_under);
-  list->Append(*left_right);
-  return list;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisPosition.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisPosition.cpp
new file mode 100644
index 0000000..2049174
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisPosition.cpp
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPIWebkitTextEmphasisPosition.h"
+
+#include "core/css/CSSIdentifierValue.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+
+class CSSParserLocalContext;
+namespace blink {
+
+// [ over | under ] && [ right | left ]?
+// If [ right | left ] is omitted, it defaults to right.
+const CSSValue* CSSPropertyAPIWebkitTextEmphasisPosition::ParseSingleValue(
+    CSSPropertyID,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) const {
+  CSSIdentifierValue* values[2] = {
+      CSSPropertyParserHelpers::ConsumeIdent<CSSValueOver, CSSValueUnder,
+                                             CSSValueRight, CSSValueLeft>(
+          range),
+      nullptr};
+  if (!values[0])
+    return nullptr;
+  values[1] = CSSPropertyParserHelpers::ConsumeIdent<
+      CSSValueOver, CSSValueUnder, CSSValueRight, CSSValueLeft>(range);
+  CSSIdentifierValue* over_under = nullptr;
+  CSSIdentifierValue* left_right = nullptr;
+
+  for (auto value : values) {
+    if (!value)
+      break;
+    switch (value->GetValueID()) {
+      case CSSValueOver:
+      case CSSValueUnder:
+        if (over_under)
+          return nullptr;
+        over_under = value;
+        break;
+      case CSSValueLeft:
+      case CSSValueRight:
+        if (left_right)
+          return nullptr;
+        left_right = value;
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+  if (!over_under)
+    return nullptr;
+  if (!left_right)
+    left_right = CSSIdentifierValue::Create(CSSValueRight);
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  list->Append(*over_under);
+  list->Append(*left_right);
+  return list;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIGrid.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIGrid.cpp
index a44334c5..cad070e 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIGrid.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIGrid.cpp
@@ -46,7 +46,7 @@
     const CSSParserLocalContext&,
     HeapVector<CSSProperty, 256>& properties) const {
   DCHECK(RuntimeEnabledFeatures::CSSGridLayoutEnabled());
-  DCHECK_EQ(shorthandForProperty(CSSPropertyGrid).length(), 8u);
+  DCHECK_EQ(shorthandForProperty(CSSPropertyGrid).length(), 6u);
 
   CSSParserTokenRange range_copy = range;
 
@@ -88,14 +88,6 @@
         CSSPropertyGridAutoRows, CSSPropertyGrid, *CSSInitialValue::Create(),
         important, CSSPropertyParserHelpers::IsImplicitProperty::kNotImplicit,
         properties);
-    CSSPropertyParserHelpers::AddProperty(
-        CSSPropertyGridColumnGap, CSSPropertyGrid, *CSSInitialValue::Create(),
-        important, CSSPropertyParserHelpers::IsImplicitProperty::kNotImplicit,
-        properties);
-    CSSPropertyParserHelpers::AddProperty(
-        CSSPropertyGridRowGap, CSSPropertyGrid, *CSSInitialValue::Create(),
-        important, CSSPropertyParserHelpers::IsImplicitProperty::kNotImplicit,
-        properties);
     return true;
   }
 
@@ -181,14 +173,6 @@
   CSSPropertyParserHelpers::AddProperty(
       CSSPropertyGridAutoRows, CSSPropertyGrid, *auto_rows_value, important,
       CSSPropertyParserHelpers::IsImplicitProperty::kNotImplicit, properties);
-  CSSPropertyParserHelpers::AddProperty(
-      CSSPropertyGridColumnGap, CSSPropertyGrid, *CSSInitialValue::Create(),
-      important, CSSPropertyParserHelpers::IsImplicitProperty::kNotImplicit,
-      properties);
-  CSSPropertyParserHelpers::AddProperty(
-      CSSPropertyGridRowGap, CSSPropertyGrid, *CSSInitialValue::Create(),
-      important, CSSPropertyParserHelpers::IsImplicitProperty::kNotImplicit,
-      properties);
   return true;
 }
 
diff --git a/third_party/WebKit/Source/core/dom/BUILD.gn b/third_party/WebKit/Source/core/dom/BUILD.gn
index cbaf0d3..4c91cde 100644
--- a/third_party/WebKit/Source/core/dom/BUILD.gn
+++ b/third_party/WebKit/Source/core/dom/BUILD.gn
@@ -87,6 +87,8 @@
     "DocumentInit.h",
     "DocumentLifecycle.cpp",
     "DocumentLifecycle.h",
+    "DocumentModulatorImpl.cpp",
+    "DocumentModulatorImpl.h",
     "DocumentOrShadowRoot.h",
     "DocumentParser.cpp",
     "DocumentParser.h",
@@ -160,8 +162,8 @@
     "MessagePort.h",
     "Modulator.cpp",
     "Modulator.h",
-    "ModulatorImpl.cpp",
-    "ModulatorImpl.h",
+    "ModulatorImplBase.cpp",
+    "ModulatorImplBase.h",
     "ModuleMap.cpp",
     "ModuleMap.h",
     "ModulePendingScript.cpp",
@@ -250,7 +252,6 @@
     "ShadowRoot.cpp",
     "ShadowRoot.h",
     "ShadowRootRareDataV0.h",
-    "SimulatedClickOptions.h",
     "SinkDocument.cpp",
     "SinkDocument.h",
     "SlotAssignment.cpp",
@@ -280,10 +281,6 @@
     "TextLinkColors.cpp",
     "TextLinkColors.h",
     "ThrowOnDynamicMarkupInsertionCountIncrementer.h",
-    "Touch.cpp",
-    "Touch.h",
-    "TouchList.cpp",
-    "TouchList.h",
     "TransformSource.h",
     "TransformSourceLibxslt.cpp",
     "TreeOrderedList.cpp",
@@ -309,6 +306,8 @@
     "WeakIdentifierMap.h",
     "WhitespaceAttacher.cpp",
     "WhitespaceAttacher.h",
+    "WorkletModulatorImpl.cpp",
+    "WorkletModulatorImpl.h",
     "XMLDocument.cpp",
     "XMLDocument.h",
     "events/AddEventListenerOptionsDefaults.h",
@@ -339,6 +338,7 @@
     "events/NodeEventContext.h",
     "events/ScopedEventQueue.cpp",
     "events/ScopedEventQueue.h",
+    "events/SimulatedClickOptions.h",
     "events/TreeScopeEventContext.cpp",
     "events/TreeScopeEventContext.h",
     "events/WindowEventContext.cpp",
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 1f6233f..742ed820 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -33,13 +33,13 @@
 
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/HTMLScriptElementOrSVGScriptElement.h"
 #include "bindings/core/v8/ScriptController.h"
 #include "bindings/core/v8/SourceLocation.h"
-#include "bindings/core/v8/StringOrDictionary.h"
 #include "bindings/core/v8/V0CustomElementConstructorBuilder.h"
 #include "bindings/core/v8/V8ElementCreationOptions.h"
 #include "bindings/core/v8/WindowProxy.h"
+#include "bindings/core/v8/html_script_element_or_svg_script_element.h"
+#include "bindings/core/v8/string_or_dictionary.h"
 #include "core/HTMLElementFactory.h"
 #include "core/HTMLElementTypeHelpers.h"
 #include "core/HTMLNames.h"
@@ -104,7 +104,6 @@
 #include "core/dom/ShadowRoot.h"
 #include "core/dom/StaticNodeList.h"
 #include "core/dom/TaskRunnerHelper.h"
-#include "core/dom/TouchList.h"
 #include "core/dom/TransformSource.h"
 #include "core/dom/TreeWalker.h"
 #include "core/dom/VisitedLinkState.h"
@@ -177,6 +176,7 @@
 #include "core/html/parser/NestingLevelIncrementer.h"
 #include "core/html/parser/TextResourceDecoder.h"
 #include "core/input/EventHandler.h"
+#include "core/input/TouchList.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/inspector/InspectorTraceEvents.h"
 #include "core/inspector/MainThreadDebugger.h"
@@ -574,6 +574,7 @@
       // pointer?
       dom_window_(frame_ ? frame_->DomWindow() : nullptr),
       imports_controller_(initializer.ImportsController()),
+      context_document_(initializer.ContextDocument()),
       context_features_(ContextFeatures::DefaultSwitch()),
       well_formed_(false),
       printing_(kNotPrinting),
@@ -620,7 +621,6 @@
       is_srcdoc_document_(initializer.ShouldTreatURLAsSrcdocDocument()),
       is_mobile_document_(false),
       layout_view_(0),
-      context_document_(initializer.ContextDocument()),
       has_fullscreen_supplement_(false),
       load_event_delay_count_(0),
       load_event_delay_timer_(
@@ -3461,7 +3461,10 @@
     return true;
   if (frame_->HasReceivedUserGesture())
     return true;
-  return ElapsedTime() >= kElapsedTimeForHistoryEntryWithoutUserGestureMS;
+  if (ElapsedTime() >= kElapsedTimeForHistoryEntryWithoutUserGestureMS)
+    return true;
+  UseCounter::Count(*this, WebFeature::kSuppressHistoryEntryWithoutUserGesture);
+  return false;
 }
 
 void Document::write(const SegmentedString& text,
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 992aa95..3f8e510 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -1498,6 +1498,10 @@
   Member<LocalDOMWindow> dom_window_;
   TraceWrapperMember<HTMLImportsController> imports_controller_;
 
+  // The document of creator browsing context for frame-less documents such as
+  // documents created by DOMParser and DOMImplementation.
+  WeakMember<Document> context_document_;
+
   Member<ResourceFetcher> fetcher_;
   TraceWrapperMember<DocumentParser> parser_;
   Member<ContextFeatures> context_features_;
@@ -1648,10 +1652,6 @@
 
   LayoutView* layout_view_;
 
-  // The document of creator browsing context for frame-less documents such as
-  // documents created by DOMParser and DOMImplementation.
-  WeakMember<Document> context_document_;
-
   // For early return in Fullscreen::fromIfExists()
   bool has_fullscreen_supplement_;
 
diff --git a/third_party/WebKit/Source/core/dom/DocumentModulatorImpl.cpp b/third_party/WebKit/Source/core/dom/DocumentModulatorImpl.cpp
new file mode 100644
index 0000000..dc698e7
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/DocumentModulatorImpl.cpp
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/dom/DocumentModulatorImpl.h"
+
+#include "core/loader/modulescript/DocumentModuleScriptFetcher.h"
+
+namespace blink {
+
+ModulatorImplBase* DocumentModulatorImpl::Create(
+    RefPtr<ScriptState> script_state,
+    ResourceFetcher* resource_fetcher) {
+  return new DocumentModulatorImpl(std::move(script_state), resource_fetcher);
+}
+
+ModuleScriptFetcher* DocumentModulatorImpl::CreateModuleScriptFetcher() {
+  return new DocumentModuleScriptFetcher(fetcher_);
+}
+
+DEFINE_TRACE(DocumentModulatorImpl) {
+  visitor->Trace(fetcher_);
+  ModulatorImplBase::Trace(visitor);
+}
+
+DocumentModulatorImpl::DocumentModulatorImpl(RefPtr<ScriptState> script_state,
+                                             ResourceFetcher* resource_fetcher)
+    : ModulatorImplBase(std::move(script_state)), fetcher_(resource_fetcher) {
+  DCHECK(fetcher_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/DocumentModulatorImpl.h b/third_party/WebKit/Source/core/dom/DocumentModulatorImpl.h
new file mode 100644
index 0000000..4eda192a
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/DocumentModulatorImpl.h
@@ -0,0 +1,38 @@
+// 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 DocumentModulatorImpl_h
+#define DocumentModulatorImpl_h
+
+#include "core/dom/ModulatorImplBase.h"
+
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class ModuleScriptFetcher;
+class ResourceFetcher;
+class ScriptState;
+
+// DocumentModulatorImpl is the Modulator implementation used in main documents
+// (that means, not worker nor worklets). Module operations depending on the
+// Document context should be implemented in this class, not in
+// ModulatorImplBase.
+class DocumentModulatorImpl final : public ModulatorImplBase {
+ public:
+  static ModulatorImplBase* Create(RefPtr<ScriptState>, ResourceFetcher*);
+
+  // Implements Modulator.
+  ModuleScriptFetcher* CreateModuleScriptFetcher() override;
+
+  DECLARE_TRACE();
+
+ private:
+  DocumentModulatorImpl(RefPtr<ScriptState>, ResourceFetcher*);
+  Member<ResourceFetcher> fetcher_;
+};
+
+}  // namespace blink
+
+#endif  // DocumentModulatorImpl_h
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 520ac7e..621db420 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -30,8 +30,8 @@
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/ScrollIntoViewOptionsOrBoolean.h"
 #include "bindings/core/v8/V8DOMActivityLogger.h"
+#include "bindings/core/v8/scroll_into_view_options_or_boolean.h"
 #include "core/CSSValueKeywords.h"
 #include "core/SVGNames.h"
 #include "core/XMLNames.h"
diff --git a/third_party/WebKit/Source/core/dom/MockScriptElementBase.h b/third_party/WebKit/Source/core/dom/MockScriptElementBase.h
index 9c7ccdb..6d3fd9d 100644
--- a/third_party/WebKit/Source/core/dom/MockScriptElementBase.h
+++ b/third_party/WebKit/Source/core/dom/MockScriptElementBase.h
@@ -5,7 +5,7 @@
 #ifndef MockScriptElementBase_h
 #define MockScriptElementBase_h
 
-#include "bindings/core/v8/HTMLScriptElementOrSVGScriptElement.h"
+#include "bindings/core/v8/html_script_element_or_svg_script_element.h"
 #include "core/dom/Document.h"
 #include "core/dom/ScriptElementBase.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/third_party/WebKit/Source/core/dom/Modulator.cpp b/third_party/WebKit/Source/core/dom/Modulator.cpp
index bb35523..ff79f1f 100644
--- a/third_party/WebKit/Source/core/dom/Modulator.cpp
+++ b/third_party/WebKit/Source/core/dom/Modulator.cpp
@@ -6,7 +6,8 @@
 
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "core/dom/Document.h"
-#include "core/dom/ModulatorImpl.h"
+#include "core/dom/DocumentModulatorImpl.h"
+#include "core/dom/WorkletModulatorImpl.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
 #include "core/workers/MainThreadWorkletGlobalScope.h"
@@ -34,7 +35,8 @@
   ExecutionContext* execution_context = ExecutionContext::From(script_state);
   if (execution_context->IsDocument()) {
     Document* document = ToDocument(execution_context);
-    modulator = ModulatorImpl::Create(script_state, document->Fetcher());
+    modulator =
+        DocumentModulatorImpl::Create(script_state, document->Fetcher());
     Modulator::SetModulator(script_state, modulator);
 
     // See comment in LocalDOMWindow::modulator_ for this workaround.
@@ -43,8 +45,7 @@
   } else if (execution_context->IsMainThreadWorkletGlobalScope()) {
     MainThreadWorkletGlobalScope* global_scope =
         ToMainThreadWorkletGlobalScope(execution_context);
-    modulator = ModulatorImpl::Create(
-        script_state, global_scope->GetFrame()->GetDocument()->Fetcher());
+    modulator = WorkletModulatorImpl::Create(script_state);
     Modulator::SetModulator(script_state, modulator);
 
     // See comment in WorkletGlobalScope::modulator_ for this workaround.
diff --git a/third_party/WebKit/Source/core/dom/Modulator.h b/third_party/WebKit/Source/core/dom/Modulator.h
index 975707d..c3968d0 100644
--- a/third_party/WebKit/Source/core/dom/Modulator.h
+++ b/third_party/WebKit/Source/core/dom/Modulator.h
@@ -21,6 +21,7 @@
 
 class ExceptionState;
 class ModuleScript;
+class ModuleScriptFetcher;
 class ModuleScriptFetchRequest;
 class ModuleScriptLoaderClient;
 class ModuleTreeReachedUrlSet;
@@ -141,6 +142,8 @@
 
   virtual void ExecuteModule(const ModuleScript*) = 0;
 
+  virtual ModuleScriptFetcher* CreateModuleScriptFetcher() = 0;
+
  private:
   friend class ModuleMap;
 
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp b/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
deleted file mode 100644
index 4681be9..0000000
--- a/third_party/WebKit/Source/core/dom/ModulatorImpl.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/dom/ModulatorImpl.h"
-
-#include "core/dom/ExecutionContext.h"
-#include "core/dom/ModuleMap.h"
-#include "core/dom/ModuleScript.h"
-#include "core/dom/ScriptModuleResolverImpl.h"
-#include "core/dom/TaskRunnerHelper.h"
-#include "core/frame/LocalFrame.h"
-#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
-#include "core/loader/modulescript/ModuleScriptLoaderRegistry.h"
-#include "core/loader/modulescript/ModuleTreeLinkerRegistry.h"
-#include "platform/loader/fetch/ResourceFetcher.h"
-
-namespace blink {
-
-ModulatorImpl* ModulatorImpl::Create(RefPtr<ScriptState> script_state,
-                                     ResourceFetcher* resource_fetcher) {
-  return new ModulatorImpl(std::move(script_state), resource_fetcher);
-}
-
-ModulatorImpl::ModulatorImpl(RefPtr<ScriptState> script_state,
-                             ResourceFetcher* fetcher)
-    : script_state_(std::move(script_state)),
-      task_runner_(
-          TaskRunnerHelper::Get(TaskType::kNetworking, script_state_.Get())),
-      fetcher_(fetcher),
-      map_(ModuleMap::Create(this)),
-      loader_registry_(ModuleScriptLoaderRegistry::Create()),
-      tree_linker_registry_(ModuleTreeLinkerRegistry::Create()),
-      script_module_resolver_(ScriptModuleResolverImpl::Create(
-          this,
-          ExecutionContext::From(script_state_.Get()))) {
-  DCHECK(script_state_);
-  DCHECK(task_runner_);
-  DCHECK(fetcher_);
-}
-
-ModulatorImpl::~ModulatorImpl() {}
-
-ReferrerPolicy ModulatorImpl::GetReferrerPolicy() {
-  return GetExecutionContext()->GetReferrerPolicy();
-}
-
-SecurityOrigin* ModulatorImpl::GetSecurityOrigin() {
-  return GetExecutionContext()->GetSecurityOrigin();
-}
-
-void ModulatorImpl::FetchTree(const ModuleScriptFetchRequest& request,
-                              ModuleTreeClient* client) {
-  // Step 1. Perform the internal module script graph fetching procedure given
-  // url, settings object, destination, cryptographic nonce, parser state,
-  // credentials mode, settings object, a new empty list, "client", and with the
-  // top-level module fetch flag set. If the caller of this algorithm specified
-  // custom perform the fetch steps, pass those along as well.
-
-  // Note: "Fetch a module script graph" algorithm doesn't have "referrer" as
-  // its argument.
-  DCHECK(request.GetReferrer().IsNull());
-
-  AncestorList empty_ancestor_list;
-  FetchTreeInternal(request, empty_ancestor_list,
-                    ModuleGraphLevel::kTopLevelModuleFetch, nullptr, client);
-
-  // Step 2. When the internal module script graph fetching procedure
-  // asynchronously completes with result, asynchronously complete this
-  // algorithm with result.
-  // Note: We delegate to ModuleTreeLinker to notify ModuleTreeClient.
-}
-
-void ModulatorImpl::FetchTreeInternal(const ModuleScriptFetchRequest& request,
-                                      const AncestorList& ancestor_list,
-                                      ModuleGraphLevel level,
-                                      ModuleTreeReachedUrlSet* reached_url_set,
-                                      ModuleTreeClient* client) {
-  // We ensure module-related code is not executed without the flag.
-  // https://crbug.com/715376
-  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
-
-  tree_linker_registry_->Fetch(request, ancestor_list, level, this,
-                               reached_url_set, client);
-}
-
-void ModulatorImpl::FetchDescendantsForInlineScript(ModuleScript* module_script,
-                                                    ModuleTreeClient* client) {
-  tree_linker_registry_->FetchDescendantsForInlineScript(module_script, this,
-                                                         client);
-}
-
-void ModulatorImpl::FetchSingle(const ModuleScriptFetchRequest& request,
-                                ModuleGraphLevel level,
-                                SingleModuleClient* client) {
-  // We ensure module-related code is not executed without the flag.
-  // https://crbug.com/715376
-  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
-
-  map_->FetchSingleModuleScript(request, level, client);
-}
-
-void ModulatorImpl::FetchNewSingleModule(
-    const ModuleScriptFetchRequest& request,
-    ModuleGraphLevel level,
-    ModuleScriptLoaderClient* client) {
-  // We ensure module-related code is not executed without the flag.
-  // https://crbug.com/715376
-  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
-
-  loader_registry_->Fetch(request, level, this, fetcher_.Get(), client);
-}
-
-ModuleScript* ModulatorImpl::GetFetchedModuleScript(const KURL& url) {
-  return map_->GetFetchedModuleScript(url);
-}
-
-bool ModulatorImpl::HasValidContext() {
-  return script_state_->ContextIsValid();
-}
-
-ScriptModule ModulatorImpl::CompileModule(
-    const String& provided_source,
-    const String& url_str,
-    AccessControlStatus access_control_status,
-    const TextPosition& position,
-    ExceptionState& exception_state) {
-  // Implements Steps 3-5 of
-  // https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-module-script
-
-  // Step 3. Let realm be the provided environment settings object's Realm.
-  // Note: Realm is v8::Context.
-
-  // Step 4. If scripting is disabled for the given environment settings
-  // object's responsible browsing context, then let script source be the empty
-  // string. Otherwise, let script source be the provided script source.
-  String script_source;
-  if (GetExecutionContext()->CanExecuteScripts(kAboutToExecuteScript))
-    script_source = provided_source;
-
-  // Step 5. Let result be ParseModule(script source, realm, script).
-  ScriptState::Scope scope(script_state_.Get());
-  return ScriptModule::Compile(script_state_->GetIsolate(), script_source,
-                               url_str, access_control_status, position,
-                               exception_state);
-}
-
-ScriptValue ModulatorImpl::InstantiateModule(ScriptModule script_module) {
-  ScriptState::Scope scope(script_state_.Get());
-  return script_module.Instantiate(script_state_.Get());
-}
-
-ScriptModuleState ModulatorImpl::GetRecordStatus(ScriptModule script_module) {
-  ScriptState::Scope scope(script_state_.Get());
-  return script_module.Status(script_state_.Get());
-}
-
-ScriptValue ModulatorImpl::GetError(const ModuleScript* module_script) {
-  DCHECK(module_script);
-  ScriptState::Scope scope(script_state_.Get());
-  // https://html.spec.whatwg.org/multipage/webappapis.html#concept-module-script-error
-  // "When a module script is errored, ..." [spec text]
-
-  // "we say that its error is either its pre-instantiation error, when its
-  // module record is null, ..." [spec text]
-  ScriptModule record = module_script->Record();
-  if (record.IsNull()) {
-    return ScriptValue(script_state_.Get(), module_script->CreateErrorInternal(
-                                                script_state_->GetIsolate()));
-  }
-
-  // "or its module record's [[ErrorCompletion]] field's [[Value]] field,
-  // otherwise." [spec text]
-  return ScriptValue(script_state_.Get(),
-                     record.ErrorCompletion(script_state_.Get()));
-}
-
-Vector<Modulator::ModuleRequest> ModulatorImpl::ModuleRequestsFromScriptModule(
-    ScriptModule script_module) {
-  ScriptState::Scope scope(script_state_.Get());
-  Vector<String> specifiers = script_module.ModuleRequests(script_state_.Get());
-  Vector<TextPosition> positions =
-      script_module.ModuleRequestPositions(script_state_.Get());
-  DCHECK_EQ(specifiers.size(), positions.size());
-  Vector<ModuleRequest> requests;
-  requests.ReserveInitialCapacity(specifiers.size());
-  for (size_t i = 0; i < specifiers.size(); ++i) {
-    requests.emplace_back(specifiers[i], positions[i]);
-  }
-  return requests;
-}
-
-inline ExecutionContext* ModulatorImpl::GetExecutionContext() const {
-  return ExecutionContext::From(script_state_.Get());
-}
-
-void ModulatorImpl::ExecuteModule(const ModuleScript* module_script) {
-  // https://html.spec.whatwg.org/#run-a-module-script
-
-  // We ensure module-related code is not executed without the flag.
-  // https://crbug.com/715376
-  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
-
-  // Step 1. "Let settings be the settings object of s." [spec text]
-  // The settings object is |this|.
-
-  // Step 2. "Check if we can run script with settings.
-  //          If this returns "do not run" then abort these steps." [spec text]
-  if (!GetExecutionContext()->CanExecuteScripts(kAboutToExecuteScript))
-    return;
-
-  // Step 4. "Prepare to run script given settings." [spec text]
-  // This is placed here to also cover ScriptModule::ReportException().
-  ScriptState::Scope scope(script_state_.Get());
-
-  // Step 3. "If s is errored, then report the exception given by s's error for
-  // s and abort these steps." [spec text]
-  if (module_script->IsErrored()) {
-    ScriptValue error = GetError(module_script);
-    ScriptModule::ReportException(script_state_.Get(), error.V8Value());
-    return;
-  }
-
-  // Step 5. "Let record be s's module record." [spec text]
-  const ScriptModule& record = module_script->Record();
-  CHECK(!record.IsNull());
-
-  // Step 6. "Let evaluationStatus be record.ModuleEvaluation()." [spec text]
-  record.Evaluate(script_state_.Get());
-
-  // Step 7. "If evaluationStatus is an abrupt completion, then report the
-  // exception given by evaluationStatus.[[Value]] for s." [spec text]
-  // TODO(kouhei): Implement this.
-
-  // Step 8. "Clean up after running script with settings." [spec text]
-  // Implemented as the ScriptState::Scope destructor.
-}
-
-DEFINE_TRACE(ModulatorImpl) {
-  Modulator::Trace(visitor);
-  visitor->Trace(fetcher_);
-  visitor->Trace(map_);
-  visitor->Trace(loader_registry_);
-  visitor->Trace(tree_linker_registry_);
-  visitor->Trace(script_module_resolver_);
-}
-
-DEFINE_TRACE_WRAPPERS(ModulatorImpl) {
-  visitor->TraceWrappers(map_);
-  visitor->TraceWrappers(tree_linker_registry_);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImpl.h b/third_party/WebKit/Source/core/dom/ModulatorImpl.h
deleted file mode 100644
index b2116adf..0000000
--- a/third_party/WebKit/Source/core/dom/ModulatorImpl.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ModulatorImpl_h
-#define ModulatorImpl_h
-
-#include "bindings/core/v8/ScriptModule.h"
-#include "core/dom/Modulator.h"
-#include "platform/bindings/ScriptWrappable.h"
-#include "platform/bindings/TraceWrapperMember.h"
-#include "platform/bindings/V8PerIsolateData.h"
-#include "platform/heap/Handle.h"
-
-namespace blink {
-
-class ExecutionContext;
-class ModuleMap;
-class ModuleScriptLoaderRegistry;
-class ModuleTreeLinkerRegistry;
-class ModuleTreeReachedUrlSet;
-class ResourceFetcher;
-class ScriptState;
-class WebTaskRunner;
-
-// ModulatorImpl is the implementation of Modulator interface, which represents
-// "environment settings object" concept for module scripts.
-// ModulatorImpl serves as the backplane for tieing all ES6 module algorithm
-// components together.
-class ModulatorImpl final : public Modulator {
- public:
-  static ModulatorImpl* Create(RefPtr<ScriptState>, ResourceFetcher*);
-
-  virtual ~ModulatorImpl();
-  DECLARE_TRACE();
-  DECLARE_VIRTUAL_TRACE_WRAPPERS();
-
- private:
-  // Implements Modulator
-
-  ScriptModuleResolver* GetScriptModuleResolver() override {
-    return script_module_resolver_.Get();
-  }
-  WebTaskRunner* TaskRunner() override { return task_runner_.Get(); }
-  ReferrerPolicy GetReferrerPolicy() override;
-  SecurityOrigin* GetSecurityOrigin() override;
-  ScriptState* GetScriptState() override { return script_state_.Get(); }
-
-  void FetchTree(const ModuleScriptFetchRequest&, ModuleTreeClient*) override;
-  void FetchDescendantsForInlineScript(ModuleScript*,
-                                       ModuleTreeClient*) override;
-  void FetchTreeInternal(const ModuleScriptFetchRequest&,
-                         const AncestorList&,
-                         ModuleGraphLevel,
-                         ModuleTreeReachedUrlSet*,
-                         ModuleTreeClient*) override;
-  void FetchSingle(const ModuleScriptFetchRequest&,
-                   ModuleGraphLevel,
-                   SingleModuleClient*) override;
-  ModuleScript* GetFetchedModuleScript(const KURL&) override;
-  bool HasValidContext() override;
-  void FetchNewSingleModule(const ModuleScriptFetchRequest&,
-                            ModuleGraphLevel,
-                            ModuleScriptLoaderClient*) override;
-  ScriptModule CompileModule(const String& script,
-                             const String& url_str,
-                             AccessControlStatus,
-                             const TextPosition&,
-                             ExceptionState&) override;
-  ScriptValue InstantiateModule(ScriptModule) override;
-  ScriptModuleState GetRecordStatus(ScriptModule) override;
-  ScriptValue GetError(const ModuleScript*) override;
-  Vector<ModuleRequest> ModuleRequestsFromScriptModule(ScriptModule) override;
-  void ExecuteModule(const ModuleScript*) override;
-
-  ModulatorImpl(RefPtr<ScriptState>, ResourceFetcher*);
-
-  ExecutionContext* GetExecutionContext() const;
-
-  RefPtr<ScriptState> script_state_;
-  RefPtr<WebTaskRunner> task_runner_;
-  Member<ResourceFetcher> fetcher_;
-  TraceWrapperMember<ModuleMap> map_;
-  Member<ModuleScriptLoaderRegistry> loader_registry_;
-  TraceWrapperMember<ModuleTreeLinkerRegistry> tree_linker_registry_;
-  Member<ScriptModuleResolver> script_module_resolver_;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImplBase.cpp b/third_party/WebKit/Source/core/dom/ModulatorImplBase.cpp
new file mode 100644
index 0000000..4765154
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/ModulatorImplBase.cpp
@@ -0,0 +1,246 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/dom/ModulatorImplBase.h"
+
+#include "core/dom/ExecutionContext.h"
+#include "core/dom/ModuleMap.h"
+#include "core/dom/ModuleScript.h"
+#include "core/dom/ScriptModuleResolverImpl.h"
+#include "core/dom/TaskRunnerHelper.h"
+#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
+#include "core/loader/modulescript/ModuleScriptLoaderRegistry.h"
+#include "core/loader/modulescript/ModuleTreeLinkerRegistry.h"
+#include "platform/WebTaskRunner.h"
+
+namespace blink {
+
+ExecutionContext* ModulatorImplBase::GetExecutionContext() const {
+  return ExecutionContext::From(script_state_.Get());
+}
+
+ModulatorImplBase::ModulatorImplBase(RefPtr<ScriptState> script_state)
+    : script_state_(std::move(script_state)),
+      task_runner_(
+          TaskRunnerHelper::Get(TaskType::kNetworking, script_state_.Get())),
+      map_(ModuleMap::Create(this)),
+      loader_registry_(ModuleScriptLoaderRegistry::Create()),
+      tree_linker_registry_(ModuleTreeLinkerRegistry::Create()),
+      script_module_resolver_(ScriptModuleResolverImpl::Create(
+          this,
+          ExecutionContext::From(script_state_.Get()))) {
+  DCHECK(script_state_);
+  DCHECK(task_runner_);
+}
+
+ModulatorImplBase::~ModulatorImplBase() {}
+
+ReferrerPolicy ModulatorImplBase::GetReferrerPolicy() {
+  return GetExecutionContext()->GetReferrerPolicy();
+}
+
+SecurityOrigin* ModulatorImplBase::GetSecurityOrigin() {
+  return GetExecutionContext()->GetSecurityOrigin();
+}
+
+void ModulatorImplBase::FetchTree(const ModuleScriptFetchRequest& request,
+                                  ModuleTreeClient* client) {
+  // Step 1. Perform the internal module script graph fetching procedure given
+  // url, settings object, destination, cryptographic nonce, parser state,
+  // credentials mode, settings object, a new empty list, "client", and with the
+  // top-level module fetch flag set. If the caller of this algorithm specified
+  // custom perform the fetch steps, pass those along as well.
+
+  // Note: "Fetch a module script graph" algorithm doesn't have "referrer" as
+  // its argument.
+  DCHECK(request.GetReferrer().IsNull());
+
+  AncestorList empty_ancestor_list;
+  FetchTreeInternal(request, empty_ancestor_list,
+                    ModuleGraphLevel::kTopLevelModuleFetch, nullptr, client);
+
+  // Step 2. When the internal module script graph fetching procedure
+  // asynchronously completes with result, asynchronously complete this
+  // algorithm with result.
+  // Note: We delegate to ModuleTreeLinker to notify ModuleTreeClient.
+}
+
+void ModulatorImplBase::FetchTreeInternal(
+    const ModuleScriptFetchRequest& request,
+    const AncestorList& ancestor_list,
+    ModuleGraphLevel level,
+    ModuleTreeReachedUrlSet* reached_url_set,
+    ModuleTreeClient* client) {
+  // We ensure module-related code is not executed without the flag.
+  // https://crbug.com/715376
+  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
+
+  tree_linker_registry_->Fetch(request, ancestor_list, level, this,
+                               reached_url_set, client);
+}
+
+void ModulatorImplBase::FetchDescendantsForInlineScript(
+    ModuleScript* module_script,
+    ModuleTreeClient* client) {
+  tree_linker_registry_->FetchDescendantsForInlineScript(module_script, this,
+                                                         client);
+}
+
+void ModulatorImplBase::FetchSingle(const ModuleScriptFetchRequest& request,
+                                    ModuleGraphLevel level,
+                                    SingleModuleClient* client) {
+  // We ensure module-related code is not executed without the flag.
+  // https://crbug.com/715376
+  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
+
+  map_->FetchSingleModuleScript(request, level, client);
+}
+
+void ModulatorImplBase::FetchNewSingleModule(
+    const ModuleScriptFetchRequest& request,
+    ModuleGraphLevel level,
+    ModuleScriptLoaderClient* client) {
+  // We ensure module-related code is not executed without the flag.
+  // https://crbug.com/715376
+  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
+
+  loader_registry_->Fetch(request, level, this, client);
+}
+
+ModuleScript* ModulatorImplBase::GetFetchedModuleScript(const KURL& url) {
+  return map_->GetFetchedModuleScript(url);
+}
+
+bool ModulatorImplBase::HasValidContext() {
+  return script_state_->ContextIsValid();
+}
+
+ScriptModule ModulatorImplBase::CompileModule(
+    const String& provided_source,
+    const String& url_str,
+    AccessControlStatus access_control_status,
+    const TextPosition& position,
+    ExceptionState& exception_state) {
+  // Implements Steps 3-5 of
+  // https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-module-script
+
+  // Step 3. Let realm be the provided environment settings object's Realm.
+  // Note: Realm is v8::Context.
+
+  // Step 4. If scripting is disabled for the given environment settings
+  // object's responsible browsing context, then let script source be the empty
+  // string. Otherwise, let script source be the provided script source.
+  String script_source;
+  if (GetExecutionContext()->CanExecuteScripts(kAboutToExecuteScript))
+    script_source = provided_source;
+
+  // Step 5. Let result be ParseModule(script source, realm, script).
+  ScriptState::Scope scope(script_state_.Get());
+  return ScriptModule::Compile(script_state_->GetIsolate(), script_source,
+                               url_str, access_control_status, position,
+                               exception_state);
+}
+
+ScriptValue ModulatorImplBase::InstantiateModule(ScriptModule script_module) {
+  ScriptState::Scope scope(script_state_.Get());
+  return script_module.Instantiate(script_state_.Get());
+}
+
+ScriptModuleState ModulatorImplBase::GetRecordStatus(
+    ScriptModule script_module) {
+  ScriptState::Scope scope(script_state_.Get());
+  return script_module.Status(script_state_.Get());
+}
+
+ScriptValue ModulatorImplBase::GetError(const ModuleScript* module_script) {
+  DCHECK(module_script);
+  ScriptState::Scope scope(script_state_.Get());
+  // https://html.spec.whatwg.org/multipage/webappapis.html#concept-module-script-error
+  // "When a module script is errored, ..." [spec text]
+
+  // "we say that its error is either its pre-instantiation error, when its
+  // module record is null, ..." [spec text]
+  ScriptModule record = module_script->Record();
+  if (record.IsNull()) {
+    return ScriptValue(script_state_.Get(), module_script->CreateErrorInternal(
+                                                script_state_->GetIsolate()));
+  }
+
+  // "or its module record's [[ErrorCompletion]] field's [[Value]] field,
+  // otherwise." [spec text]
+  return ScriptValue(script_state_.Get(),
+                     record.ErrorCompletion(script_state_.Get()));
+}
+
+Vector<Modulator::ModuleRequest>
+ModulatorImplBase::ModuleRequestsFromScriptModule(ScriptModule script_module) {
+  ScriptState::Scope scope(script_state_.Get());
+  Vector<String> specifiers = script_module.ModuleRequests(script_state_.Get());
+  Vector<TextPosition> positions =
+      script_module.ModuleRequestPositions(script_state_.Get());
+  DCHECK_EQ(specifiers.size(), positions.size());
+  Vector<ModuleRequest> requests;
+  requests.ReserveInitialCapacity(specifiers.size());
+  for (size_t i = 0; i < specifiers.size(); ++i) {
+    requests.emplace_back(specifiers[i], positions[i]);
+  }
+  return requests;
+}
+
+void ModulatorImplBase::ExecuteModule(const ModuleScript* module_script) {
+  // https://html.spec.whatwg.org/#run-a-module-script
+
+  // We ensure module-related code is not executed without the flag.
+  // https://crbug.com/715376
+  CHECK(RuntimeEnabledFeatures::ModuleScriptsEnabled());
+
+  // Step 1. "Let settings be the settings object of s." [spec text]
+  // The settings object is |this|.
+
+  // Step 2. "Check if we can run script with settings.
+  //          If this returns "do not run" then abort these steps." [spec text]
+  if (!GetExecutionContext()->CanExecuteScripts(kAboutToExecuteScript))
+    return;
+
+  // Step 4. "Prepare to run script given settings." [spec text]
+  // This is placed here to also cover ScriptModule::ReportException().
+  ScriptState::Scope scope(script_state_.Get());
+
+  // Step 3. "If s is errored, then report the exception given by s's error for
+  // s and abort these steps." [spec text]
+  if (module_script->IsErrored()) {
+    ScriptValue error = GetError(module_script);
+    ScriptModule::ReportException(script_state_.Get(), error.V8Value());
+    return;
+  }
+
+  // Step 5. "Let record be s's module record." [spec text]
+  const ScriptModule& record = module_script->Record();
+  CHECK(!record.IsNull());
+
+  // Step 6. "Let evaluationStatus be record.ModuleEvaluation()." [spec text]
+  record.Evaluate(script_state_.Get());
+
+  // Step 7. "If evaluationStatus is an abrupt completion, then report the
+  // exception given by evaluationStatus.[[Value]] for s." [spec text]
+  // TODO(kouhei): Implement this.
+
+  // Step 8. "Clean up after running script with settings." [spec text]
+  // Implemented as the ScriptState::Scope destructor.
+}
+
+DEFINE_TRACE(ModulatorImplBase) {
+  Modulator::Trace(visitor);
+  visitor->Trace(map_);
+  visitor->Trace(loader_registry_);
+  visitor->Trace(tree_linker_registry_);
+  visitor->Trace(script_module_resolver_);
+}
+
+DEFINE_TRACE_WRAPPERS(ModulatorImplBase) {
+  visitor->TraceWrappers(map_);
+  visitor->TraceWrappers(tree_linker_registry_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ModulatorImplBase.h b/third_party/WebKit/Source/core/dom/ModulatorImplBase.h
new file mode 100644
index 0000000..a76fb59
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/ModulatorImplBase.h
@@ -0,0 +1,88 @@
+// 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 ModulatorImplBase_h
+#define ModulatorImplBase_h
+
+#include "bindings/core/v8/ScriptModule.h"
+#include "core/dom/Modulator.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/bindings/TraceWrapperMember.h"
+#include "platform/bindings/V8PerIsolateData.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class ExecutionContext;
+class ModuleMap;
+class ModuleScriptLoaderRegistry;
+class ModuleTreeLinkerRegistry;
+class ModuleTreeReachedUrlSet;
+class ScriptState;
+class WebTaskRunner;
+
+// ModulatorImplBase is the base implementation of Modulator interface, which
+// represents "environment settings object" concept for module scripts.
+// ModulatorImplBase serves as the backplane for tieing all ES6 module algorithm
+// components together.
+class ModulatorImplBase : public Modulator {
+ public:
+  virtual ~ModulatorImplBase();
+  DECLARE_TRACE();
+  DECLARE_VIRTUAL_TRACE_WRAPPERS();
+
+  ExecutionContext* GetExecutionContext() const;
+
+ protected:
+  explicit ModulatorImplBase(RefPtr<ScriptState>);
+
+ private:
+  // Implements Modulator
+
+  ScriptModuleResolver* GetScriptModuleResolver() override {
+    return script_module_resolver_.Get();
+  }
+  WebTaskRunner* TaskRunner() override { return task_runner_.Get(); }
+  ReferrerPolicy GetReferrerPolicy() override;
+  SecurityOrigin* GetSecurityOrigin() override;
+  ScriptState* GetScriptState() override { return script_state_.Get(); }
+
+  void FetchTree(const ModuleScriptFetchRequest&, ModuleTreeClient*) override;
+  void FetchDescendantsForInlineScript(ModuleScript*,
+                                       ModuleTreeClient*) override;
+  void FetchTreeInternal(const ModuleScriptFetchRequest&,
+                         const AncestorList&,
+                         ModuleGraphLevel,
+                         ModuleTreeReachedUrlSet*,
+                         ModuleTreeClient*) override;
+  void FetchSingle(const ModuleScriptFetchRequest&,
+                   ModuleGraphLevel,
+                   SingleModuleClient*) override;
+  ModuleScript* GetFetchedModuleScript(const KURL&) override;
+  bool HasValidContext() override;
+  void FetchNewSingleModule(const ModuleScriptFetchRequest&,
+                            ModuleGraphLevel,
+                            ModuleScriptLoaderClient*) override;
+  ScriptModule CompileModule(const String& script,
+                             const String& url_str,
+                             AccessControlStatus,
+                             const TextPosition&,
+                             ExceptionState&) override;
+  ScriptValue InstantiateModule(ScriptModule) override;
+  ScriptModuleState GetRecordStatus(ScriptModule) override;
+  ScriptValue GetError(const ModuleScript*) override;
+  Vector<ModuleRequest> ModuleRequestsFromScriptModule(ScriptModule) override;
+  void ExecuteModule(const ModuleScript*) override;
+
+  RefPtr<ScriptState> script_state_;
+  RefPtr<WebTaskRunner> task_runner_;
+  TraceWrapperMember<ModuleMap> map_;
+  Member<ModuleScriptLoaderRegistry> loader_registry_;
+  TraceWrapperMember<ModuleTreeLinkerRegistry> tree_linker_registry_;
+  Member<ScriptModuleResolver> script_module_resolver_;
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.h b/third_party/WebKit/Source/core/dom/ModuleScript.h
index 2df3050..b18f3a96 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.h
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.h
@@ -113,7 +113,7 @@
   void RunScript(LocalFrame*, const SecurityOrigin*) const override;
   String InlineSourceTextForCSP() const override;
 
-  friend class ModulatorImpl;
+  friend class ModulatorImplBase;
   friend class ModuleTreeLinkerTestModulator;
   // Access this func only via ModulatorImpl::GetError(),
   // or via Modulator mocks for unit tests.
diff --git a/third_party/WebKit/Source/core/dom/MutationObserver.cpp b/third_party/WebKit/Source/core/dom/MutationObserver.cpp
index 05e76dc..f7ad1b8 100644
--- a/third_party/WebKit/Source/core/dom/MutationObserver.cpp
+++ b/third_party/WebKit/Source/core/dom/MutationObserver.cpp
@@ -33,8 +33,8 @@
 #include <algorithm>
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/MutationCallback.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/mutation_callback.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/MutationObserverInit.h"
 #include "core/dom/MutationObserverRegistration.h"
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 23e2d834..8caa2f3b 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -27,7 +27,7 @@
 #include "core/dom/Node.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/NodeOrString.h"
+#include "bindings/core/v8/node_or_string.h"
 #include "core/HTMLNames.h"
 #include "core/MathMLNames.h"
 #include "core/css/CSSSelector.h"
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index 1808177..2746eef1 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -29,9 +29,9 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/CoreExport.h"
 #include "core/dom/MutationObserver.h"
-#include "core/dom/SimulatedClickOptions.h"
 #include "core/dom/TreeScope.h"
 #include "core/dom/events/EventTarget.h"
+#include "core/dom/events/SimulatedClickOptions.h"
 #include "core/editing/EditingBoundary.h"
 #include "core/style/ComputedStyleConstants.h"
 #include "platform/bindings/TraceWrapperMember.h"
diff --git a/third_party/WebKit/Source/core/dom/RangeTest.cpp b/third_party/WebKit/Source/core/dom/RangeTest.cpp
index a5dcc2eb..ad0d599 100644
--- a/third_party/WebKit/Source/core/dom/RangeTest.cpp
+++ b/third_party/WebKit/Source/core/dom/RangeTest.cpp
@@ -5,8 +5,8 @@
 #include "core/dom/Range.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/StringOrArrayBufferOrArrayBufferView.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/string_or_array_buffer_or_array_buffer_view.h"
 #include "core/css/FontFaceDescriptors.h"
 #include "core/css/FontFaceSetDocument.h"
 #include "core/dom/Element.h"
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
index c241695..4b94ccf1 100644
--- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
+++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
@@ -18,18 +18,16 @@
 namespace blink {
 
 RefPtr<WebTaskRunner> TaskRunnerHelper::Get(TaskType type, LocalFrame* frame) {
+  DCHECK(frame);
   // TODO(haraken): Optimize the mapping from TaskTypes to task runners.
   switch (type) {
     case TaskType::kTimer:
-      return frame ? frame->FrameScheduler()->ThrottleableTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+      return frame->FrameScheduler()->ThrottleableTaskRunner();
     case TaskType::kUnspecedLoading:
     case TaskType::kNetworking:
-      return frame ? frame->FrameScheduler()->LoadingTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+      return frame->FrameScheduler()->LoadingTaskRunner();
     case TaskType::kNetworkingControl:
-      return frame ? frame->FrameScheduler()->LoadingControlTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+      return frame->FrameScheduler()->LoadingControlTaskRunner();
     // Throttling following tasks may break existing web pages, so tentatively
     // these are unthrottled.
     // TODO(nhiroki): Throttle them again after we're convinced that it's safe
@@ -52,8 +50,7 @@
     case TaskType::kUnspecedTimer:
     case TaskType::kMiscPlatformAPI:
       // TODO(altimin): Move appropriate tasks to throttleable task queue.
-      return frame ? frame->FrameScheduler()->DeferrableTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+      return frame->FrameScheduler()->DeferrableTaskRunner();
     // PostedMessage can be used for navigation, so we shouldn't defer it
     // when expecting a user gesture.
     case TaskType::kPostedMessage:
@@ -62,37 +59,41 @@
     // Media events should not be deferred to ensure that media playback is
     // smooth.
     case TaskType::kMediaElementEvent:
-      return frame ? frame->FrameScheduler()->PausableTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+      return frame->FrameScheduler()->PausableTaskRunner();
     case TaskType::kUnthrottled:
-      return frame ? frame->FrameScheduler()->UnpausableTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+      return frame->FrameScheduler()->UnpausableTaskRunner();
   }
   NOTREACHED();
   return nullptr;
 }
 
 RefPtr<WebTaskRunner> TaskRunnerHelper::Get(TaskType type, Document* document) {
-  return Get(type, document ? document->GetFrame() : nullptr);
+  DCHECK(document);
+  if (document->ContextDocument())
+    return Get(type, document->ContextDocument()->GetFrame());
+  // In most cases, ContextDocument() will get us to a relevant Frame, even if
+  // the passed-in document is detached. In some cases, though, there isn't a
+  // good candidate (e.g., XMLDocuments created by DocumentResource and stored
+  // in the MemoryCache).
+  return Platform::Current()->CurrentThread()->GetWebTaskRunner();
 }
 
 RefPtr<WebTaskRunner> TaskRunnerHelper::Get(
     TaskType type,
     ExecutionContext* execution_context) {
   if (!execution_context)
-    return Get(type, ToDocument(execution_context));
+    return Platform::Current()->CurrentThread()->GetWebTaskRunner();
   if (execution_context->IsDocument())
     return Get(type, ToDocument(execution_context));
   if (execution_context->IsWorkerOrWorkletGlobalScope())
     return Get(type, ToWorkerOrWorkletGlobalScope(execution_context));
-  execution_context = nullptr;
-  return Get(type, ToDocument(execution_context));
+  // This should only happen for a NullExecutionContext in a unit test.
+  return Platform::Current()->CurrentThread()->GetWebTaskRunner();
 }
 
 RefPtr<WebTaskRunner> TaskRunnerHelper::Get(TaskType type,
                                             ScriptState* script_state) {
-  return Get(type,
-             script_state ? ExecutionContext::From(script_state) : nullptr);
+  return Get(type, ExecutionContext::From(script_state));
 }
 
 RefPtr<WebTaskRunner> TaskRunnerHelper::Get(
diff --git a/third_party/WebKit/Source/core/dom/Touch.cpp b/third_party/WebKit/Source/core/dom/Touch.cpp
deleted file mode 100644
index 89e431c..0000000
--- a/third_party/WebKit/Source/core/dom/Touch.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "core/dom/Touch.h"
-
-#include "core/frame/LocalFrame.h"
-#include "core/frame/LocalFrameView.h"
-#include "platform/geometry/FloatPoint.h"
-
-namespace blink {
-
-static FloatPoint ContentsOffset(LocalFrame* frame) {
-  if (!frame)
-    return FloatPoint();
-  LocalFrameView* frame_view = frame->View();
-  if (!frame_view)
-    return FloatPoint();
-  float scale = 1.0f / frame->PageZoomFactor();
-  return FloatPoint(frame_view->GetScrollOffset()).ScaledBy(scale);
-}
-
-Touch::Touch(LocalFrame* frame,
-             EventTarget* target,
-             int identifier,
-             const FloatPoint& screen_pos,
-             const FloatPoint& page_pos,
-             const FloatSize& radius,
-             float rotation_angle,
-             float force,
-             String region)
-    : target_(target),
-      identifier_(identifier),
-      client_pos_(page_pos - ContentsOffset(frame)),
-      screen_pos_(screen_pos),
-      page_pos_(page_pos),
-      radius_(radius),
-      rotation_angle_(rotation_angle),
-      force_(force),
-      region_(region) {
-  float scale_factor = frame ? frame->PageZoomFactor() : 1.0f;
-  absolute_location_ = LayoutPoint(page_pos.ScaledBy(scale_factor));
-}
-
-Touch::Touch(EventTarget* target,
-             int identifier,
-             const FloatPoint& client_pos,
-             const FloatPoint& screen_pos,
-             const FloatPoint& page_pos,
-             const FloatSize& radius,
-             float rotation_angle,
-             float force,
-             String region,
-             LayoutPoint absolute_location)
-    : target_(target),
-      identifier_(identifier),
-      client_pos_(client_pos),
-      screen_pos_(screen_pos),
-      page_pos_(page_pos),
-      radius_(radius),
-      rotation_angle_(rotation_angle),
-      force_(force),
-      region_(region),
-      absolute_location_(absolute_location) {}
-
-Touch::Touch(LocalFrame* frame, const TouchInit& initializer)
-    : target_(initializer.target()),
-      identifier_(initializer.identifier()),
-      client_pos_(FloatPoint(initializer.clientX(), initializer.clientY())),
-      screen_pos_(FloatPoint(initializer.screenX(), initializer.screenY())),
-      page_pos_(FloatPoint(initializer.pageX(), initializer.pageY())),
-      radius_(FloatSize(initializer.radiusX(), initializer.radiusY())),
-      rotation_angle_(initializer.rotationAngle()),
-      force_(initializer.force()),
-      region_(initializer.region()) {
-  float scale_factor = frame ? frame->PageZoomFactor() : 1.0f;
-  absolute_location_ = LayoutPoint(page_pos_.ScaledBy(scale_factor));
-}
-
-Touch* Touch::CloneWithNewTarget(EventTarget* event_target) const {
-  return new Touch(event_target, identifier_, client_pos_, screen_pos_,
-                   page_pos_, radius_, rotation_angle_, force_, region_,
-                   absolute_location_);
-}
-
-DEFINE_TRACE(Touch) {
-  visitor->Trace(target_);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/Touch.h b/third_party/WebKit/Source/core/dom/Touch.h
deleted file mode 100644
index c756997..0000000
--- a/third_party/WebKit/Source/core/dom/Touch.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef Touch_h
-#define Touch_h
-
-#include "core/CoreExport.h"
-#include "core/dom/Document.h"
-#include "core/dom/TouchInit.h"
-#include "core/dom/events/EventTarget.h"
-#include "platform/bindings/ScriptWrappable.h"
-#include "platform/geometry/FloatPoint.h"
-#include "platform/geometry/FloatSize.h"
-#include "platform/geometry/LayoutPoint.h"
-#include "platform/heap/Handle.h"
-
-namespace blink {
-
-class LocalFrame;
-
-class CORE_EXPORT Touch final : public GarbageCollectedFinalized<Touch>,
-                                public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static Touch* Create(LocalFrame* frame,
-                       EventTarget* target,
-                       int identifier,
-                       const FloatPoint& screen_pos,
-                       const FloatPoint& page_pos,
-                       const FloatSize& radius,
-                       float rotation_angle,
-                       float force,
-                       String region) {
-    return new Touch(frame, target, identifier, screen_pos, page_pos, radius,
-                     rotation_angle, force, region);
-  }
-
-  static Touch* Create(const Document& document, const TouchInit& initializer) {
-    return new Touch(document.GetFrame(), initializer);
-  }
-
-  // DOM Touch implementation
-  EventTarget* target() const { return target_.Get(); }
-  int identifier() const { return identifier_; }
-  double clientX() const { return client_pos_.X(); }
-  double clientY() const { return client_pos_.Y(); }
-  double screenX() const { return screen_pos_.X(); }
-  double screenY() const { return screen_pos_.Y(); }
-  double pageX() const { return page_pos_.X(); }
-  double pageY() const { return page_pos_.Y(); }
-  float radiusX() const { return radius_.Width(); }
-  float radiusY() const { return radius_.Height(); }
-  float rotationAngle() const { return rotation_angle_; }
-  float force() const { return force_; }
-  const String& region() const { return region_; }
-
-  // Blink-internal methods
-  const LayoutPoint& AbsoluteLocation() const { return absolute_location_; }
-  const FloatPoint& ScreenLocation() const { return screen_pos_; }
-  Touch* CloneWithNewTarget(EventTarget*) const;
-
-  DECLARE_TRACE();
-
- private:
-  Touch(LocalFrame*,
-        EventTarget*,
-        int identifier,
-        const FloatPoint& screen_pos,
-        const FloatPoint& page_pos,
-        const FloatSize& radius,
-        float rotation_angle,
-        float force,
-        String region);
-
-  Touch(EventTarget*,
-        int identifier,
-        const FloatPoint& client_pos,
-        const FloatPoint& screen_pos,
-        const FloatPoint& page_pos,
-        const FloatSize& radius,
-        float rotation_angle,
-        float force,
-        String region,
-        LayoutPoint absolute_location);
-
-  Touch(LocalFrame*, const TouchInit&);
-
-  Member<EventTarget> target_;
-  int identifier_;
-  // Position relative to the viewport in CSS px.
-  FloatPoint client_pos_;
-  // Position relative to the screen in DIPs.
-  FloatPoint screen_pos_;
-  // Position relative to the page in CSS px.
-  FloatPoint page_pos_;
-  // Radius in CSS px.
-  FloatSize radius_;
-  float rotation_angle_;
-  float force_;
-  String region_;
-  // FIXME(rbyers): Shouldn't we be able to migrate callers to relying on
-  // screenPos, pagePos or clientPos? absoluteLocation appears to be the same as
-  // pagePos but without browser scale applied.
-  LayoutPoint absolute_location_;
-};
-
-}  // namespace blink
-
-#endif  // Touch_h
diff --git a/third_party/WebKit/Source/core/dom/TouchList.cpp b/third_party/WebKit/Source/core/dom/TouchList.cpp
deleted file mode 100644
index 61d38db..0000000
--- a/third_party/WebKit/Source/core/dom/TouchList.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "core/dom/TouchList.h"
-
-namespace blink {
-
-Touch* TouchList::item(unsigned index) {
-  if (index >= values_.size())
-    return nullptr;
-  return values_[index].Get();
-}
-
-const Touch* TouchList::item(unsigned index) const {
-  return const_cast<TouchList*>(this)->item(index);
-}
-
-DEFINE_TRACE(TouchList) {
-  visitor->Trace(values_);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/TouchList.h b/third_party/WebKit/Source/core/dom/TouchList.h
deleted file mode 100644
index bbe0e78..0000000
--- a/third_party/WebKit/Source/core/dom/TouchList.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TouchList_h
-#define TouchList_h
-
-#include "core/CoreExport.h"
-#include "core/dom/Touch.h"
-#include "platform/bindings/ScriptWrappable.h"
-#include "platform/heap/Handle.h"
-#include "platform/wtf/Vector.h"
-
-namespace blink {
-
-class CORE_EXPORT TouchList final : public GarbageCollected<TouchList>,
-                                    public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static TouchList* Create() { return new TouchList; }
-
-  static TouchList* Create(const HeapVector<Member<Touch>>& touches) {
-    TouchList* list = new TouchList;
-    list->values_.AppendVector(touches);
-    return list;
-  }
-
-  static TouchList* Adopt(HeapVector<Member<Touch>>& touches) {
-    return new TouchList(touches);
-  }
-
-  unsigned length() const { return values_.size(); }
-
-  Touch* item(unsigned);
-  const Touch* item(unsigned) const;
-
-  void Append(Touch* touch) { values_.push_back(touch); }
-
-  DECLARE_TRACE();
-
- private:
-  TouchList() {}
-
-  TouchList(HeapVector<Member<Touch>>& touches) { values_.swap(touches); }
-
-  HeapVector<Member<Touch>> values_;
-};
-
-}  // namespace blink
-
-#endif  // TouchList_h
diff --git a/third_party/WebKit/Source/core/dom/TreeScopeTest.cpp b/third_party/WebKit/Source/core/dom/TreeScopeTest.cpp
index a1f695e..8def3f1 100644
--- a/third_party/WebKit/Source/core/dom/TreeScopeTest.cpp
+++ b/third_party/WebKit/Source/core/dom/TreeScopeTest.cpp
@@ -4,7 +4,7 @@
 
 #include "core/dom/TreeScope.h"
 
-#include "bindings/core/v8/StringOrDictionary.h"
+#include "bindings/core/v8/string_or_dictionary.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
 #include "core/dom/ShadowRoot.h"
diff --git a/third_party/WebKit/Source/core/dom/WorkletModulatorImpl.cpp b/third_party/WebKit/Source/core/dom/WorkletModulatorImpl.cpp
new file mode 100644
index 0000000..f1799220
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/WorkletModulatorImpl.cpp
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/dom/WorkletModulatorImpl.h"
+
+#include "core/loader/modulescript/WorkletModuleScriptFetcher.h"
+#include "core/workers/WorkletGlobalScope.h"
+
+namespace blink {
+
+ModulatorImplBase* WorkletModulatorImpl::Create(
+    RefPtr<ScriptState> script_state) {
+  return new WorkletModulatorImpl(std::move(script_state));
+}
+
+WorkletModulatorImpl::WorkletModulatorImpl(RefPtr<ScriptState> script_state)
+    : ModulatorImplBase(std::move(script_state)) {}
+
+ModuleScriptFetcher* WorkletModulatorImpl::CreateModuleScriptFetcher() {
+  auto global_scope = ToWorkletGlobalScope(GetExecutionContext());
+  return new WorkletModuleScriptFetcher(
+      global_scope->ModuleResponsesMapProxy());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/WorkletModulatorImpl.h b/third_party/WebKit/Source/core/dom/WorkletModulatorImpl.h
new file mode 100644
index 0000000..26fe7df
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/WorkletModulatorImpl.h
@@ -0,0 +1,33 @@
+// 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 WorkletModulatorImpl_h
+#define WorkletModulatorImpl_h
+
+#include "core/dom/ModulatorImplBase.h"
+
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class ModuleScriptFetcher;
+class ScriptState;
+
+// WorkletModulatorImpl is the Modulator implementation used in worklet contexts
+// (that means, not main documents). Module operations depending on the Worklet
+// context should be implemented in this class, not in ModulatorImplBase.
+class WorkletModulatorImpl final : public ModulatorImplBase {
+ public:
+  static ModulatorImplBase* Create(RefPtr<ScriptState>);
+
+  // Implements Modulator.
+  ModuleScriptFetcher* CreateModuleScriptFetcher() override;
+
+ private:
+  explicit WorkletModulatorImpl(RefPtr<ScriptState>);
+};
+
+}  // namespace blink
+
+#endif  // WorkletModulatorImpl_h
diff --git a/third_party/WebKit/Source/core/dom/events/EventDispatcher.h b/third_party/WebKit/Source/core/dom/events/EventDispatcher.h
index 7fad899..b7622ef9 100644
--- a/third_party/WebKit/Source/core/dom/events/EventDispatcher.h
+++ b/third_party/WebKit/Source/core/dom/events/EventDispatcher.h
@@ -28,8 +28,8 @@
 #ifndef EventDispatcher_h
 #define EventDispatcher_h
 
-#include "core/dom/SimulatedClickOptions.h"
 #include "core/dom/events/EventDispatchResult.h"
+#include "core/dom/events/SimulatedClickOptions.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/RefPtr.h"
 
diff --git a/third_party/WebKit/Source/core/dom/events/EventPath.cpp b/third_party/WebKit/Source/core/dom/events/EventPath.cpp
index 2f63b7b4..546f589 100644
--- a/third_party/WebKit/Source/core/dom/events/EventPath.cpp
+++ b/third_party/WebKit/Source/core/dom/events/EventPath.cpp
@@ -29,12 +29,12 @@
 #include "core/EventNames.h"
 #include "core/dom/Document.h"
 #include "core/dom/ShadowRoot.h"
-#include "core/dom/Touch.h"
-#include "core/dom/TouchList.h"
 #include "core/dom/V0InsertionPoint.h"
 #include "core/events/TouchEvent.h"
 #include "core/events/TouchEventContext.h"
 #include "core/html/HTMLSlotElement.h"
+#include "core/input/Touch.h"
+#include "core/input/TouchList.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/dom/events/EventTarget.cpp b/third_party/WebKit/Source/core/dom/events/EventTarget.cpp
index 5946098c..65a99a78 100644
--- a/third_party/WebKit/Source/core/dom/events/EventTarget.cpp
+++ b/third_party/WebKit/Source/core/dom/events/EventTarget.cpp
@@ -32,12 +32,12 @@
 #include "core/dom/events/EventTarget.h"
 
 #include <memory>
-#include "bindings/core/v8/AddEventListenerOptionsOrBoolean.h"
-#include "bindings/core/v8/EventListenerOptionsOrBoolean.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptEventListener.h"
 #include "bindings/core/v8/SourceLocation.h"
 #include "bindings/core/v8/V8DOMActivityLogger.h"
+#include "bindings/core/v8/add_event_listener_options_or_boolean.h"
+#include "bindings/core/v8/event_listener_options_or_boolean.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/events/Event.h"
 #include "core/editing/Editor.h"
diff --git a/third_party/WebKit/Source/core/dom/events/NodeEventContext.cpp b/third_party/WebKit/Source/core/dom/events/NodeEventContext.cpp
index 770beeca..edca0ae 100644
--- a/third_party/WebKit/Source/core/dom/events/NodeEventContext.cpp
+++ b/third_party/WebKit/Source/core/dom/events/NodeEventContext.cpp
@@ -26,12 +26,12 @@
 
 #include "core/dom/events/NodeEventContext.h"
 
-#include "core/dom/TouchList.h"
 #include "core/dom/events/Event.h"
 #include "core/events/FocusEvent.h"
 #include "core/events/MouseEvent.h"
 #include "core/events/PointerEvent.h"
 #include "core/events/TouchEventContext.h"
+#include "core/input/TouchList.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/dom/SimulatedClickOptions.h b/third_party/WebKit/Source/core/dom/events/SimulatedClickOptions.h
similarity index 100%
rename from third_party/WebKit/Source/core/dom/SimulatedClickOptions.h
rename to third_party/WebKit/Source/core/dom/events/SimulatedClickOptions.h
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp
index 78f483b..5bb88cc 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -379,14 +379,22 @@
       is_handle_visible = event.Event().FromTouch();
   }
 
-  UpdateSelectionForMouseDownDispatchingSelectStart(
-      inner_node,
-      ExpandSelectionToRespectUserSelectAll(
+  // This applies the JavaScript selectstart handler, which can change the DOM.
+  // SelectionControllerTest_SelectStartHandlerRemovesElement makes this return
+  // false.
+  if (!UpdateSelectionForMouseDownDispatchingSelectStart(
           inner_node,
-          SelectionInFlatTree::Builder().Collapse(position_to_use).Build()),
-      TextGranularity::kCharacter,
-      is_handle_visible ? HandleVisibility::kVisible
-                        : HandleVisibility::kNotVisible);
+          ExpandSelectionToRespectUserSelectAll(
+              inner_node,
+              SelectionInFlatTree::Builder().Collapse(position_to_use).Build()),
+          TextGranularity::kCharacter,
+          is_handle_visible ? HandleVisibility::kVisible
+                            : HandleVisibility::kNotVisible)) {
+    // UpdateSelectionForMouseDownDispatchingSelectStart() returns false when
+    // the selectstart handler has prevented the default selection behavior from
+    // occurring.
+    return false;
+  }
 
   if (has_editable_style && event.Event().FromTouch()) {
     frame_->GetTextSuggestionController().HandlePotentialMisspelledWordTap(
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
index d6ef164..7a39a3ab 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
@@ -584,7 +584,7 @@
     return true;
 
   return base_.GetDocument() == &document && !base_.IsOrphan() &&
-         !extent_.IsOrphan();
+         extent_.GetDocument() == &document && !extent_.IsOrphan();
 }
 
 // TODO(yosin) This function breaks the invariant of this class.
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
index 8ab37ed..bdaca0d 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -2401,7 +2401,8 @@
                                Event*) {
   const VisibleSelection& selection =
       frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated();
-  if (!selection.IsNonOrphanedCaretOrRange() || !selection.IsContentEditable())
+  if (selection.IsNone() || !selection.IsValidFor(*(frame.GetDocument())) ||
+      !selection.IsContentEditable())
     return "";
   Element* format_block_element =
       FormatBlockCommand::ElementForFormatBlockCommand(
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp
index 77c2e24..3004a82 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp
@@ -176,7 +176,10 @@
 }
 
 void InsertParagraphSeparatorCommand::DoApply(EditingState* editing_state) {
-  if (!EndingVisibleSelection().IsNonOrphanedCaretOrRange())
+  // TODO(editing-dev): We shouldn't construct an
+  // InsertParagraphSeparatorCommand with none or invalid selection.
+  if (EndingVisibleSelection().IsNone() ||
+      !EndingVisibleSelection().IsValidFor(GetDocument()))
     return;
 
   Position insertion_position = EndingVisibleSelection().Start();
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
index 45e531ba..3665c3b 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
@@ -147,7 +147,10 @@
 void InsertTextCommand::DoApply(EditingState* editing_state) {
   DCHECK_EQ(text_.find('\n'), kNotFound);
 
-  if (!EndingVisibleSelection().IsNonOrphanedCaretOrRange())
+  // TODO(editing-dev): We shouldn't construct an InsertTextCommand with none or
+  // invalid selection.
+  if (EndingVisibleSelection().IsNone() ||
+      !EndingVisibleSelection().IsValidFor(GetDocument()))
     return;
 
   // Delete the current selection.
diff --git a/third_party/WebKit/Source/core/editing/commands/RemoveFormatCommand.cpp b/third_party/WebKit/Source/core/editing/commands/RemoveFormatCommand.cpp
index 67c3b5a..7461479bd 100644
--- a/third_party/WebKit/Source/core/editing/commands/RemoveFormatCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/RemoveFormatCommand.cpp
@@ -57,10 +57,9 @@
 
 void RemoveFormatCommand::DoApply(EditingState* editing_state) {
   LocalFrame* frame = GetDocument().GetFrame();
-
-  if (!frame->Selection()
-           .ComputeVisibleSelectionInDOMTreeDeprecated()
-           .IsNonOrphanedCaretOrRange())
+  const VisibleSelection selection =
+      frame->Selection().ComputeVisibleSelectionInDOMTreeDeprecated();
+  if (selection.IsNone() || !selection.IsValidFor(GetDocument()))
     return;
 
   // Get the default style for this editable root, it's the style that we'll
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index 1d814dff..a8d11a2 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -453,7 +453,8 @@
 }
 
 void TypingCommand::DoApply(EditingState* editing_state) {
-  if (!EndingVisibleSelection().IsNonOrphanedCaretOrRange())
+  if (EndingVisibleSelection().IsNone() ||
+      !EndingVisibleSelection().IsValidFor(GetDocument()))
     return;
 
   if (command_type_ == kDeleteKey) {
diff --git a/third_party/WebKit/Source/core/events/TouchEvent.h b/third_party/WebKit/Source/core/events/TouchEvent.h
index c3e2e01..3665213 100644
--- a/third_party/WebKit/Source/core/events/TouchEvent.h
+++ b/third_party/WebKit/Source/core/events/TouchEvent.h
@@ -28,10 +28,10 @@
 #define TouchEvent_h
 
 #include "core/CoreExport.h"
-#include "core/dom/TouchList.h"
 #include "core/dom/events/EventDispatchMediator.h"
 #include "core/events/TouchEventInit.h"
 #include "core/events/UIEventWithKeyState.h"
+#include "core/input/TouchList.h"
 #include "platform/graphics/TouchAction.h"
 #include "public/platform/WebCoalescedInputEvent.h"
 #include "public/platform/WebTouchEvent.h"
diff --git a/third_party/WebKit/Source/core/events/TouchEventContext.cpp b/third_party/WebKit/Source/core/events/TouchEventContext.cpp
index 4892a3be..61a7c78 100644
--- a/third_party/WebKit/Source/core/events/TouchEventContext.cpp
+++ b/third_party/WebKit/Source/core/events/TouchEventContext.cpp
@@ -26,9 +26,9 @@
 
 #include "core/events/TouchEventContext.h"
 
-#include "core/dom/TouchList.h"
 #include "core/dom/events/Event.h"
 #include "core/events/TouchEvent.h"
+#include "core/input/TouchList.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
index 07611e8..445fd27 100644
--- a/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
+++ b/third_party/WebKit/Source/core/events/WebInputEventConversion.cpp
@@ -30,8 +30,6 @@
 
 #include "core/events/WebInputEventConversion.h"
 
-#include "core/dom/Touch.h"
-#include "core/dom/TouchList.h"
 #include "core/events/GestureEvent.h"
 #include "core/events/KeyboardEvent.h"
 #include "core/events/MouseEvent.h"
@@ -39,6 +37,8 @@
 #include "core/events/WheelEvent.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/VisualViewport.h"
+#include "core/input/Touch.h"
+#include "core/input/TouchList.h"
 #include "core/layout/api/LayoutItem.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
diff --git a/third_party/WebKit/Source/core/events/WebInputEventConversionTest.cpp b/third_party/WebKit/Source/core/events/WebInputEventConversionTest.cpp
index fdd8a81..9e17e39 100644
--- a/third_party/WebKit/Source/core/events/WebInputEventConversionTest.cpp
+++ b/third_party/WebKit/Source/core/events/WebInputEventConversionTest.cpp
@@ -30,8 +30,6 @@
 
 #include "core/events/WebInputEventConversion.h"
 
-#include "core/dom/Touch.h"
-#include "core/dom/TouchList.h"
 #include "core/events/GestureEvent.h"
 #include "core/events/KeyboardEvent.h"
 #include "core/events/MouseEvent.h"
@@ -43,6 +41,8 @@
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/VisualViewport.h"
 #include "core/frame/WebLocalFrameImpl.h"
+#include "core/input/Touch.h"
+#include "core/input/TouchList.h"
 #include "core/layout/api/LayoutViewItem.h"
 #include "core/page/Page.h"
 #include "platform/geometry/IntSize.h"
diff --git a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
index f700cd6e..f86369f 100644
--- a/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebDevToolsAgentImpl.cpp
@@ -669,7 +669,8 @@
   return method == "Debugger.pause" || method == "Debugger.setBreakpoint" ||
          method == "Debugger.setBreakpointByUrl" ||
          method == "Debugger.removeBreakpoint" ||
-         method == "Debugger.setBreakpointsActive";
+         method == "Debugger.setBreakpointsActive" ||
+         method == "Performance.getMetrics";
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/fileapi/Blob.h b/third_party/WebKit/Source/core/fileapi/Blob.h
index b65c412..29d81fc 100644
--- a/third_party/WebKit/Source/core/fileapi/Blob.h
+++ b/third_party/WebKit/Source/core/fileapi/Blob.h
@@ -31,7 +31,7 @@
 #ifndef Blob_h
 #define Blob_h
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferViewOrBlobOrUSVString.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
 #include "core/CoreExport.h"
 #include "core/html/URLRegistry.h"
 #include "core/imagebitmap/ImageBitmapSource.h"
diff --git a/third_party/WebKit/Source/core/fileapi/File.h b/third_party/WebKit/Source/core/fileapi/File.h
index da78499..8b089c5 100644
--- a/third_party/WebKit/Source/core/fileapi/File.h
+++ b/third_party/WebKit/Source/core/fileapi/File.h
@@ -26,7 +26,7 @@
 #ifndef File_h
 #define File_h
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferViewOrBlobOrUSVString.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
 #include "core/CoreExport.h"
 #include "core/fileapi/Blob.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/core/fileapi/FileReader.cpp b/third_party/WebKit/Source/core/fileapi/FileReader.cpp
index b6bc2ce..a614ae0d 100644
--- a/third_party/WebKit/Source/core/fileapi/FileReader.cpp
+++ b/third_party/WebKit/Source/core/fileapi/FileReader.cpp
@@ -31,7 +31,7 @@
 #include "core/fileapi/FileReader.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/StringOrArrayBuffer.h"
+#include "bindings/core/v8/string_or_array_buffer.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
diff --git a/third_party/WebKit/Source/core/frame/DeviceSingleWindowEventController.cpp b/third_party/WebKit/Source/core/frame/DeviceSingleWindowEventController.cpp
index fd72574..a0525ec 100644
--- a/third_party/WebKit/Source/core/frame/DeviceSingleWindowEventController.cpp
+++ b/third_party/WebKit/Source/core/frame/DeviceSingleWindowEventController.cpp
@@ -12,7 +12,7 @@
 
 DeviceSingleWindowEventController::DeviceSingleWindowEventController(
     Document& document)
-    : PlatformEventController(document.GetFrame()),
+    : PlatformEventController(&document),
       needs_checking_null_events_(true),
       document_(document) {
   document.domWindow()->RegisterEventListenerObserver(this);
diff --git a/third_party/WebKit/Source/core/frame/PlatformEventController.cpp b/third_party/WebKit/Source/core/frame/PlatformEventController.cpp
index 492b3726..08b354c 100644
--- a/third_party/WebKit/Source/core/frame/PlatformEventController.cpp
+++ b/third_party/WebKit/Source/core/frame/PlatformEventController.cpp
@@ -8,11 +8,13 @@
 
 namespace blink {
 
-PlatformEventController::PlatformEventController(LocalFrame* frame)
-    : PageVisibilityObserver(frame ? frame->GetPage() : nullptr),
+PlatformEventController::PlatformEventController(Document* document)
+    : PageVisibilityObserver(document && document->GetFrame()
+                                 ? document->GetFrame()->GetPage()
+                                 : nullptr),
       has_event_listener_(false),
       is_active_(false),
-      timer_(TaskRunnerHelper::Get(TaskType::kUnspecedTimer, frame),
+      timer_(TaskRunnerHelper::Get(TaskType::kUnspecedTimer, document),
              this,
              &PlatformEventController::OneShotCallback) {}
 
diff --git a/third_party/WebKit/Source/core/frame/PlatformEventController.h b/third_party/WebKit/Source/core/frame/PlatformEventController.h
index ea8e8c7..4db113b5 100644
--- a/third_party/WebKit/Source/core/frame/PlatformEventController.h
+++ b/third_party/WebKit/Source/core/frame/PlatformEventController.h
@@ -26,7 +26,7 @@
   virtual void DidUpdateData() = 0;
 
  protected:
-  explicit PlatformEventController(LocalFrame*);
+  explicit PlatformEventController(Document*);
   virtual ~PlatformEventController();
 
   virtual void RegisterWithDispatcher() = 0;
diff --git a/third_party/WebKit/Source/core/frame/ReportingObserver.h b/third_party/WebKit/Source/core/frame/ReportingObserver.h
index 7047b97..408dc52 100644
--- a/third_party/WebKit/Source/core/frame/ReportingObserver.h
+++ b/third_party/WebKit/Source/core/frame/ReportingObserver.h
@@ -5,7 +5,7 @@
 #ifndef ReportingObserver_h
 #define ReportingObserver_h
 
-#include "bindings/core/v8/ReportingObserverCallback.h"
+#include "bindings/core/v8/reporting_observer_callback.h"
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/wtf/Vector.h"
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrix.h b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
index fa0ac68..0d7ea4a 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrix.h
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrix.h
@@ -6,7 +6,7 @@
 #define DOMMatrix_h
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/StringOrUnrestrictedDoubleSequence.h"
+#include "bindings/core/v8/string_or_unrestricted_double_sequence.h"
 #include "core/geometry/DOMMatrixInit.h"
 #include "core/geometry/DOMMatrixReadOnly.h"
 #include "core/typed_arrays/ArrayBufferViewHelpers.h"
diff --git a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h
index 69495e5..e44e39a 100644
--- a/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h
+++ b/third_party/WebKit/Source/core/geometry/DOMMatrixReadOnly.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/StringOrUnrestrictedDoubleSequence.h"
+#include "bindings/core/v8/string_or_unrestricted_double_sequence.h"
 #include "core/typed_arrays/ArrayBufferViewHelpers.h"
 #include "core/typed_arrays/DOMTypedArray.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/core/html/FormData.h b/third_party/WebKit/Source/core/html/FormData.h
index 3585d5c3..3118748 100644
--- a/third_party/WebKit/Source/core/html/FormData.h
+++ b/third_party/WebKit/Source/core/html/FormData.h
@@ -31,8 +31,8 @@
 #ifndef FormData_h
 #define FormData_h
 
-#include "bindings/core/v8/FileOrUSVString.h"
 #include "bindings/core/v8/Iterable.h"
+#include "bindings/core/v8/file_or_usv_string.h"
 #include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/network/EncodedFormData.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLAllCollection.cpp b/third_party/WebKit/Source/core/html/HTMLAllCollection.cpp
index 5a72a3e..49f8075 100644
--- a/third_party/WebKit/Source/core/html/HTMLAllCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLAllCollection.cpp
@@ -25,7 +25,7 @@
 
 #include "core/html/HTMLAllCollection.h"
 
-#include "bindings/core/v8/NodeListOrElement.h"
+#include "bindings/core/v8/node_list_or_element.h"
 #include "core/dom/Element.h"
 #include "core/dom/StaticNodeList.h"
 
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp
index d6c0602..5297ee3 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp
@@ -24,7 +24,7 @@
 
 #include "core/html/HTMLFormControlsCollection.h"
 
-#include "bindings/core/v8/RadioNodeListOrElement.h"
+#include "bindings/core/v8/radio_node_list_or_element.h"
 #include "core/HTMLNames.h"
 #include "core/frame/UseCounter.h"
 #include "core/html/HTMLFormElement.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
index c1f0492..8a10a78 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
@@ -26,9 +26,9 @@
 #include "core/html/HTMLFormElement.h"
 
 #include <limits>
-#include "bindings/core/v8/RadioNodeListOrElement.h"
 #include "bindings/core/v8/ScriptController.h"
 #include "bindings/core/v8/ScriptEventListener.h"
+#include "bindings/core/v8/radio_node_list_or_element.h"
 #include "core/HTMLNames.h"
 #include "core/dom/Attribute.h"
 #include "core/dom/Document.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index aa65902..c23fe49 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -338,7 +338,6 @@
 
 void HTMLInputElement::HandleFocusEvent(Element* old_focused_element,
                                         WebFocusType type) {
-  input_type_view_->HandleFocusEvent(old_focused_element, type);
   input_type_->EnableSecureTextInput();
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp b/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp
index 3e32106..1a91b23e 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp
@@ -23,9 +23,9 @@
 
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/HTMLElementOrLong.h"
-#include "bindings/core/v8/HTMLOptionElementOrHTMLOptGroupElement.h"
-#include "bindings/core/v8/NodeListOrElement.h"
+#include "bindings/core/v8/html_element_or_long.h"
+#include "bindings/core/v8/html_option_element_or_html_opt_group_element.h"
+#include "bindings/core/v8/node_list_or_element.h"
 #include "core/dom/StaticNodeList.h"
 #include "core/frame/UseCounter.h"
 #include "core/html/HTMLOptionElement.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
index 3cda11d..2d0d8f554 100644
--- a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
@@ -24,8 +24,8 @@
 #include "core/html/HTMLScriptElement.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/HTMLScriptElementOrSVGScriptElement.h"
 #include "bindings/core/v8/ScriptEventListener.h"
+#include "bindings/core/v8/html_script_element_or_svg_script_element.h"
 #include "core/HTMLNames.h"
 #include "core/dom/Attribute.h"
 #include "core/dom/Document.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index a1320d2b..dee364c 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -31,8 +31,8 @@
 
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/HTMLElementOrLong.h"
-#include "bindings/core/v8/HTMLOptionElementOrHTMLOptGroupElement.h"
+#include "bindings/core/v8/html_element_or_long.h"
+#include "bindings/core/v8/html_option_element_or_html_opt_group_element.h"
 #include "build/build_config.h"
 #include "core/HTMLNames.h"
 #include "core/dom/AXObjectCache.h"
diff --git a/third_party/WebKit/Source/core/html/ImageData.cpp b/third_party/WebKit/Source/core/html/ImageData.cpp
index 66d63a1c..b70297c8 100644
--- a/third_party/WebKit/Source/core/html/ImageData.cpp
+++ b/third_party/WebKit/Source/core/html/ImageData.cpp
@@ -463,7 +463,7 @@
                                            EventTarget& event_target,
                                            Optional<IntRect> crop_rect,
                                            const ImageBitmapOptions& options) {
-  if (data()->BufferBase()->IsNeutered()) {
+  if (BufferBase()->IsNeutered()) {
     return ScriptPromise::RejectWithDOMException(
         script_state,
         DOMException::Create(kInvalidStateError,
diff --git a/third_party/WebKit/Source/core/html/ImageData.h b/third_party/WebKit/Source/core/html/ImageData.h
index b47a126..5ab03921 100644
--- a/third_party/WebKit/Source/core/html/ImageData.h
+++ b/third_party/WebKit/Source/core/html/ImageData.h
@@ -29,7 +29,7 @@
 #ifndef ImageData_h
 #define ImageData_h
 
-#include "bindings/core/v8/Uint8ClampedArrayOrUint16ArrayOrFloat32Array.h"
+#include "bindings/core/v8/uint8_clamped_array_or_uint16_array_or_float32_array.h"
 #include "core/CoreExport.h"
 #include "core/html/ImageDataColorSettings.h"
 #include "core/html/canvas/CanvasRenderingContext.h"
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
index 90f70d46..5bceb209 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
@@ -7,6 +7,7 @@
 #include "build/build_config.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
+#include "core/dom/ExecutionContext.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/fileapi/Blob.h"
 #include "platform/CrossThreadFunctional.h"
@@ -153,10 +154,10 @@
     const IntSize& size,
     BlobCallback* callback,
     double start_time,
-    Document* document) {
+    ExecutionContext* context) {
   return new CanvasAsyncBlobCreator(
       unpremultiplied_rgba_image_data, ConvertMimeTypeStringToEnum(mime_type),
-      size, callback, start_time, document, nullptr);
+      size, callback, start_time, context, nullptr);
 }
 
 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::Create(
@@ -164,11 +165,11 @@
     const String& mime_type,
     const IntSize& size,
     double start_time,
-    Document* document,
+    ExecutionContext* context,
     ScriptPromiseResolver* resolver) {
   return new CanvasAsyncBlobCreator(
       unpremultiplied_rgba_image_data, ConvertMimeTypeStringToEnum(mime_type),
-      size, nullptr, start_time, document, resolver);
+      size, nullptr, start_time, context, resolver);
 }
 
 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(DOMUint8ClampedArray* data,
@@ -176,10 +177,10 @@
                                                const IntSize& size,
                                                BlobCallback* callback,
                                                double start_time,
-                                               Document* document,
+                                               ExecutionContext* context,
                                                ScriptPromiseResolver* resolver)
     : data_(data),
-      document_(document),
+      context_(context),
       mime_type_(mime_type),
       start_time_(start_time),
       elapsed_time_(0),
@@ -193,9 +194,9 @@
   src_data_.reset(info, data_->Data(), rowBytes);
   idle_task_status_ = kIdleTaskNotSupported;
   num_rows_completed_ = 0;
-  if (document) {
+  if (context->IsDocument()) {
     parent_frame_task_runner_ =
-        ParentFrameTaskRunners::Create(*document->GetFrame());
+        ParentFrameTaskRunners::Create(*ToDocument(context)->GetFrame());
   }
   if (script_promise_resolver_) {
     function_type_ = kOffscreenCanvasToBlobPromise;
@@ -210,7 +211,7 @@
   // Eagerly let go of references to prevent retention of these
   // resources while any remaining posted tasks are queued.
   data_.Clear();
-  document_.Clear();
+  context_.Clear();
   parent_frame_task_runner_.Clear();
   callback_.Clear();
   script_promise_resolver_.Clear();
@@ -226,7 +227,7 @@
       IntSize size(src_data_.width(), src_data_.height());
       if (!ImageDataBuffer(size, data_->Data())
                .EncodeImage("image/webp", quality, &encoded_image_)) {
-        TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+        TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
             ->PostTask(
                 BLINK_FROM_HERE,
                 WTF::Bind(&CanvasAsyncBlobCreator::CreateNullAndReturnResult,
@@ -234,7 +235,7 @@
 
         return;
       }
-      TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+      TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
           ->PostTask(
               BLINK_FROM_HERE,
               WTF::Bind(&CanvasAsyncBlobCreator::CreateBlobAndReturnResult,
@@ -315,7 +316,7 @@
   elapsed_time_ += (WTF::MonotonicallyIncreasingTime() - start_time);
   RecordElapsedTimeHistogram(kIdleEncodeDuration, mime_type_, elapsed_time_);
   if (IsDeadlineNearOrPassed(deadline_seconds)) {
-    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
         ->PostTask(BLINK_FROM_HERE,
                    WTF::Bind(&CanvasAsyncBlobCreator::CreateBlobAndReturnResult,
                              WrapPersistent(this)));
@@ -340,7 +341,7 @@
   if (IsMainThread()) {
     this->CreateBlobAndReturnResult();
   } else {
-    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
         ->PostTask(
             BLINK_FROM_HERE,
             CrossThreadBind(&CanvasAsyncBlobCreator::CreateBlobAndReturnResult,
@@ -358,7 +359,7 @@
   Blob* result_blob = Blob::Create(encoded_image_.data(), encoded_image_.size(),
                                    ConvertMimeTypeEnumToString(mime_type_));
   if (function_type_ == kHTMLCanvasToBlobCallback) {
-    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
         ->PostTask(BLINK_FROM_HERE, WTF::Bind(&BlobCallback::handleEvent,
                                               WrapPersistent(callback_.Get()),
                                               WrapPersistent(result_blob)));
@@ -374,7 +375,7 @@
   if (function_type_ == kHTMLCanvasToBlobCallback) {
     DCHECK(IsMainThread());
     RecordIdleTaskStatusHistogram(idle_task_status_);
-    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
         ->PostTask(BLINK_FROM_HERE,
                    WTF::Bind(&BlobCallback::handleEvent,
                              WrapPersistent(callback_.Get()), nullptr));
@@ -452,7 +453,7 @@
 
     DCHECK(mime_type_ == kMimeTypePng || mime_type_ == kMimeTypeJpeg);
     if (InitializeEncoder(quality)) {
-      TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+      TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
           ->PostTask(
               BLINK_FROM_HERE,
               WTF::Bind(&CanvasAsyncBlobCreator::ForceEncodeRowsOnCurrentThread,
@@ -477,7 +478,7 @@
     SignalTaskSwitchInCompleteTimeoutEventForTesting();
 
     DCHECK(mime_type_ == kMimeTypePng || mime_type_ == kMimeTypeJpeg);
-    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+    TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
         ->PostTask(
             BLINK_FROM_HERE,
             WTF::Bind(&CanvasAsyncBlobCreator::ForceEncodeRowsOnCurrentThread,
@@ -493,13 +494,13 @@
     const WebTraceLocation& location,
     WTF::Closure task,
     double delay_ms) {
-  TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, document_)
+  TaskRunnerHelper::Get(TaskType::kCanvasBlobSerialization, context_)
       ->PostDelayedTask(location, std::move(task),
                         TimeDelta::FromMillisecondsD(delay_ms));
 }
 
 DEFINE_TRACE(CanvasAsyncBlobCreator) {
-  visitor->Trace(document_);
+  visitor->Trace(context_);
   visitor->Trace(data_);
   visitor->Trace(callback_);
   visitor->Trace(parent_frame_task_runner_);
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
index f6998752..d4b6ffa 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
@@ -20,7 +20,7 @@
 
 namespace blink {
 
-class Document;
+class ExecutionContext;
 
 class CORE_EXPORT CanvasAsyncBlobCreator
     : public GarbageCollectedFinalized<CanvasAsyncBlobCreator> {
@@ -31,13 +31,13 @@
       const IntSize&,
       BlobCallback*,
       double start_time,
-      Document*);
+      ExecutionContext*);
   static CanvasAsyncBlobCreator* Create(
       DOMUint8ClampedArray* unpremultiplied_rgba_image_data,
       const String& mime_type,
       const IntSize&,
       double start_time,
-      Document*,
+      ExecutionContext*,
       ScriptPromiseResolver*);
   void ScheduleAsyncBlobCreation(const double& quality);
   virtual ~CanvasAsyncBlobCreator();
@@ -78,7 +78,7 @@
                          const IntSize&,
                          BlobCallback*,
                          double,
-                         Document*,
+                         ExecutionContext*,
                          ScriptPromiseResolver*);
   // Methods are virtual for unit testing
   virtual void ScheduleInitiateEncoding(double quality);
@@ -102,7 +102,7 @@
   std::unique_ptr<ImageEncoder> encoder_;
   Vector<unsigned char> encoded_image_;
   int num_rows_completed_;
-  Member<Document> document_;
+  Member<ExecutionContext> context_;
 
   SkPixmap src_data_;
   const MimeType mime_type_;
diff --git a/third_party/WebKit/Source/core/html/custom/CustomElementUpgradeSorterTest.cpp b/third_party/WebKit/Source/core/html/custom/CustomElementUpgradeSorterTest.cpp
index 9ae8065..9e5e58f3 100644
--- a/third_party/WebKit/Source/core/html/custom/CustomElementUpgradeSorterTest.cpp
+++ b/third_party/WebKit/Source/core/html/custom/CustomElementUpgradeSorterTest.cpp
@@ -6,8 +6,8 @@
 
 #include <memory>
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/StringOrDictionary.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/string_or_dictionary.h"
 #include "core/HTMLNames.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
diff --git a/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp b/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp
index 9e66a4a1..1cdc2f9 100644
--- a/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp
+++ b/third_party/WebKit/Source/core/html/forms/InputTypeView.cpp
@@ -108,8 +108,6 @@
   return true;
 }
 
-void InputTypeView::HandleFocusEvent(Element*, WebFocusType) {}
-
 void InputTypeView::HandleBlurEvent() {}
 
 void InputTypeView::HandleFocusInEvent(Element*, WebFocusType) {}
diff --git a/third_party/WebKit/Source/core/html/forms/InputTypeView.h b/third_party/WebKit/Source/core/html/forms/InputTypeView.h
index 54b7d04..8e7cb41 100644
--- a/third_party/WebKit/Source/core/html/forms/InputTypeView.h
+++ b/third_party/WebKit/Source/core/html/forms/InputTypeView.h
@@ -92,7 +92,6 @@
   virtual bool ShouldSubmitImplicitly(Event*);
   virtual HTMLFormElement* FormForSubmission() const;
   virtual bool HasCustomFocusLogic() const;
-  virtual void HandleFocusEvent(Element* old_focused_element, WebFocusType);
   virtual void HandleFocusInEvent(Element* old_focused_element, WebFocusType);
   virtual void HandleBlurEvent();
   virtual void HandleDOMActivateEvent(Event*);
diff --git a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
index dfca2b9..e356893 100644
--- a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
@@ -251,11 +251,6 @@
   }
 }
 
-void TextFieldInputType::HandleFocusEvent(Element* old_focused_node,
-                                          WebFocusType focus_type) {
-  InputTypeView::HandleFocusEvent(old_focused_node, focus_type);
-}
-
 void TextFieldInputType::HandleBlurEvent() {
   InputTypeView::HandleBlurEvent();
   GetElement().EndEditing();
diff --git a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.h b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.h
index 9040e03..79fc671 100644
--- a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.h
@@ -60,7 +60,6 @@
   void DisabledAttributeChanged() override;
   void ReadonlyAttributeChanged() override;
   bool SupportsReadOnly() const override;
-  void HandleFocusEvent(Element* old_focused_node, WebFocusType) final;
   void HandleBlurEvent() final;
   String SanitizeValue(const String&) const override;
   void SetValue(const String&,
diff --git a/third_party/WebKit/Source/core/html/media/MediaDocument.cpp b/third_party/WebKit/Source/core/html/media/MediaDocument.cpp
index 7bbc7c8..85a70fe 100644
--- a/third_party/WebKit/Source/core/html/media/MediaDocument.cpp
+++ b/third_party/WebKit/Source/core/html/media/MediaDocument.cpp
@@ -25,8 +25,8 @@
 
 #include "core/html/media/MediaDocument.h"
 
-#include "bindings/core/v8/AddEventListenerOptionsOrBoolean.h"
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/add_event_listener_options_or_boolean.h"
 #include "core/HTMLNames.h"
 #include "core/dom/ElementTraversal.h"
 #include "core/dom/RawDataDocumentParser.h"
@@ -141,6 +141,8 @@
 
   body->AppendChild(media);
   root_element->AppendChild(head);
+  if (IsDetached())
+    return;  // DOM insertion events can detach the frame.
   root_element->AppendChild(body);
 
   did_build_document_structure_ = true;
diff --git a/third_party/WebKit/Source/core/html/track/TrackEvent.cpp b/third_party/WebKit/Source/core/html/track/TrackEvent.cpp
index c990b6e..5f97647 100644
--- a/third_party/WebKit/Source/core/html/track/TrackEvent.cpp
+++ b/third_party/WebKit/Source/core/html/track/TrackEvent.cpp
@@ -25,7 +25,7 @@
 
 #include "core/html/track/TrackEvent.h"
 
-#include "bindings/core/v8/VideoTrackOrAudioTrackOrTextTrack.h"
+#include "bindings/core/v8/video_track_or_audio_track_or_text_track.h"
 #include "core/html/track/AudioTrack.h"
 #include "core/html/track/TextTrack.h"
 #include "core/html/track/VideoTrack.h"
diff --git a/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp b/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp
index 9b0dd19b..2b48f693 100644
--- a/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp
+++ b/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp
@@ -29,9 +29,9 @@
 
 #include "core/html/track/vtt/VTTCue.h"
 
-#include "bindings/core/v8/DoubleOrAutoKeyword.h"
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/double_or_auto_keyword.h"
 #include "core/CSSPropertyNames.h"
 #include "core/CSSValueKeywords.h"
 #include "core/dom/DocumentFragment.h"
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
index 53e14e1..3e8b5116 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
@@ -313,16 +313,43 @@
   // a new SRGB SkImage). This is inefficient and also converts GPU-backed
   // images to CPU-backed. For now, we ignore this and let the images be in
   // null color space. This must be okay if color management is only supported
-  // for SRGB. This might be okay for converting null color space to other
-  // color spaces. Please see crbug.com/754713 for more details.
+  // for SRGB. Please see crbug.com/754713 for more details.
 
   if (!CanvasColorParams::ColorCorrectRenderingInAnyColorSpace())
     return image;
 
+  // If the image is still in legacy color mode (no color space info) use a
+  // slow code path to tag the image as SRGB. This is inefficient and
+  // problematic. We eventually need to replace this with a check for the
+  // color space information of the image (crbug.com/754713).
+  sk_sp<SkImage> sk_image = image->PaintImageForCurrentFrame().GetSkImage();
+  if (!sk_image->colorSpace()) {
+    SkImageInfo srgb_info =
+        SkImageInfo::Make(sk_image->width(), sk_image->height(),
+                          kN32_SkColorType, sk_image->alphaType(), nullptr);
+    size_t size =
+        sk_image->width() * sk_image->height() * srgb_info.bytesPerPixel();
+    sk_sp<SkData> srgb_data = SkData::MakeUninitialized(size);
+    if (srgb_data && srgb_data->size() == size) {
+      sk_sp<SkImage> srgb_image;
+      if (sk_image->readPixels(srgb_info, srgb_data->writable_data(),
+                               sk_image->width() * srgb_info.bytesPerPixel(), 0,
+                               0)) {
+        srgb_info = srgb_info.makeColorSpace(SkColorSpace::MakeSRGB());
+        srgb_image = SkImage::MakeRasterData(
+            srgb_info, srgb_data,
+            sk_image->width() * srgb_info.bytesPerPixel());
+      }
+      if (srgb_image)
+        image = StaticBitmapImage::Create(srgb_image);
+    }
+  }
+
   // Color correct the image. This code path uses SkImage::makeColorSpace(). If
   // the color space of the source image is nullptr, it will be assumed in SRGB.
-  return image->ConvertToColorSpace(options.color_params.GetSkColorSpace(),
-                                    SkTransferFunctionBehavior::kRespect);
+  return image->ConvertToColorSpace(
+      options.color_params.GetSkColorSpaceForSkSurfaces(),
+      SkTransferFunctionBehavior::kRespect);
 }
 
 RefPtr<StaticBitmapImage> MakeBlankImage(
@@ -605,13 +632,24 @@
     return;
   RefPtr<Uint8Array> image_pixels =
       Uint8Array::Create(std::move(array_buffer), 0, byte_length);
-  memcpy(image_pixels->Data(), cropped_data->BufferBase()->Data(), byte_length);
-
-  SkImageInfo info = SkImageInfo::Make(
-      cropped_data->width(), cropped_data->height(),
-      cropped_data->GetCanvasColorParams().GetSkColorType(),
-      kUnpremul_SkAlphaType,
-      cropped_data->GetCanvasColorParams().GetSkColorSpaceForSkSurfaces());
+  CanvasColorParams color_params = cropped_data->GetCanvasColorParams();
+  if (color_params.GetSkColorType() == kRGBA_F16_SkColorType) {
+    std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(
+        color_params.GetSkColorSpaceForSkSurfaces().get(),
+        color_params.GetSkColorSpaceForSkSurfaces().get());
+    xform->apply(SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat,
+                 image_pixels->Data(),
+                 SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat,
+                 cropped_data->BufferBase()->Data(),
+                 cropped_data->Size().Area(), kUnpremul_SkAlphaType);
+  } else {
+    memcpy(image_pixels->Data(), cropped_data->BufferBase()->Data(),
+           byte_length);
+  }
+  SkImageInfo info =
+      SkImageInfo::Make(cropped_data->width(), cropped_data->height(),
+                        color_params.GetSkColorType(), kUnpremul_SkAlphaType,
+                        color_params.GetSkColorSpaceForSkSurfaces());
 
   // If we are in color correct rendering mode but we only color correct to
   // SRGB, we don't do any color conversion when transferring the pixels from
@@ -861,7 +899,6 @@
                       std::move(paint_record), draw_dst_rect,
                       !image->WouldTaintOrigin(document->GetSecurityOrigin()),
                       WTF::Passed(std::move(passed_parsed_options))));
-
   return promise;
 }
 
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
index 3344bb3..ce88d7f2 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
@@ -32,9 +32,9 @@
 #define ImageBitmapFactories_h
 
 #include <memory>
-#include "bindings/core/v8/ImageBitmapSource.h"
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "bindings/core/v8/image_bitmap_source.h"
 #include "core/fileapi/FileReaderLoader.h"
 #include "core/fileapi/FileReaderLoaderClient.h"
 #include "core/frame/LocalDOMWindow.h"
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapTest.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapTest.cpp
index 69b3368..7f67522 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapTest.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapTest.cpp
@@ -110,9 +110,15 @@
   const ImageBitmapOptions default_options;
   HTMLImageElement* image_element =
       HTMLImageElement::Create(*Document::CreateForTest());
-  ImageResourceContent* image = ImageResourceContent::CreateLoaded(
-      StaticBitmapImage::Create(image_).Get());
-  image_element->SetImageForTest(image);
+  sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB();
+  SkImageInfo raster_image_info =
+      SkImageInfo::MakeN32Premul(5, 5, src_rgb_color_space);
+  sk_sp<SkSurface> surface(SkSurface::MakeRaster(raster_image_info));
+  sk_sp<SkImage> image = surface->makeImageSnapshot();
+  ImageResourceContent* original_image_resource =
+      ImageResourceContent::CreateLoaded(
+          StaticBitmapImage::Create(image).Get());
+  image_element->SetImageForTest(original_image_resource);
 
   Optional<IntRect> crop_rect =
       IntRect(0, 0, image_->width(), image_->height());
@@ -149,7 +155,7 @@
                 ->GetImage()
                 ->PaintImageForCurrentFrame()
                 .GetSkImage());
-  ASSERT_NE(image_bitmap_exterior_crop->BitmapImage()
+  ASSERT_EQ(image_bitmap_exterior_crop->BitmapImage()
                 ->PaintImageForCurrentFrame()
                 .GetSkImage(),
             image_element->CachedImage()
@@ -172,9 +178,14 @@
   RuntimeEnabledFeatures::SetColorCanvasExtensionsEnabled(true);
   HTMLImageElement* image =
       HTMLImageElement::Create(*Document::CreateForTest());
+  sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB();
+  SkImageInfo raster_image_info =
+      SkImageInfo::MakeN32Premul(5, 5, src_rgb_color_space);
+  sk_sp<SkSurface> raster_surface(SkSurface::MakeRaster(raster_image_info));
+  sk_sp<SkImage> raster_image = raster_surface->makeImageSnapshot();
   ImageResourceContent* original_image_resource =
       ImageResourceContent::CreateLoaded(
-          StaticBitmapImage::Create(image_).Get());
+          StaticBitmapImage::Create(raster_image).Get());
   image->SetImageForTest(original_image_resource);
 
   const ImageBitmapOptions default_options;
diff --git a/third_party/WebKit/Source/core/input/BUILD.gn b/third_party/WebKit/Source/core/input/BUILD.gn
index 2526d53..0086fb3 100644
--- a/third_party/WebKit/Source/core/input/BUILD.gn
+++ b/third_party/WebKit/Source/core/input/BUILD.gn
@@ -28,10 +28,14 @@
     "PointerEventManager.h",
     "ScrollManager.cpp",
     "ScrollManager.h",
+    "Touch.cpp",
+    "Touch.h",
     "TouchActionUtil.cpp",
     "TouchActionUtil.h",
     "TouchEventManager.cpp",
     "TouchEventManager.h",
+    "TouchList.cpp",
+    "TouchList.h",
   ]
 
   configs += [
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index fc51793..c5f50394 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -40,7 +40,6 @@
 #include "core/dom/FlatTreeTraversal.h"
 #include "core/dom/ShadowRoot.h"
 #include "core/dom/TaskRunnerHelper.h"
-#include "core/dom/TouchList.h"
 #include "core/dom/UserGestureIndicator.h"
 #include "core/dom/events/EventPath.h"
 #include "core/editing/EditingUtilities.h"
@@ -68,6 +67,7 @@
 #include "core/input/EventHandlingUtil.h"
 #include "core/input/InputDeviceCapabilities.h"
 #include "core/input/TouchActionUtil.h"
+#include "core/input/TouchList.h"
 #include "core/layout/HitTestRequest.h"
 #include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutView.h"
diff --git a/third_party/WebKit/Source/core/input/Touch.cpp b/third_party/WebKit/Source/core/input/Touch.cpp
new file mode 100644
index 0000000..2a2faf6e
--- /dev/null
+++ b/third_party/WebKit/Source/core/input/Touch.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/input/Touch.h"
+
+#include "core/frame/LocalFrame.h"
+#include "core/frame/LocalFrameView.h"
+#include "platform/geometry/FloatPoint.h"
+
+namespace blink {
+
+static FloatPoint ContentsOffset(LocalFrame* frame) {
+  if (!frame)
+    return FloatPoint();
+  LocalFrameView* frame_view = frame->View();
+  if (!frame_view)
+    return FloatPoint();
+  float scale = 1.0f / frame->PageZoomFactor();
+  return FloatPoint(frame_view->GetScrollOffset()).ScaledBy(scale);
+}
+
+Touch::Touch(LocalFrame* frame,
+             EventTarget* target,
+             int identifier,
+             const FloatPoint& screen_pos,
+             const FloatPoint& page_pos,
+             const FloatSize& radius,
+             float rotation_angle,
+             float force,
+             String region)
+    : target_(target),
+      identifier_(identifier),
+      client_pos_(page_pos - ContentsOffset(frame)),
+      screen_pos_(screen_pos),
+      page_pos_(page_pos),
+      radius_(radius),
+      rotation_angle_(rotation_angle),
+      force_(force),
+      region_(region) {
+  float scale_factor = frame ? frame->PageZoomFactor() : 1.0f;
+  absolute_location_ = LayoutPoint(page_pos.ScaledBy(scale_factor));
+}
+
+Touch::Touch(EventTarget* target,
+             int identifier,
+             const FloatPoint& client_pos,
+             const FloatPoint& screen_pos,
+             const FloatPoint& page_pos,
+             const FloatSize& radius,
+             float rotation_angle,
+             float force,
+             String region,
+             LayoutPoint absolute_location)
+    : target_(target),
+      identifier_(identifier),
+      client_pos_(client_pos),
+      screen_pos_(screen_pos),
+      page_pos_(page_pos),
+      radius_(radius),
+      rotation_angle_(rotation_angle),
+      force_(force),
+      region_(region),
+      absolute_location_(absolute_location) {}
+
+Touch::Touch(LocalFrame* frame, const TouchInit& initializer)
+    : target_(initializer.target()),
+      identifier_(initializer.identifier()),
+      client_pos_(FloatPoint(initializer.clientX(), initializer.clientY())),
+      screen_pos_(FloatPoint(initializer.screenX(), initializer.screenY())),
+      page_pos_(FloatPoint(initializer.pageX(), initializer.pageY())),
+      radius_(FloatSize(initializer.radiusX(), initializer.radiusY())),
+      rotation_angle_(initializer.rotationAngle()),
+      force_(initializer.force()),
+      region_(initializer.region()) {
+  float scale_factor = frame ? frame->PageZoomFactor() : 1.0f;
+  absolute_location_ = LayoutPoint(page_pos_.ScaledBy(scale_factor));
+}
+
+Touch* Touch::CloneWithNewTarget(EventTarget* event_target) const {
+  return new Touch(event_target, identifier_, client_pos_, screen_pos_,
+                   page_pos_, radius_, rotation_angle_, force_, region_,
+                   absolute_location_);
+}
+
+DEFINE_TRACE(Touch) {
+  visitor->Trace(target_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/input/Touch.h b/third_party/WebKit/Source/core/input/Touch.h
new file mode 100644
index 0000000..a2734a5
--- /dev/null
+++ b/third_party/WebKit/Source/core/input/Touch.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Touch_h
+#define Touch_h
+
+#include "core/CoreExport.h"
+#include "core/dom/Document.h"
+#include "core/dom/events/EventTarget.h"
+#include "core/input/TouchInit.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/geometry/FloatPoint.h"
+#include "platform/geometry/FloatSize.h"
+#include "platform/geometry/LayoutPoint.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class LocalFrame;
+
+class CORE_EXPORT Touch final : public GarbageCollectedFinalized<Touch>,
+                                public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static Touch* Create(LocalFrame* frame,
+                       EventTarget* target,
+                       int identifier,
+                       const FloatPoint& screen_pos,
+                       const FloatPoint& page_pos,
+                       const FloatSize& radius,
+                       float rotation_angle,
+                       float force,
+                       String region) {
+    return new Touch(frame, target, identifier, screen_pos, page_pos, radius,
+                     rotation_angle, force, region);
+  }
+
+  static Touch* Create(const Document& document, const TouchInit& initializer) {
+    return new Touch(document.GetFrame(), initializer);
+  }
+
+  // DOM Touch implementation
+  EventTarget* target() const { return target_.Get(); }
+  int identifier() const { return identifier_; }
+  double clientX() const { return client_pos_.X(); }
+  double clientY() const { return client_pos_.Y(); }
+  double screenX() const { return screen_pos_.X(); }
+  double screenY() const { return screen_pos_.Y(); }
+  double pageX() const { return page_pos_.X(); }
+  double pageY() const { return page_pos_.Y(); }
+  float radiusX() const { return radius_.Width(); }
+  float radiusY() const { return radius_.Height(); }
+  float rotationAngle() const { return rotation_angle_; }
+  float force() const { return force_; }
+  const String& region() const { return region_; }
+
+  // Blink-internal methods
+  const LayoutPoint& AbsoluteLocation() const { return absolute_location_; }
+  const FloatPoint& ScreenLocation() const { return screen_pos_; }
+  Touch* CloneWithNewTarget(EventTarget*) const;
+
+  DECLARE_TRACE();
+
+ private:
+  Touch(LocalFrame*,
+        EventTarget*,
+        int identifier,
+        const FloatPoint& screen_pos,
+        const FloatPoint& page_pos,
+        const FloatSize& radius,
+        float rotation_angle,
+        float force,
+        String region);
+
+  Touch(EventTarget*,
+        int identifier,
+        const FloatPoint& client_pos,
+        const FloatPoint& screen_pos,
+        const FloatPoint& page_pos,
+        const FloatSize& radius,
+        float rotation_angle,
+        float force,
+        String region,
+        LayoutPoint absolute_location);
+
+  Touch(LocalFrame*, const TouchInit&);
+
+  Member<EventTarget> target_;
+  int identifier_;
+  // Position relative to the viewport in CSS px.
+  FloatPoint client_pos_;
+  // Position relative to the screen in DIPs.
+  FloatPoint screen_pos_;
+  // Position relative to the page in CSS px.
+  FloatPoint page_pos_;
+  // Radius in CSS px.
+  FloatSize radius_;
+  float rotation_angle_;
+  float force_;
+  String region_;
+  // FIXME(rbyers): Shouldn't we be able to migrate callers to relying on
+  // screenPos, pagePos or clientPos? absoluteLocation appears to be the same as
+  // pagePos but without browser scale applied.
+  LayoutPoint absolute_location_;
+};
+
+}  // namespace blink
+
+#endif  // Touch_h
diff --git a/third_party/WebKit/Source/core/dom/Touch.idl b/third_party/WebKit/Source/core/input/Touch.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/Touch.idl
rename to third_party/WebKit/Source/core/input/Touch.idl
diff --git a/third_party/WebKit/Source/core/input/TouchEventManager.cpp b/third_party/WebKit/Source/core/input/TouchEventManager.cpp
index 15b5948e..7055f14c 100644
--- a/third_party/WebKit/Source/core/input/TouchEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/TouchEventManager.cpp
@@ -275,6 +275,8 @@
         if (last_coalesced_touch_event_.touches[i].id == web_pointer_event.id) {
           last_coalesced_touch_event_.touches[i] =
               CreateWebTouchPointFromWebPointerEvent(web_pointer_event, false);
+          last_coalesced_touch_event_.SetTimeStampSeconds(
+              web_pointer_event.TimeStampSeconds());
           found_existing_id = true;
           break;
         }
@@ -301,6 +303,8 @@
         if (last_coalesced_touch_event_.touches[i].id == web_pointer_event.id) {
           last_coalesced_touch_event_.touches[i] =
               CreateWebTouchPointFromWebPointerEvent(web_pointer_event, false);
+          last_coalesced_touch_event_.SetTimeStampSeconds(
+              web_pointer_event.TimeStampSeconds());
           result.AddCoalescedEvent(last_coalesced_touch_event_);
 
           // Remove up and canceled points.
diff --git a/third_party/WebKit/Source/core/dom/TouchInit.idl b/third_party/WebKit/Source/core/input/TouchInit.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/TouchInit.idl
rename to third_party/WebKit/Source/core/input/TouchInit.idl
diff --git a/third_party/WebKit/Source/core/input/TouchList.cpp b/third_party/WebKit/Source/core/input/TouchList.cpp
new file mode 100644
index 0000000..30b7ca73
--- /dev/null
+++ b/third_party/WebKit/Source/core/input/TouchList.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/input/TouchList.h"
+
+namespace blink {
+
+Touch* TouchList::item(unsigned index) {
+  if (index >= values_.size())
+    return nullptr;
+  return values_[index].Get();
+}
+
+const Touch* TouchList::item(unsigned index) const {
+  return const_cast<TouchList*>(this)->item(index);
+}
+
+DEFINE_TRACE(TouchList) {
+  visitor->Trace(values_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/input/TouchList.h b/third_party/WebKit/Source/core/input/TouchList.h
new file mode 100644
index 0000000..9dcbd19
--- /dev/null
+++ b/third_party/WebKit/Source/core/input/TouchList.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TouchList_h
+#define TouchList_h
+
+#include "core/CoreExport.h"
+#include "core/input/Touch.h"
+#include "platform/bindings/ScriptWrappable.h"
+#include "platform/heap/Handle.h"
+#include "platform/wtf/Vector.h"
+
+namespace blink {
+
+class CORE_EXPORT TouchList final : public GarbageCollected<TouchList>,
+                                    public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static TouchList* Create() { return new TouchList; }
+
+  static TouchList* Create(const HeapVector<Member<Touch>>& touches) {
+    TouchList* list = new TouchList;
+    list->values_.AppendVector(touches);
+    return list;
+  }
+
+  static TouchList* Adopt(HeapVector<Member<Touch>>& touches) {
+    return new TouchList(touches);
+  }
+
+  unsigned length() const { return values_.size(); }
+
+  Touch* item(unsigned);
+  const Touch* item(unsigned) const;
+
+  void Append(Touch* touch) { values_.push_back(touch); }
+
+  DECLARE_TRACE();
+
+ private:
+  TouchList() {}
+
+  TouchList(HeapVector<Member<Touch>>& touches) { values_.swap(touches); }
+
+  HeapVector<Member<Touch>> values_;
+};
+
+}  // namespace blink
+
+#endif  // TouchList_h
diff --git a/third_party/WebKit/Source/core/dom/TouchList.idl b/third_party/WebKit/Source/core/input/TouchList.idl
similarity index 100%
rename from third_party/WebKit/Source/core/dom/TouchList.idl
rename to third_party/WebKit/Source/core/input/TouchList.idl
diff --git a/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.cpp
index 188b4916..7c086eb 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.cpp
@@ -13,7 +13,6 @@
 #include "core/page/Page.h"
 #include "platform/geometry/DoubleRect.h"
 #include "platform/graphics/Color.h"
-#include "platform/scheduler/renderer/web_view_scheduler.h"
 #include "platform/wtf/Time.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebFloatPoint.h"
@@ -43,7 +42,9 @@
 InspectorEmulationAgent::InspectorEmulationAgent(
     WebLocalFrameImpl* web_local_frame_impl,
     Client* client)
-    : web_local_frame_(web_local_frame_impl), client_(client) {}
+    : web_local_frame_(web_local_frame_impl),
+      client_(client),
+      virtual_time_observer_registered_(false) {}
 
 InspectorEmulationAgent::~InspectorEmulationAgent() {}
 
@@ -79,6 +80,10 @@
   setEmulatedMedia(String());
   setCPUThrottlingRate(1);
   setDefaultBackgroundColorOverride(Maybe<protocol::DOM::RGBA>());
+  if (virtual_time_observer_registered_) {
+    web_local_frame_->View()->Scheduler()->RemoveVirtualTimeObserver(this);
+    virtual_time_observer_registered_ = false;
+  }
   return Response::OK();
 }
 
@@ -139,6 +144,10 @@
         WebViewScheduler::VirtualTimePolicy::DETERMINISTIC_LOADING);
   }
   web_local_frame_->View()->Scheduler()->EnableVirtualTime();
+  if (!virtual_time_observer_registered_) {
+    web_local_frame_->View()->Scheduler()->AddVirtualTimeObserver(this);
+    virtual_time_observer_registered_ = true;
+  }
 
   if (budget.isJust()) {
     WTF::TimeDelta budget_amount =
@@ -157,6 +166,11 @@
   GetFrontend()->virtualTimeBudgetExpired();
 }
 
+void InspectorEmulationAgent::OnVirtualTimePaused(
+    WTF::TimeDelta virtual_time_offset) {
+  GetFrontend()->virtualTimePaused(virtual_time_offset.InMilliseconds());
+}
+
 Response InspectorEmulationAgent::setDefaultBackgroundColorOverride(
     Maybe<protocol::DOM::RGBA> color) {
   if (!color.isJust()) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.h b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.h
index 3504843..830a7c7a 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.h
@@ -8,6 +8,8 @@
 #include "core/CoreExport.h"
 #include "core/inspector/InspectorBaseAgent.h"
 #include "core/inspector/protocol/Emulation.h"
+#include "platform/scheduler/renderer/web_view_scheduler.h"
+#include "platform/wtf/Time.h"
 
 namespace blink {
 
@@ -21,7 +23,8 @@
 }  // namespace protocol
 
 class CORE_EXPORT InspectorEmulationAgent final
-    : public InspectorBaseAgent<protocol::Emulation::Metainfo> {
+    : public InspectorBaseAgent<protocol::Emulation::Metainfo>,
+      public WebViewScheduler::VirtualTimeObserver {
   WTF_MAKE_NONCOPYABLE(InspectorEmulationAgent);
 
  public:
@@ -54,6 +57,9 @@
   protocol::Response disable() override;
   void Restore() override;
 
+  // scheduler::WebViewScheduler::VirtualTimeObserver implementation.
+  void OnVirtualTimePaused(WTF::TimeDelta virtual_time_offset) override;
+
   DECLARE_VIRTUAL_TRACE();
 
  private:
@@ -63,6 +69,7 @@
 
   Member<WebLocalFrameImpl> web_local_frame_;
   Client* client_;
+  bool virtual_time_observer_registered_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp
index ee0d68b..60699b1 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp
@@ -49,6 +49,7 @@
   instrumenting_agents_->addInspectorPerformanceAgent(this);
   Platform::Current()->CurrentThread()->AddTaskTimeObserver(this);
   task_start_time_ = 0;
+  script_start_time_ = 0;
   return Response::OK();
 }
 
@@ -84,8 +85,8 @@
   std::unique_ptr<protocol::Array<protocol::Performance::Metric>> result =
       protocol::Array<protocol::Performance::Metric>::create();
 
-  AppendMetric(result.get(), "Timestamp",
-               (TimeTicks::Now() - TimeTicks()).InSecondsF());
+  double now = (TimeTicks::Now() - TimeTicks()).InSecondsF();
+  AppendMetric(result.get(), "Timestamp", now);
 
   // Renderer instance counters.
   for (size_t i = 0; i < ARRAY_SIZE(kInstanceCounterNames); ++i) {
@@ -100,8 +101,14 @@
                static_cast<double>(recalc_style_count_));
   AppendMetric(result.get(), "LayoutDuration", layout_duration_);
   AppendMetric(result.get(), "RecalcStyleDuration", recalc_style_duration_);
-  AppendMetric(result.get(), "ScriptDuration", script_duration_);
-  AppendMetric(result.get(), "TaskDuration", task_duration_);
+  double script_duration = script_duration_;
+  if (script_start_time_)
+    script_duration += now - script_start_time_;
+  AppendMetric(result.get(), "ScriptDuration", script_duration);
+  double task_duration = task_duration_;
+  if (task_start_time_)
+    task_duration += now - task_start_time_;
+  AppendMetric(result.get(), "TaskDuration", task_duration);
 
   v8::HeapStatistics heap_statistics;
   V8PerIsolateData::MainThreadIsolate()->GetHeapStatistics(&heap_statistics);
@@ -135,22 +142,26 @@
 
 void InspectorPerformanceAgent::Will(const probe::CallFunction& probe) {
   if (!script_call_depth_++)
-    probe.CaptureStartTime();
+    script_start_time_ = probe.CaptureStartTime();
 }
 
 void InspectorPerformanceAgent::Did(const probe::CallFunction& probe) {
-  if (!--script_call_depth_)
-    script_duration_ += probe.Duration();
+  if (--script_call_depth_)
+    return;
+  script_duration_ += probe.Duration();
+  script_start_time_ = 0;
 }
 
 void InspectorPerformanceAgent::Will(const probe::ExecuteScript& probe) {
   if (!script_call_depth_++)
-    probe.CaptureStartTime();
+    script_start_time_ = probe.CaptureStartTime();
 }
 
 void InspectorPerformanceAgent::Did(const probe::ExecuteScript& probe) {
-  if (!--script_call_depth_)
-    script_duration_ += probe.Duration();
+  if (--script_call_depth_)
+    return;
+  script_duration_ += probe.Duration();
+  script_start_time_ = 0;
 }
 
 void InspectorPerformanceAgent::Will(const probe::RecalculateStyle& probe) {
@@ -182,6 +193,7 @@
                                                double end_time) {
   if (task_start_time_ == start_time)
     task_duration_ += end_time - start_time;
+  task_start_time_ = 0;
 }
 
 DEFINE_TRACE(InspectorPerformanceAgent) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.h b/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.h
index 427a6fa..81a4fe2 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.h
@@ -66,6 +66,7 @@
   double layout_duration_ = 0;
   double recalc_style_duration_ = 0;
   double script_duration_ = 0;
+  double script_start_time_ = 0;
   double task_duration_ = 0;
   double task_start_time_ = 0;
   unsigned long long layout_count_ = 0;
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index ccdaec4..070e291 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -1094,7 +1094,15 @@
             {
                 "name": "virtualTimeBudgetExpired",
                 "experimental": true,
-                "description": "Notification sent after the virual time budget for the current VirtualTimePolicy has run out."
+                "description": "Notification sent after the virtual time budget for the current VirtualTimePolicy has run out."
+            },
+            {
+                "name": "virtualTimePaused",
+                "experimental": true,
+                "parameters": [
+                    { "name": "virtualTimeElapsed", "type": "integer", "description": "The amount of virtual time that has elapsed in milliseconds since virtual time was first enabled." }
+                ],
+                "description": "Notification sent after the virtual time has paused."
             }
         ]
     },
diff --git a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
index cd0917e..73ffa93 100644
--- a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
+++ b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
@@ -91,7 +91,7 @@
                 "domain": "Emulation",
                 "include": ["forceViewport", "resetViewport", "resetPageScaleFactor", "setPageScaleFactor", "setScriptExecutionDisabled", "setTouchEmulationEnabled",
                             "setEmulatedMedia", "setCPUThrottlingRate", "setVirtualTimePolicy", "setDefaultBackgroundColorOverride"],
-                "include_events": ["virtualTimeBudgetExpired"]
+                "include_events": ["virtualTimeBudgetExpired", "virtualTimePaused"]
             },
             {
                 "domain": "Network",
diff --git a/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
index 69643fc6..b5537184 100644
--- a/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
@@ -6,8 +6,8 @@
 
 #include <algorithm>
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/IntersectionObserverCallback.h"
 #include "bindings/core/v8/V8IntersectionObserverDelegate.h"
+#include "bindings/core/v8/intersection_observer_callback.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSTokenizer.h"
 #include "core/dom/Element.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
index 9f0d932..1910300 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
@@ -4,8 +4,8 @@
 
 #include "core/layout/LayoutTestHelper.h"
 
-#include "bindings/core/v8/StringOrArrayBufferOrArrayBufferView.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/string_or_array_buffer_or_array_buffer_view.h"
 #include "core/css/FontFaceDescriptors.h"
 #include "core/css/FontFaceSetDocument.h"
 #include "core/html/HTMLIFrameElement.h"
diff --git a/third_party/WebKit/Source/core/layout/ng/geometry/ng_logical_offset.cc b/third_party/WebKit/Source/core/layout/ng/geometry/ng_logical_offset.cc
index 82f07bf..81ef994 100644
--- a/third_party/WebKit/Source/core/layout/ng/geometry/ng_logical_offset.cc
+++ b/third_party/WebKit/Source/core/layout/ng/geometry/ng_logical_offset.cc
@@ -103,7 +103,7 @@
 }
 
 String NGLogicalOffset::ToString() const {
-  return String::Format("%dx%d", inline_offset.ToInt(), block_offset.ToInt());
+  return String::Format("%d,%d", inline_offset.ToInt(), block_offset.ToInt());
 }
 
 std::ostream& operator<<(std::ostream& os, const NGLogicalOffset& value) {
diff --git a/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset.cc b/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset.cc
index 637d0df..208d5b0b 100644
--- a/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset.cc
+++ b/third_party/WebKit/Source/core/layout/ng/geometry/ng_physical_offset.cc
@@ -33,7 +33,7 @@
 }
 
 String NGPhysicalOffset::ToString() const {
-  return String::Format("%dx%d", left.ToInt(), top.ToInt());
+  return String::Format("%d,%d", left.ToInt(), top.ToInt());
 }
 
 std::ostream& operator<<(std::ostream& os, const NGPhysicalOffset& value) {
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
index 11f2263..ade606e 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
@@ -54,6 +54,12 @@
   LayoutUnit borders_paddings_block_start;
   LayoutUnit borders_paddings_block_end;
 
+  // The amount of expansion for justification.
+  // Not used in NG paint, only to copy to InlineTextBox::SetExpansion().
+  // TODO(layout-dev): crbug.com/714962 Remove once fragment painting is enabled
+  // by default.
+  int expansion = 0;
+
   // Create a box when the box is empty, for open/close tags.
   bool needs_box_when_empty = false;
 
@@ -130,6 +136,12 @@
                        LayoutUnit available_width,
                        LayoutUnit line_top);
 
+  // Start/end text offset of this line.
+  unsigned StartOffset() const { return start_offset_; }
+  unsigned EndOffset() const { return end_offset_; }
+  void SetStartOffset(unsigned offset) { start_offset_ = offset; }
+  void SetEndOffset(unsigned offset) { end_offset_ = offset; }
+
  private:
   const ComputedStyle* line_style_ = nullptr;
   NGInlineItemResults results_;
@@ -139,6 +151,9 @@
   LayoutUnit line_top_;
   LayoutUnit text_indent_;
 
+  unsigned start_offset_;
+  unsigned end_offset_;
+
   bool use_first_line_style_ = false;
   bool is_last_line_ = false;
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 8295db8..9cac3585 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -22,6 +22,7 @@
 #include "core/layout/ng/ng_space_utils.h"
 #include "core/layout/ng/ng_unpositioned_float.h"
 #include "core/style/ComputedStyle.h"
+#include "platform/fonts/shaping/ShapeResultSpacing.h"
 
 namespace blink {
 namespace {
@@ -138,7 +139,15 @@
     RefPtr<NGInlineBreakToken> break_token) {
   NGInlineItemResults* line_items = &line_info->Results();
 
+  // Apply justification before placing items, because it affects size/position
+  // of items, which are needed to compute inline static positions.
   const ComputedStyle& line_style = line_info->LineStyle();
+  ETextAlign text_align = line_style.GetTextAlign(line_info->IsLastLine());
+  if (text_align == ETextAlign::kJustify) {
+    if (!ApplyJustify(line_info))
+      text_align = ETextAlign::kStart;
+  }
+
   NGLineHeightMetrics line_metrics(line_style, baseline_type_);
   NGLineHeightMetrics line_metrics_with_leading = line_metrics;
   line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed());
@@ -174,6 +183,7 @@
         }
         text_builder.SetEndEffect(item_result.text_end_effect);
         text_builder.SetShapeResult(std::move(item_result.shape_result));
+        text_builder.SetExpansion(item_result.expansion);
       } else {
         DCHECK(!item.TextShapeResult());  // kControl or unit tests.
       }
@@ -256,16 +266,13 @@
   LayoutUnit inline_size = position;
   NGLogicalOffset offset(line_info->LineLeft(),
                          baseline - box_states_.LineBoxState().metrics.ascent);
-  LayoutUnit available_width = line_info->AvailableWidth();
-  if (LayoutUnit text_indent = line_info->TextIndent()) {
-    // Move the line box by indent. Negative indents are ink overflow, let the
-    // line box overflow from the container box.
-    if (IsLtr(Node().BaseDirection()))
-      offset.inline_offset += text_indent;
-    available_width -= text_indent;
+
+  // Other 'text-align' values than 'justify' move line boxes as a whole, but
+  // indivisual items do not change their relative position to the line box.
+  if (text_align != ETextAlign::kJustify) {
+    ApplyTextAlign(text_align, &offset.inline_offset, inline_size,
+                   line_info->AvailableWidth());
   }
-  ApplyTextAlign(line_style.GetTextAlign(line_info->IsLastLine()),
-                 &offset.inline_offset, inline_size, available_width);
 
   line_box.SetInlineSize(inline_size);
   container_builder_.AddChild(line_box.ToLineBoxFragment(), offset);
@@ -322,6 +329,49 @@
   return box_states_.OnCloseTag(item, line_box, box, baseline_type_);
 }
 
+// Justify the line. This changes the size of items by adding spacing.
+// Returns false if justification failed and should fall back to start-aligned.
+bool NGInlineLayoutAlgorithm::ApplyJustify(NGLineInfo* line_info) {
+  LayoutUnit inline_size;
+  for (const NGInlineItemResult& item_result : line_info->Results())
+    inline_size += item_result.inline_size;
+  LayoutUnit available_width = line_info->AvailableWidth();
+  LayoutUnit expansion = available_width - inline_size;
+  if (expansion <= 0)
+    return false;  // no expansion is needed.
+
+  const String line_text =
+      Node().Text(line_info->StartOffset(), line_info->EndOffset()).ToString();
+  ShapeResultSpacing<String> spacing(line_text);
+  spacing.SetExpansion(expansion, Node().BaseDirection(),
+                       line_info->LineStyle().GetTextJustify());
+  if (!spacing.HasExpansion())
+    return false;  // no expansion opportunities exist.
+
+  for (NGInlineItemResult& item_result : line_info->Results()) {
+    if (item_result.shape_result) {
+      // Mutate the existing shape result if only used here, if not create a
+      // copy.
+      RefPtr<ShapeResult> shape_result =
+          item_result.shape_result->MutableUnique();
+      DCHECK_GE(item_result.start_offset, line_info->StartOffset());
+      DCHECK_EQ(shape_result->NumCharacters(),
+                item_result.end_offset - item_result.start_offset);
+      LayoutUnit size_before_justify = item_result.inline_size;
+      shape_result->ApplySpacing(
+          spacing, item_result.start_offset - line_info->StartOffset() -
+                       shape_result->StartIndexForResult());
+      item_result.inline_size = shape_result->SnappedWidth();
+      item_result.expansion =
+          (item_result.inline_size - size_before_justify).ToInt();
+      item_result.shape_result = std::move(shape_result);
+    } else {
+      // TODO(kojii): Implement atomic inline.
+    }
+  }
+  return true;
+}
+
 void NGInlineLayoutAlgorithm::ApplyTextAlign(ETextAlign text_align,
                                              LayoutUnit* line_left,
                                              LayoutUnit inline_size,
@@ -366,7 +416,8 @@
         text_align = is_base_ltr ? ETextAlign::kRight : ETextAlign::kLeft;
         continue;
       case ETextAlign::kJustify:
-        // TODO(kojii): Implement.
+        // Justification is applied in earlier phase, see PlaceItems().
+        NOTREACHED();
         return;
     }
     NOTREACHED();
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
index ff67069..7f613abb 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -62,6 +62,7 @@
                       LayoutUnit* line_left,
                       LayoutUnit inline_size,
                       LayoutUnit available_width);
+  bool ApplyJustify(NGLineInfo*);
 
   LayoutUnit ComputeContentSize(const NGLineInfo&,
                                 const NGExclusionSpace&,
@@ -77,9 +78,6 @@
   LayoutUnit max_inline_size_;
   FontBaseline baseline_type_ = FontBaseline::kAlphabeticBaseline;
 
-  NGLogicalOffset bfc_offset_;
-  NGBfcRect current_opportunity_;
-
   unsigned is_horizontal_writing_mode_ : 1;
 
   std::unique_ptr<NGExclusionSpace> exclusion_space_;
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
index 016efbf..bbc7050 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
@@ -42,9 +42,9 @@
 namespace {
 
 struct FragmentPosition {
+  const NGPhysicalFragment* fragment;
   NGLogicalOffset offset;
   LayoutUnit inline_size;
-  NGTextEndEffect end_effect;
   NGBorderEdges border_edges;
 
   void operator+=(const NGBoxStrut& strut) {
@@ -92,8 +92,8 @@
       // One LayoutText may produce multiple text fragments that they can't
       // be set to a map.
       positions_for_bidi_runs_out->push_back(FragmentPosition{
-          fragment.Offset() + parent_offset, fragment.InlineSize(),
-          physical_fragment.EndEffect()});
+          &physical_fragment, fragment.Offset() + parent_offset,
+          fragment.InlineSize()});
     } else {
       DCHECK_EQ(child->Type(), NGPhysicalFragment::kFragmentBox);
       const auto& physical_fragment = ToNGPhysicalBoxFragment(*child);
@@ -113,8 +113,8 @@
       // Store box fragments in a map by LineLayoutItem.
       positions_out->Set(
           LineLayoutItem(child->GetLayoutObject()),
-          FragmentPosition{child_offset, fragment.InlineSize(),
-                           NGTextEndEffect::kNone, fragment.BorderEdges()});
+          FragmentPosition{&physical_fragment, child_offset,
+                           fragment.InlineSize(), fragment.BorderEdges()});
     }
   }
 }
@@ -155,7 +155,11 @@
       inline_box->SetLogicalWidth(position.inline_size);
       if (inline_box->IsInlineTextBox()) {
         InlineTextBox* text_box = ToInlineTextBox(inline_box);
-        text_box->SetHasHyphen(position.end_effect == NGTextEndEffect::kHyphen);
+        const auto& physical_fragment =
+            ToNGPhysicalTextFragment(*position.fragment);
+        text_box->SetExpansion(physical_fragment.Expansion());
+        text_box->SetHasHyphen(physical_fragment.EndEffect() ==
+                               NGTextEndEffect::kHyphen);
       } else if (inline_box->GetLineLayoutItem().IsBox()) {
         LineLayoutBox box(inline_box->GetLineLayoutItem());
         box.SetLocation(inline_box->Location());
@@ -453,7 +457,15 @@
     item_index = NGInlineItem::SetBidiLevel(items, item_index, end, level);
     start = end;
   }
+#if DCHECK_IS_ON()
+  // Check all items have bidi levels, except trailing non-length items.
+  // Items that do not create break opportunities such as kOutOfFlowPositioned
+  // do not have corresponding characters, and that they do not have bidi level
+  // assigned.
+  while (item_index < items.size() && !items[item_index].Length())
+    item_index++;
   DCHECK_EQ(item_index, items.size());
+#endif
 }
 
 void NGInlineNode::ShapeText() {
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
index 20f0bac..6759b37 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
@@ -61,6 +61,7 @@
                                     NGLineInfo* line_info) {
   NGInlineItemResults* item_results = &line_info->Results();
   item_results->clear();
+  line_info->SetStartOffset(offset_);
   line_info->SetLineStyle(node_, constraint_space_, IsFirstFormattedLine(),
                           line_.is_after_forced_break);
   SetCurrentStyle(line_info->LineStyle());
@@ -104,6 +105,8 @@
   if (line_.should_create_line_box)
     ComputeLineLocation(line_info);
 
+  line_info->SetEndOffset(offset_);
+
   return true;
 }
 
@@ -223,7 +226,20 @@
 void NGLineBreaker::ComputeLineLocation(NGLineInfo* line_info) const {
   LayoutUnit line_left = line_.opportunity.value().LineStartOffset() -
                          constraint_space_.BfcOffset().line_offset;
-  line_info->SetLineLocation(line_left, line_.AvailableWidth(),
+  LayoutUnit available_width = line_.AvailableWidth();
+
+  // Indenting should move the current position to compute the size of
+  // tabulations. Since it is computed and stored in NGInlineItemResult,
+  // adjust the positoin of the line box to simplify placing items.
+  if (LayoutUnit text_indent = line_info->TextIndent()) {
+    // Move the line box by indent. Negative indents are ink overflow, let the
+    // line box overflow from the container box.
+    if (IsLtr(node_.BaseDirection()))
+      line_left += text_indent;
+    available_width -= text_indent;
+  }
+
+  line_info->SetLineLocation(line_left, available_width,
                              content_offset_.block_offset);
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h
index 496aa30..fc3601f3 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.h
@@ -44,6 +44,7 @@
                          unsigned start_offset,
                          unsigned end_offset,
                          NGPhysicalSize size,
+                         int expansion,
                          NGLineOrientation line_orientation,
                          NGTextEndEffect end_effect,
                          RefPtr<const ShapeResult> shape_result)
@@ -53,6 +54,7 @@
         start_offset_(start_offset),
         end_offset_(end_offset),
         shape_result_(shape_result),
+        expansion_(expansion),
         line_orientation_(static_cast<unsigned>(line_orientation)),
         end_effect_(static_cast<unsigned>(end_effect)) {}
 
@@ -70,6 +72,12 @@
   unsigned StartOffset() const { return start_offset_; }
   unsigned EndOffset() const { return end_offset_; }
 
+  // The amount of expansion for justification.
+  // Not used in NG paint, only to copy to InlineTextBox::SetExpansion().
+  // TODO(layout-dev): crbug.com/714962 Remove once fragment painting is enabled
+  // by default.
+  int Expansion() const { return expansion_; }
+
   NGLineOrientation LineOrientation() const {
     return static_cast<NGLineOrientation>(line_orientation_);
   }
@@ -84,7 +92,7 @@
   RefPtr<NGPhysicalFragment> CloneWithoutOffset() const {
     return AdoptRef(new NGPhysicalTextFragment(
         layout_object_, Style(), text_, item_index_, start_offset_, end_offset_,
-        size_, LineOrientation(), EndEffect(), shape_result_));
+        size_, expansion_, LineOrientation(), EndEffect(), shape_result_));
   }
 
   NGTextFragmentPaintInfo PaintInfo() const {
@@ -106,6 +114,8 @@
 
   RefPtr<const ShapeResult> shape_result_;
 
+  int expansion_;
+
   unsigned line_orientation_ : 2;  // NGLineOrientation
   unsigned end_effect_ : 1;        // NGTextEndEffect
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.cc
index 1fa60a28..b9f134a 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.cc
@@ -50,6 +50,11 @@
   return *this;
 }
 
+NGTextFragmentBuilder& NGTextFragmentBuilder::SetExpansion(int expansion) {
+  expansion_ = expansion;
+  return *this;
+}
+
 NGTextFragmentBuilder& NGTextFragmentBuilder::SetEndEffect(
     NGTextEndEffect end_effect) {
   end_effect_ = end_effect;
@@ -62,7 +67,7 @@
     unsigned end_offset) {
   return AdoptRef(new NGPhysicalTextFragment(
       node_.GetLayoutObject(), Style(), node_.Text(), index, start_offset,
-      end_offset, size_.ConvertToPhysical(WritingMode()),
+      end_offset, size_.ConvertToPhysical(WritingMode()), expansion_,
       ToLineOrientation(WritingMode()), end_effect_, std::move(shape_result_)));
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.h
index 4963412..b3cc6ac9 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_text_fragment_builder.h
@@ -29,6 +29,10 @@
 
   NGTextFragmentBuilder& SetShapeResult(RefPtr<const ShapeResult>);
 
+  // The amount of expansion for justification.
+  // Not used in NG paint, only to copy to InlineTextBox::SetExpansion().
+  NGTextFragmentBuilder& SetExpansion(int expansion);
+
   NGTextFragmentBuilder& SetEndEffect(NGTextEndEffect);
 
   // Creates the fragment. Can only be called once.
@@ -43,6 +47,8 @@
 
   RefPtr<const ShapeResult> shape_result_;
 
+  int expansion_ = 0;
+
   NGTextEndEffect end_effect_ = NGTextEndEffect::kNone;
 };
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
index d6e0f2bf..8b7c9aa 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -89,8 +89,6 @@
 // preceding this one (but not including this one).
 LayoutUnit PreviouslyUsedBlockSpace(const NGConstraintSpace& constraint_space,
                                     const NGPhysicalBoxFragment& fragment) {
-  if (!constraint_space.HasBlockFragmentation())
-    return LayoutUnit();
   const auto* break_token = ToNGBlockBreakToken(fragment.BreakToken());
   if (!break_token)
     return LayoutUnit();
@@ -285,42 +283,17 @@
     box_->SetMarginEnd(margins.inline_end);
   }
 
-  for (const auto& child_fragment : physical_fragment.Children()) {
-    DCHECK(child_fragment->IsPlaced());
-
-    // At the moment "anonymous" fragments for inline layout will have the same
-    // layout object as ourselves, we need to copy its floats across.
-    if (child_fragment->GetLayoutObject() == box_) {
-      for (const auto& maybe_float_fragment :
-           ToNGPhysicalBoxFragment(child_fragment.Get())->Children()) {
-        // The child of the anonymous fragment might be just a line-box
-        // fragment - ignore.
-        if (IsFloatFragment(*maybe_float_fragment)) {
-          // We need to include the anonymous fragments offset here for the
-          // correct position.
-          CopyChildFragmentPosition(
-              ToNGPhysicalBoxFragment(*maybe_float_fragment),
-              child_fragment->Offset());
-        }
-      }
-    } else {
-      const auto& box_fragment = *ToNGPhysicalBoxFragment(child_fragment.Get());
-      if (IsFirstFragment(constraint_space, box_fragment))
-        CopyChildFragmentPosition(box_fragment);
-
-      if (child_fragment->GetLayoutObject()->IsLayoutBlockFlow())
-        ToLayoutBlockFlow(child_fragment->GetLayoutObject())
-            ->AddOverflowFromFloats();
-    }
-  }
+  PlaceChildrenInLayoutBox(constraint_space, physical_fragment);
 
   if (box_->IsLayoutBlock() && IsLastFragment(physical_fragment)) {
     LayoutBlock* block = ToLayoutBlock(box_);
     NGWritingMode writing_mode = constraint_space.WritingMode();
     NGBoxFragment fragment(writing_mode, physical_fragment);
     LayoutUnit overflow_size = fragment.OverflowSize().block_size;
-    overflow_size +=
-        PreviouslyUsedBlockSpace(constraint_space, physical_fragment);
+    if (constraint_space.HasBlockFragmentation()) {
+      overflow_size +=
+          PreviouslyUsedBlockSpace(constraint_space, physical_fragment);
+    }
     block->LayoutPositionedObjects(true);
     block->ComputeOverflow(overflow_size - border_scrollbar_padding.block_end);
   }
@@ -337,6 +310,82 @@
   }
 }
 
+void NGBlockNode::PlaceChildrenInLayoutBox(
+    const NGConstraintSpace& constraint_space,
+    const NGPhysicalBoxFragment& physical_fragment) {
+  if (box_->IsLayoutBlockFlow() &&
+      ToLayoutBlockFlow(box_)->MultiColumnFlowThread()) {
+    PlaceChildrenInFlowThread(constraint_space, physical_fragment);
+    return;
+  }
+
+  NGPhysicalOffset offset_from_start;
+  if (constraint_space.HasBlockFragmentation()) {
+    // Need to include any block space that this container has used in previous
+    // fragmentainers. The offset of children will be relative to the
+    // container, in flow thread coordinates, i.e. the model where everything
+    // is represented as one single strip, rather than being sliced and
+    // translated into columns.
+
+    // TODO(mstensho): writing modes
+    offset_from_start.top =
+        PreviouslyUsedBlockSpace(constraint_space, physical_fragment);
+  }
+
+  for (const auto& child_fragment : physical_fragment.Children()) {
+    auto* child_object = child_fragment->GetLayoutObject();
+    DCHECK(child_fragment->IsPlaced());
+
+    // At the moment "anonymous" fragments for inline layout will have the same
+    // layout object as ourselves, we need to copy its floats across.
+    if (child_object == box_) {
+      for (const auto& maybe_float_fragment :
+           ToNGPhysicalBoxFragment(child_fragment.Get())->Children()) {
+        // The child of the anonymous fragment might be just a line-box
+        // fragment - ignore.
+        if (IsFloatFragment(*maybe_float_fragment)) {
+          // We need to include the anonymous fragments offset here for the
+          // correct position.
+          CopyChildFragmentPosition(
+              ToNGPhysicalBoxFragment(*maybe_float_fragment),
+              offset_from_start + child_fragment->Offset());
+        }
+      }
+      continue;
+    }
+    const auto& box_fragment = *ToNGPhysicalBoxFragment(child_fragment.Get());
+    if (IsFirstFragment(constraint_space, box_fragment))
+      CopyChildFragmentPosition(box_fragment, offset_from_start);
+
+    if (child_object->IsLayoutBlockFlow())
+      ToLayoutBlockFlow(child_object)->AddOverflowFromFloats();
+  }
+}
+
+void NGBlockNode::PlaceChildrenInFlowThread(
+    const NGConstraintSpace& constraint_space,
+    const NGPhysicalBoxFragment& physical_fragment) {
+  LayoutUnit flowthread_offset;
+  for (const auto& child : physical_fragment.Children()) {
+    // Each anonymous child of a multicol container constitutes one column.
+    DCHECK(child->IsPlaced());
+    DCHECK(child->GetLayoutObject() == box_);
+    const auto* column = ToNGPhysicalBoxFragment(child.Get());
+    for (const auto& actual_child : column->Children()) {
+      // Position each child node in the first column that they occur,
+      // relatively to the block-start of the flow thread.
+      const auto& box_fragment = *ToNGPhysicalBoxFragment(actual_child.Get());
+      if (!IsFirstFragment(constraint_space, box_fragment))
+        continue;
+      // TODO(mstensho): writing modes
+      NGPhysicalOffset offset(LayoutUnit(), flowthread_offset);
+      CopyChildFragmentPosition(box_fragment, offset);
+    }
+    const auto* token = ToNGBlockBreakToken(column->BreakToken());
+    flowthread_offset = token->UsedBlockSize();
+  }
+}
+
 // Copies data back to the legacy layout tree for a given child fragment.
 void NGBlockNode::CopyChildFragmentPosition(
     const NGPhysicalFragment& fragment,
@@ -348,7 +397,11 @@
   DCHECK(layout_box->Parent()) << "Should be called on children only.";
 
   // We should only be positioning children which are relative to ourselves.
-  DCHECK_EQ(box_, layout_box->ContainingBlock());
+  // The flow thread, however, is invisible to LayoutNG, so we need to make
+  // an exception there.
+  DCHECK(box_ == layout_box->ContainingBlock() ||
+         (layout_box->ContainingBlock()->IsLayoutFlowThread() &&
+          box_ == layout_box->ContainingBlock()->ContainingBlock()));
 
   // LegacyLayout flips vertical-rl horizontal coordinates before paint.
   // NGLayout flips X location for LegacyLayout compatibility.
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
index 97e2be63..178fce4 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
@@ -16,6 +16,7 @@
 class NGConstraintSpace;
 class NGFragmentBuilder;
 class NGLayoutResult;
+class NGPhysicalBoxFragment;
 class NGPhysicalFragment;
 struct MinMaxSize;
 struct NGBaselineRequest;
@@ -61,6 +62,10 @@
   // data to the layout box.
   void CopyFragmentDataToLayoutBox(const NGConstraintSpace&,
                                    const NGLayoutResult&);
+  void PlaceChildrenInLayoutBox(const NGConstraintSpace&,
+                                const NGPhysicalBoxFragment&);
+  void PlaceChildrenInFlowThread(const NGConstraintSpace&,
+                                 const NGPhysicalBoxFragment&);
   void CopyChildFragmentPosition(
       const NGPhysicalFragment& fragment,
       const NGPhysicalOffset& additional_offset = NGPhysicalOffset());
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
index 1fcb01d..fcabbe27 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -550,7 +550,7 @@
   EXPECT_FALSE(iterator.NextChild());
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatInOneColumn) {
+TEST_F(NGColumnLayoutAlgorithmTest, FloatInOneColumn) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -582,6 +582,14 @@
   EXPECT_FALSE(iterator.NextChild());
 
   iterator.SetParent(fragment);
+
+  // first column fragment
+  fragment = iterator.NextChild();
+  ASSERT_TRUE(fragment);
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
+  EXPECT_FALSE(iterator.NextChild());
+
+  iterator.SetParent(fragment);
   // #child fragment in first column
   fragment = iterator.NextChild();
   ASSERT_TRUE(fragment);
@@ -591,7 +599,7 @@
   EXPECT_FALSE(iterator.NextChild());
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_TwoFloatsInOneColumn) {
+TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInOneColumn) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -624,6 +632,14 @@
   EXPECT_FALSE(iterator.NextChild());
 
   iterator.SetParent(fragment);
+
+  // first column fragment
+  fragment = iterator.NextChild();
+  ASSERT_TRUE(fragment);
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
+  EXPECT_FALSE(iterator.NextChild());
+
+  iterator.SetParent(fragment);
   // #child1 fragment in first column
   fragment = iterator.NextChild();
   ASSERT_TRUE(fragment);
@@ -639,7 +655,7 @@
   EXPECT_FALSE(iterator.NextChild());
 }
 
-TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_TwoFloatsInTwoColumns) {
+TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInTwoColumns) {
   SetBodyInnerHTML(R"HTML(
     <style>
       #parent {
@@ -672,6 +688,19 @@
   EXPECT_FALSE(iterator.NextChild());
 
   iterator.SetParent(fragment);
+
+  // first column fragment
+  fragment = iterator.NextChild();
+  ASSERT_TRUE(fragment);
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
+
+  // second column fragment
+  const auto* column2 = iterator.NextChild();
+  ASSERT_TRUE(column2);
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()), column2->Offset());
+  EXPECT_FALSE(iterator.NextChild());
+
+  iterator.SetParent(fragment);
   // #child1 fragment in first column
   fragment = iterator.NextChild();
   ASSERT_TRUE(fragment);
@@ -685,18 +714,17 @@
   EXPECT_EQ(NGPhysicalSize(LayoutUnit(16), LayoutUnit(100)), fragment->Size());
   EXPECT_EQ(0UL, fragment->Children().size());
 
+  iterator.SetParent(column2);
   // #child1 fragment in second column
   fragment = iterator.NextChild();
   ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()),
-            fragment->Offset());
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
   EXPECT_EQ(NGPhysicalSize(LayoutUnit(15), LayoutUnit(50)), fragment->Size());
   EXPECT_EQ(0UL, fragment->Children().size());
   // #child2 fragment in second column
   fragment = iterator.NextChild();
   ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(194), LayoutUnit()),
-            fragment->Offset());
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(84), LayoutUnit()), fragment->Offset());
   EXPECT_EQ(NGPhysicalSize(LayoutUnit(16), LayoutUnit(50)), fragment->Size());
   EXPECT_EQ(0UL, fragment->Children().size());
   EXPECT_FALSE(iterator.NextChild());
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
index 36a1a7d..d8aa2881 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
@@ -68,7 +68,7 @@
     return container_builder_.BfcOffset().value();
   }
 
-  virtual NGInputNodeType Node() const { return node_; }
+  NGInputNodeType Node() const { return node_; }
 
   NGBreakTokenType* BreakToken() const { return break_token_; }
 
diff --git a/third_party/WebKit/Source/core/loader/BUILD.gn b/third_party/WebKit/Source/core/loader/BUILD.gn
index 1e08519..47a2c7f 100644
--- a/third_party/WebKit/Source/core/loader/BUILD.gn
+++ b/third_party/WebKit/Source/core/loader/BUILD.gn
@@ -79,6 +79,8 @@
     "appcache/ApplicationCache.h",
     "appcache/ApplicationCacheHost.cpp",
     "appcache/ApplicationCacheHost.h",
+    "modulescript/DocumentModuleScriptFetcher.cpp",
+    "modulescript/DocumentModuleScriptFetcher.h",
     "modulescript/ModuleScriptCreationParams.h",
     "modulescript/ModuleScriptFetchRequest.h",
     "modulescript/ModuleScriptFetcher.cpp",
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index 8729a09..cc4b4cc 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -291,8 +291,10 @@
     HistoryScrollRestorationType scroll_restoration_type,
     FrameLoadType type,
     Document* initiating_document) {
-  if (initiating_document && !initiating_document->CanCreateHistoryEntry())
+  if (type == kFrameLoadTypeStandard && initiating_document &&
+      !initiating_document->CanCreateHistoryEntry()) {
     type = kFrameLoadTypeReplaceCurrentItem;
+  }
 
   KURL old_url = request_.Url();
   original_request_.SetURL(new_url);
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 2b21539..8a4a39e9 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -666,15 +666,15 @@
       document_loader_->LoadType() == kFrameLoadTypeReload)
     return kFrameLoadTypeReload;
 
-  if (request.OriginDocument() &&
-      !request.OriginDocument()->CanCreateHistoryEntry())
-    return kFrameLoadTypeReplaceCurrentItem;
-
   if (request.GetResourceRequest().Url().IsEmpty() &&
       request.GetSubstituteData().FailingURL().IsEmpty()) {
     return kFrameLoadTypeReplaceCurrentItem;
   }
 
+  if (request.OriginDocument() &&
+      !request.OriginDocument()->CanCreateHistoryEntry())
+    return kFrameLoadTypeReplaceCurrentItem;
+
   return kFrameLoadTypeStandard;
 }
 
diff --git a/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp b/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
index 53725e4a..f9454e7 100644
--- a/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
@@ -111,12 +111,16 @@
 
 void TextTrackLoader::NotifyFinished(Resource* resource) {
   DCHECK_EQ(this->GetResource(), resource);
-  if (state_ != kFailed)
-    state_ = resource->ErrorOccurred() ? kFailed : kFinished;
-
-  if (state_ == kFinished && cue_parser_)
+  if (cue_parser_)
     cue_parser_->Flush();
 
+  if (state_ != kFailed) {
+    if (resource->ErrorOccurred() || !cue_parser_)
+      state_ = kFailed;
+    else
+      state_ = kFinished;
+  }
+
   if (!cue_load_timer_.IsActive())
     cue_load_timer_.StartOneShot(0, BLINK_FROM_HERE);
 
diff --git a/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.cpp b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.cpp
new file mode 100644
index 0000000..66143665
--- /dev/null
+++ b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.cpp
@@ -0,0 +1,115 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/loader/modulescript/DocumentModuleScriptFetcher.h"
+
+#include "core/dom/ExecutionContext.h"
+#include "core/inspector/ConsoleMessage.h"
+#include "platform/loader/fetch/FetchUtils.h"
+#include "platform/network/mime/MIMETypeRegistry.h"
+
+namespace blink {
+
+namespace {
+
+bool WasModuleLoadSuccessful(Resource* resource,
+                             ConsoleMessage** error_message) {
+  // Implements conditions in Step 7 of
+  // https://html.spec.whatwg.org/#fetch-a-single-module-script
+
+  // - response's type is "error"
+  if (!resource || resource->ErrorOccurred()) {
+    return false;
+  }
+
+  const auto& response = resource->GetResponse();
+  // - response's status is not an ok status
+  if (response.IsHTTP() && !FetchUtils::IsOkStatus(response.HttpStatusCode())) {
+    return false;
+  }
+
+  // The result of extracting a MIME type from response's header list
+  // (ignoring parameters) is not a JavaScript MIME type
+  // Note: For historical reasons, fetching a classic script does not include
+  // MIME type checking. In contrast, module scripts will fail to load if they
+  // are not of a correct MIME type.
+  // We use ResourceResponse::HttpContentType() instead of MimeType(), as
+  // MimeType() may be rewritten by mime sniffer.
+  if (!MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
+          response.HttpContentType())) {
+    if (error_message) {
+      String message =
+          "Failed to load module script: The server responded with a "
+          "non-JavaScript MIME type of \"" +
+          response.HttpContentType() +
+          "\". Strict MIME type checking is enforced for module scripts per "
+          "HTML spec.";
+      *error_message = ConsoleMessage::CreateForRequest(
+          kJSMessageSource, kErrorMessageLevel, message,
+          response.Url().GetString(), resource->Identifier());
+    }
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+DocumentModuleScriptFetcher::DocumentModuleScriptFetcher(
+    ResourceFetcher* fetcher)
+    : fetcher_(fetcher) {
+  DCHECK(fetcher_);
+}
+
+void DocumentModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
+                                        ModuleScriptFetcher::Client* client) {
+  SetClient(client);
+  ScriptResource* resource = ScriptResource::Fetch(fetch_params, fetcher_);
+  if (was_fetched_) {
+    // ScriptResource::Fetch() has succeeded synchronously,
+    // ::NotifyFinished() already took care of the |resource|.
+    return;
+  }
+  if (!resource) {
+    // ScriptResource::Fetch() has failed synchronously.
+    NotifyFinished(nullptr /* resource */);
+    return;
+  }
+
+  // ScriptResource::Fetch() is processed asynchronously.
+  SetResource(resource);
+}
+
+void DocumentModuleScriptFetcher::NotifyFinished(Resource* resource) {
+  ClearResource();
+
+  ScriptResource* script_resource = ToScriptResource(resource);
+  ConsoleMessage* error_message = nullptr;
+  if (!WasModuleLoadSuccessful(script_resource, &error_message)) {
+    Finalize(WTF::nullopt, error_message);
+    return;
+  }
+
+  ModuleScriptCreationParams params(
+      script_resource->GetResponse().Url(), script_resource->SourceText(),
+      script_resource->GetResourceRequest().GetFetchCredentialsMode(),
+      script_resource->CalculateAccessControlStatus());
+  Finalize(params, nullptr /* error_message */);
+}
+
+void DocumentModuleScriptFetcher::Finalize(
+    const WTF::Optional<ModuleScriptCreationParams>& params,
+    ConsoleMessage* error_message) {
+  was_fetched_ = true;
+  NotifyFetchFinished(params, error_message);
+}
+
+DEFINE_TRACE(DocumentModuleScriptFetcher) {
+  visitor->Trace(fetcher_);
+  ResourceOwner<ScriptResource>::Trace(visitor);
+  ModuleScriptFetcher::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.h b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.h
new file mode 100644
index 0000000..f915d89
--- /dev/null
+++ b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.h
@@ -0,0 +1,55 @@
+// 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 DocumentModuleScriptFetcher_h
+#define DocumentModuleScriptFetcher_h
+
+#include "core/dom/Modulator.h"
+#include "core/loader/modulescript/ModuleScriptCreationParams.h"
+#include "core/loader/modulescript/ModuleScriptFetcher.h"
+#include "core/loader/resource/ScriptResource.h"
+#include "platform/loader/fetch/FetchParameters.h"
+#include "platform/loader/fetch/ResourceFetcher.h"
+#include "platform/loader/fetch/ResourceOwner.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "platform/wtf/Optional.h"
+
+namespace blink {
+
+class ConsoleMessage;
+
+// DocumentModuleScriptFetcher is used to fetch module scripts used in main
+// documents (that means, not worker nor worklets).
+//
+// DocumentModuleScriptFetcher emits FetchParameters to ResourceFetcher
+// (via ScriptResource::Fetch). Then, it keeps track of the fetch progress by
+// being a ResourceOwner. Finally, it returns its client a fetched resource as
+// ModuleScriptCreationParams.
+class CORE_EXPORT DocumentModuleScriptFetcher
+    : public ModuleScriptFetcher,
+      public ResourceOwner<ScriptResource> {
+  USING_GARBAGE_COLLECTED_MIXIN(DocumentModuleScriptFetcher);
+
+ public:
+  explicit DocumentModuleScriptFetcher(ResourceFetcher*);
+
+  void Fetch(FetchParameters&, ModuleScriptFetcher::Client*) final;
+
+  // Implements ScriptResourceClient
+  void NotifyFinished(Resource*) final;
+  String DebugName() const final { return "DocumentModuleScriptFetcher"; }
+
+  DECLARE_TRACE();
+
+ private:
+  void Finalize(const WTF::Optional<ModuleScriptCreationParams>&,
+                ConsoleMessage* error_message);
+
+  Member<ResourceFetcher> fetcher_;
+  bool was_fetched_ = false;
+};
+
+}  // namespace blink
+
+#endif  // DocumentModuleScriptFetcher_h
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.cpp
index af9e7f95..45b5a28 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.cpp
@@ -4,111 +4,21 @@
 
 #include "core/loader/modulescript/ModuleScriptFetcher.h"
 
-#include "core/dom/ExecutionContext.h"
-#include "core/inspector/ConsoleMessage.h"
-#include "platform/loader/fetch/FetchUtils.h"
-#include "platform/network/mime/MIMETypeRegistry.h"
-
 namespace blink {
 
-namespace {
-
-bool WasModuleLoadSuccessful(Resource* resource,
-                             ConsoleMessage** error_message) {
-  // Implements conditions in Step 7 of
-  // https://html.spec.whatwg.org/#fetch-a-single-module-script
-
-  // - response's type is "error"
-  if (!resource || resource->ErrorOccurred()) {
-    return false;
-  }
-
-  const auto& response = resource->GetResponse();
-  // - response's status is not an ok status
-  if (response.IsHTTP() && !FetchUtils::IsOkStatus(response.HttpStatusCode())) {
-    return false;
-  }
-
-  // The result of extracting a MIME type from response's header list
-  // (ignoring parameters) is not a JavaScript MIME type
-  // Note: For historical reasons, fetching a classic script does not include
-  // MIME type checking. In contrast, module scripts will fail to load if they
-  // are not of a correct MIME type.
-  // We use ResourceResponse::HttpContentType() instead of MimeType(), as
-  // MimeType() may be rewritten by mime sniffer.
-  if (!MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
-          response.HttpContentType())) {
-    if (error_message) {
-      String message =
-          "Failed to load module script: The server responded with a "
-          "non-JavaScript MIME type of \"" +
-          response.HttpContentType() +
-          "\". Strict MIME type checking is enforced for module scripts per "
-          "HTML spec.";
-      *error_message = ConsoleMessage::CreateForRequest(
-          kJSMessageSource, kErrorMessageLevel, message,
-          response.Url().GetString(), resource->Identifier());
-    }
-    return false;
-  }
-
-  return true;
+DEFINE_TRACE(ModuleScriptFetcher) {
+  visitor->Trace(client_);
 }
 
-}  // namespace
-
-ModuleScriptFetcher::ModuleScriptFetcher(const FetchParameters& fetch_params,
-                                         ResourceFetcher* fetcher,
-                                         Client* client)
-    : fetch_params_(fetch_params),
-      fetcher_(fetcher),
-      client_(client) {}
-
-void ModuleScriptFetcher::Fetch() {
-  ScriptResource* resource = ScriptResource::Fetch(fetch_params_, fetcher_);
-  if (was_fetched_) {
-    // ScriptResource::Fetch() has succeeded synchronously,
-    // ::NotifyFinished() already took care of the |resource|.
-    return;
-  }
-  if (!resource) {
-    // ScriptResource::Fetch() has failed synchronously.
-    NotifyFinished(nullptr /* resource */);
-    return;
-  }
-
-  // ScriptResource::Fetch() is processed asynchronously.
-  SetResource(resource);
-}
-
-void ModuleScriptFetcher::NotifyFinished(Resource* resource) {
-  ClearResource();
-
-  ScriptResource* script_resource = ToScriptResource(resource);
-  ConsoleMessage* error_message = nullptr;
-  if (!WasModuleLoadSuccessful(script_resource, &error_message)) {
-    Finalize(WTF::nullopt, error_message);
-    return;
-  }
-
-  ModuleScriptCreationParams params(
-      script_resource->GetResponse().Url(), script_resource->SourceText(),
-      script_resource->GetResourceRequest().GetFetchCredentialsMode(),
-      script_resource->CalculateAccessControlStatus());
-  Finalize(params, nullptr /* error_message */);
-}
-
-void ModuleScriptFetcher::Finalize(
+void ModuleScriptFetcher::NotifyFetchFinished(
     const WTF::Optional<ModuleScriptCreationParams>& params,
     ConsoleMessage* error_message) {
-  was_fetched_ = true;
   client_->NotifyFetchFinished(params, error_message);
 }
 
-DEFINE_TRACE(ModuleScriptFetcher) {
-  visitor->Trace(fetcher_);
-  visitor->Trace(client_);
-  ResourceOwner<ScriptResource>::Trace(visitor);
+void ModuleScriptFetcher::SetClient(Client* client) {
+  DCHECK(!client_);
+  client_ = client;
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.h
index 07badd6b..cf68e4f 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.h
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptFetcher.h
@@ -5,28 +5,20 @@
 #ifndef ModuleScriptFetcher_h
 #define ModuleScriptFetcher_h
 
-#include "core/dom/Modulator.h"
+#include "core/CoreExport.h"
 #include "core/loader/modulescript/ModuleScriptCreationParams.h"
-#include "core/loader/resource/ScriptResource.h"
 #include "platform/loader/fetch/FetchParameters.h"
-#include "platform/loader/fetch/ResourceFetcher.h"
-#include "platform/loader/fetch/ResourceOwner.h"
-#include "platform/weborigin/SecurityOrigin.h"
 #include "platform/wtf/Optional.h"
 
 namespace blink {
 
 class ConsoleMessage;
 
-// ModuleScriptFetcher emits FetchParameters to ResourceFetcher
-// (via ScriptResource::Fetch). Then, it keeps track of the fetch progress by
-// being a ResourceOwner. Finally, it returns its client a fetched resource as
-// ModuleScriptCreationParams.
+// ModuleScriptFetcher is an abstract class to fetch module scripts. Derived
+// classes are expected to fetch a module script for the given FetchParameters
+// and return its client a fetched resource as ModuleScriptCreationParams.
 class CORE_EXPORT ModuleScriptFetcher
-    : public GarbageCollectedFinalized<ModuleScriptFetcher>,
-      public ResourceOwner<ScriptResource> {
-  USING_GARBAGE_COLLECTED_MIXIN(ModuleScriptFetcher);
-
+    : public GarbageCollectedFinalized<ModuleScriptFetcher> {
  public:
   class CORE_EXPORT Client : public GarbageCollectedMixin {
    public:
@@ -35,30 +27,23 @@
         ConsoleMessage* error_message) = 0;
   };
 
-  ModuleScriptFetcher(const FetchParameters&,
-                      ResourceFetcher*,
-                      Client*);
+  ModuleScriptFetcher() = default;
+  virtual ~ModuleScriptFetcher() = default;
 
-  // 'virtual' for custom fetch.
-  virtual void Fetch();
+  // Takes a non-const reference to FetchParameters because
+  // ScriptResource::Fetch() requires it.
+  virtual void Fetch(FetchParameters&, Client*) = 0;
 
-  // Implements ScriptResourceClient
-  void NotifyFinished(Resource*) final;
-  String DebugName() const final { return "ModuleScriptFetcher"; }
-
-  const FetchParameters& GetFetchParams() const { return fetch_params_; }
-
-  DECLARE_TRACE();
+  DECLARE_VIRTUAL_TRACE();
 
  protected:
-  virtual void Finalize(const WTF::Optional<ModuleScriptCreationParams>&,
-                        ConsoleMessage* error_message);
+  void NotifyFetchFinished(const WTF::Optional<ModuleScriptCreationParams>&,
+                           ConsoleMessage*);
+
+  void SetClient(Client*);
 
  private:
-  FetchParameters fetch_params_;
-  Member<ResourceFetcher> fetcher_;
   Member<Client> client_;
-  bool was_fetched_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
index 76a1f8a..164b80e 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
@@ -8,6 +8,8 @@
 #include "core/dom/Modulator.h"
 #include "core/dom/ModuleScript.h"
 #include "core/inspector/ConsoleMessage.h"
+#include "core/loader/modulescript/DocumentModuleScriptFetcher.h"
+#include "core/loader/modulescript/ModuleScriptFetcher.h"
 #include "core/loader/modulescript/ModuleScriptLoaderClient.h"
 #include "core/loader/modulescript/ModuleScriptLoaderRegistry.h"
 #include "core/loader/modulescript/WorkletModuleScriptFetcher.h"
@@ -73,7 +75,6 @@
 }
 
 void ModuleScriptLoader::Fetch(const ModuleScriptFetchRequest& module_request,
-                               ResourceFetcher* fetcher,
                                ModuleGraphLevel level) {
   // https://html.spec.whatwg.org/#fetch-a-single-module-script
 
@@ -143,17 +144,8 @@
   // steps.
   // Otherwise, fetch request. Return from this algorithm, and run the remaining
   // steps as part of the fetch's process response for the response response.
-  ExecutionContext* execution_context =
-      ExecutionContext::From(modulator_->GetScriptState());
-  if (execution_context->IsMainThreadWorkletGlobalScope()) {
-    MainThreadWorkletGlobalScope* global_scope =
-        ToMainThreadWorkletGlobalScope(execution_context);
-    module_fetcher_ = new WorkletModuleScriptFetcher(
-        fetch_params, fetcher, this, global_scope->ModuleResponsesMapProxy());
-  } else {
-    module_fetcher_ = new ModuleScriptFetcher(fetch_params, fetcher, this);
-  }
-  module_fetcher_->Fetch();
+  module_fetcher_ = modulator_->CreateModuleScriptFetcher();
+  module_fetcher_->Fetch(fetch_params, this);
 }
 
 void ModuleScriptLoader::NotifyFetchFinished(
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h
index 3ff70dfb..a2ba0c6 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h
@@ -53,7 +53,6 @@
   ~ModuleScriptLoader();
 
   void Fetch(const ModuleScriptFetchRequest&,
-             ResourceFetcher*,
              ModuleGraphLevel);
 
   // Implements ModuleScriptFetcher::Client.
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.cpp
index 9e0894e..cc9fb102 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.cpp
@@ -16,13 +16,12 @@
     const ModuleScriptFetchRequest& request,
     ModuleGraphLevel level,
     Modulator* modulator,
-    ResourceFetcher* fetcher,
     ModuleScriptLoaderClient* client) {
   ModuleScriptLoader* loader =
       ModuleScriptLoader::Create(modulator, this, client);
   DCHECK(loader->IsInitialState());
   active_loaders_.insert(loader);
-  loader->Fetch(request, fetcher, level);
+  loader->Fetch(request, level);
   return loader;
 }
 
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.h
index cb289840..b2b51a1 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.h
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderRegistry.h
@@ -16,7 +16,6 @@
 class ModuleScriptFetchRequest;
 class ModuleScriptLoader;
 class ModuleScriptLoaderClient;
-class ResourceFetcher;
 enum class ModuleGraphLevel;
 
 // ModuleScriptLoaderRegistry keeps active ModuleLoaders alive.
@@ -31,7 +30,6 @@
   ModuleScriptLoader* Fetch(const ModuleScriptFetchRequest&,
                             ModuleGraphLevel,
                             Modulator*,
-                            ResourceFetcher*,
                             ModuleScriptLoaderClient*);
 
  private:
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp
index c3986a37..acfa8e2c1 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoaderTest.cpp
@@ -10,9 +10,11 @@
 #include "core/dom/Modulator.h"
 #include "core/dom/ModuleScript.h"
 #include "core/dom/TaskRunnerHelper.h"
+#include "core/loader/modulescript/DocumentModuleScriptFetcher.h"
 #include "core/loader/modulescript/ModuleScriptFetchRequest.h"
 #include "core/loader/modulescript/ModuleScriptLoaderClient.h"
 #include "core/loader/modulescript/ModuleScriptLoaderRegistry.h"
+#include "core/loader/modulescript/WorkletModuleScriptFetcher.h"
 #include "core/testing/DummyModulator.h"
 #include "core/testing/DummyPageHolder.h"
 #include "core/workers/MainThreadWorkletGlobalScope.h"
@@ -60,7 +62,11 @@
   ModuleScriptLoaderTestModulator(RefPtr<ScriptState> script_state,
                                   RefPtr<SecurityOrigin> security_origin)
       : script_state_(std::move(script_state)),
-        security_origin_(std::move(security_origin)) {}
+        security_origin_(std::move(security_origin)) {
+    auto* fetch_context =
+        MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
+    fetcher_ = ResourceFetcher::Create(fetch_context);
+  }
 
   ~ModuleScriptLoaderTestModulator() override {}
 
@@ -95,15 +101,28 @@
     return ScriptModuleState::kUninstantiated;
   }
 
+  ModuleScriptFetcher* CreateModuleScriptFetcher() override {
+    auto* execution_context = ExecutionContext::From(script_state_.Get());
+    if (execution_context->IsDocument())
+      return new DocumentModuleScriptFetcher(Fetcher());
+    auto* global_scope = ToWorkletGlobalScope(execution_context);
+    return new WorkletModuleScriptFetcher(
+        global_scope->ModuleResponsesMapProxy());
+  }
+
+  ResourceFetcher* Fetcher() const { return fetcher_.Get(); }
+
   DECLARE_TRACE();
 
  private:
   RefPtr<ScriptState> script_state_;
   RefPtr<SecurityOrigin> security_origin_;
+  Member<ResourceFetcher> fetcher_;
   Vector<ModuleRequest> requests_;
 };
 
 DEFINE_TRACE(ModuleScriptLoaderTestModulator) {
+  visitor->Trace(fetcher_);
   DummyModulator::Trace(visitor);
 }
 
@@ -126,14 +145,12 @@
 
   LocalFrame& GetFrame() { return dummy_page_holder_->GetFrame(); }
   Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
-  ResourceFetcher* Fetcher() { return fetcher_.Get(); }
   ModuleScriptLoaderTestModulator* GetModulator() { return modulator_.Get(); }
 
  protected:
   ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_;
   std::unique_ptr<DummyPageHolder> dummy_page_holder_;
   std::unique_ptr<MainThreadWorkletReportingProxy> reporting_proxy_;
-  Persistent<ResourceFetcher> fetcher_;
   Persistent<ModuleScriptLoaderTestModulator> modulator_;
   Persistent<MainThreadWorkletGlobalScope> global_scope_;
 };
@@ -143,9 +160,6 @@
   dummy_page_holder_ = DummyPageHolder::Create(IntSize(500, 500));
   GetDocument().SetURL(KURL(kParsedURLString, "https://example.test"));
   GetDocument().SetSecurityOrigin(SecurityOrigin::Create(GetDocument().Url()));
-  auto* context =
-      MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
-  fetcher_ = ResourceFetcher::Create(context);
 }
 
 void ModuleScriptLoaderTest::InitializeForDocument() {
@@ -162,14 +176,14 @@
       "fake user agent", GetDocument().GetSecurityOrigin(),
       ToIsolate(&GetDocument()), *reporting_proxy_);
   global_scope_->ScriptController()->InitializeContextIfNeeded("Dummy Context");
-  global_scope_->SetModuleResponsesMapProxyForTesting(
-      WorkletModuleResponsesMapProxy::Create(
-          new WorkletModuleResponsesMap(Fetcher()),
-          TaskRunnerHelper::Get(TaskType::kUnspecedLoading, &GetDocument()),
-          TaskRunnerHelper::Get(TaskType::kUnspecedLoading, global_scope_)));
   modulator_ = new ModuleScriptLoaderTestModulator(
       global_scope_->ScriptController()->GetScriptState(),
       GetDocument().GetSecurityOrigin());
+  global_scope_->SetModuleResponsesMapProxyForTesting(
+      WorkletModuleResponsesMapProxy::Create(
+          new WorkletModuleResponsesMap(modulator_->Fetcher()),
+          TaskRunnerHelper::Get(TaskType::kUnspecedLoading, &GetDocument()),
+          TaskRunnerHelper::Get(TaskType::kUnspecedLoading, global_scope_)));
 }
 
 void ModuleScriptLoaderTest::TestFetchDataURL(
@@ -179,7 +193,7 @@
   ModuleScriptFetchRequest module_request(
       url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit);
   registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
-                  GetModulator(), Fetcher(), client);
+                  GetModulator(), client);
 }
 
 TEST_F(ModuleScriptLoaderTest, FetchDataURL) {
@@ -229,7 +243,7 @@
       url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit);
   GetModulator()->SetModuleRequests({"invalid"});
   registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
-                  GetModulator(), Fetcher(), client);
+                  GetModulator(), client);
 }
 
 TEST_F(ModuleScriptLoaderTest, InvalidSpecifier) {
@@ -265,7 +279,7 @@
   ModuleScriptFetchRequest module_request(
       url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit);
   registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
-                  GetModulator(), Fetcher(), client);
+                  GetModulator(), client);
 }
 
 TEST_F(ModuleScriptLoaderTest, FetchInvalidURL) {
@@ -301,7 +315,7 @@
   ModuleScriptFetchRequest module_request(
       url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit);
   registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
-                  GetModulator(), Fetcher(), client);
+                  GetModulator(), client);
 }
 
 TEST_F(ModuleScriptLoaderTest, FetchURL) {
diff --git a/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.cpp b/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.cpp
index a73a228b..3490a51 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.cpp
@@ -9,20 +9,20 @@
 namespace blink {
 
 WorkletModuleScriptFetcher::WorkletModuleScriptFetcher(
-    const FetchParameters& fetch_params,
-    ResourceFetcher* fetcher,
-    ModuleScriptFetcher::Client* client,
     WorkletModuleResponsesMapProxy* module_responses_map_proxy)
-    : ModuleScriptFetcher(fetch_params, fetcher, client),
-      module_responses_map_proxy_(module_responses_map_proxy) {}
+    : module_responses_map_proxy_(module_responses_map_proxy) {
+  DCHECK(module_responses_map_proxy_);
+}
 
 DEFINE_TRACE(WorkletModuleScriptFetcher) {
   visitor->Trace(module_responses_map_proxy_);
   ModuleScriptFetcher::Trace(visitor);
 }
 
-void WorkletModuleScriptFetcher::Fetch() {
-  module_responses_map_proxy_->ReadEntry(GetFetchParams(), this);
+void WorkletModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
+                                       ModuleScriptFetcher::Client* client) {
+  SetClient(client);
+  module_responses_map_proxy_->ReadEntry(fetch_params, this);
 }
 
 void WorkletModuleScriptFetcher::OnRead(
@@ -34,4 +34,10 @@
   Finalize(WTF::nullopt, nullptr /* error_message */);
 }
 
+void WorkletModuleScriptFetcher::Finalize(
+    const WTF::Optional<ModuleScriptCreationParams>& params,
+    ConsoleMessage* error_message) {
+  NotifyFetchFinished(params, error_message);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.h b/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.h
index af8792a..e3d7259 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.h
+++ b/third_party/WebKit/Source/core/loader/modulescript/WorkletModuleScriptFetcher.h
@@ -6,7 +6,6 @@
 #define WorkletModuleScriptFetcher_h
 
 #include "core/loader/modulescript/ModuleScriptFetcher.h"
-
 #include "core/workers/WorkletModuleResponsesMap.h"
 #include "core/workers/WorkletModuleResponsesMapProxy.h"
 #include "platform/wtf/Optional.h"
@@ -17,25 +16,20 @@
 // module loading defined in:
 // https://drafts.css-houdini.org/worklets/#fetch-a-worklet-script
 //
-// This class works as follows. First, this queries WorkletModuleResponsesMap
-// about whether a module script in question has already been cached. If the
-// module script is in the map, this retrieves it as ModuleScriptCreationParams
-// and returns it to its client. If the module script isn't in the map, this
-// fetches the module script via the default module fetch path and then caches
-// it in the map.
+// WorkletModuleScriptFetcher does not initiate module fetch by itself. This
+// asks WorkletModuleResponsesMap on the main thread via
+// WorkletModuleResponsesMapProxy to read a cached module script or to fetch it
+// via network. See comments on WorkletModuleResponsesMap for details.
 class CORE_EXPORT WorkletModuleScriptFetcher final
     : public ModuleScriptFetcher,
       public WorkletModuleResponsesMap::Client {
   USING_GARBAGE_COLLECTED_MIXIN(WorkletModuleScriptFetcher);
 
  public:
-  WorkletModuleScriptFetcher(const FetchParameters&,
-                             ResourceFetcher*,
-                             ModuleScriptFetcher::Client*,
-                             WorkletModuleResponsesMapProxy*);
+  explicit WorkletModuleScriptFetcher(WorkletModuleResponsesMapProxy*);
 
   // Implements ModuleScriptFetcher.
-  void Fetch() override;
+  void Fetch(FetchParameters&, ModuleScriptFetcher::Client*) override;
 
   // Implements WorkletModuleResponsesMap::Client.
   void OnRead(const ModuleScriptCreationParams&) override;
@@ -44,6 +38,9 @@
   DECLARE_TRACE();
 
  private:
+  void Finalize(const WTF::Optional<ModuleScriptCreationParams>&,
+                ConsoleMessage* error_message);
+
   Member<WorkletModuleResponsesMapProxy> module_responses_map_proxy_;
 };
 
diff --git a/third_party/WebKit/Source/core/mojo/MojoHandle.cpp b/third_party/WebKit/Source/core/mojo/MojoHandle.cpp
index 27b62778..5258eef 100644
--- a/third_party/WebKit/Source/core/mojo/MojoHandle.cpp
+++ b/third_party/WebKit/Source/core/mojo/MojoHandle.cpp
@@ -4,7 +4,7 @@
 
 #include "core/mojo/MojoHandle.h"
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/mojo/MojoCreateSharedBufferResult.h"
 #include "core/mojo/MojoDiscardDataOptions.h"
diff --git a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp
index 902c00b..2dd0be86 100644
--- a/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp
+++ b/third_party/WebKit/Source/core/mojo/MojoWatcher.cpp
@@ -4,7 +4,7 @@
 
 #include "core/mojo/MojoWatcher.h"
 
-#include "bindings/core/v8/MojoWatchCallback.h"
+#include "bindings/core/v8/mojo_watch_callback.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/mojo/MojoHandleSignals.h"
diff --git a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp
index e570adee..458352d 100644
--- a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp
+++ b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.cpp
@@ -18,15 +18,27 @@
 #include "platform/WebTaskRunner.h"
 #include "platform/bindings/ScriptState.h"
 #include "platform/wtf/text/StringUTF8Adaptor.h"
+#include "public/platform/Platform.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 
 namespace blink {
 
 // static
 MojoInterfaceInterceptor* MojoInterfaceInterceptor::Create(
-    ScriptState* script_state,
-    const String& interface_name) {
-  return new MojoInterfaceInterceptor(script_state, interface_name);
+    ExecutionContext* context,
+    const String& interface_name,
+    const String& scope,
+    ExceptionState& exception_state) {
+  bool process_scope = scope == "process";
+  if (process_scope && !context->IsDocument()) {
+    exception_state.ThrowDOMException(
+        kNotSupportedError,
+        "\"process\" scope interception is unavailable outside a Document.");
+    return nullptr;
+  }
+
+  return new MojoInterfaceInterceptor(context, interface_name, process_scope);
 }
 
 MojoInterfaceInterceptor::~MojoInterfaceInterceptor() {}
@@ -46,6 +58,27 @@
   std::string interface_name =
       StringUTF8Adaptor(interface_name_).AsStringPiece().as_string();
 
+  if (process_scope_) {
+    std::string browser_service = Platform::Current()->GetBrowserServiceName();
+    service_manager::Connector::TestApi test_api(
+        Platform::Current()->GetConnector());
+    if (test_api.HasBinderOverride(browser_service, interface_name)) {
+      exception_state.ThrowDOMException(
+          kInvalidModificationError,
+          "Interface " + interface_name_ +
+              " is already intercepted by another MojoInterfaceInterceptor.");
+      return;
+    }
+
+    started_ = true;
+    test_api.OverrideBinderForTesting(
+        browser_service, interface_name,
+        ConvertToBaseCallback(
+            WTF::Bind(&MojoInterfaceInterceptor::OnInterfaceRequest,
+                      WrapWeakPersistent(this))));
+    return;
+  }
+
   service_manager::InterfaceProvider::TestApi test_api(interface_provider);
   if (test_api.HasBinderForName(interface_name)) {
     exception_state.ThrowDOMException(
@@ -67,11 +100,21 @@
     return;
 
   started_ = false;
+  std::string interface_name =
+      StringUTF8Adaptor(interface_name_).AsStringPiece().as_string();
+
+  if (process_scope_) {
+    std::string browser_service = Platform::Current()->GetBrowserServiceName();
+    service_manager::Connector::TestApi test_api(
+        Platform::Current()->GetConnector());
+    DCHECK(test_api.HasBinderOverride(browser_service, interface_name));
+    test_api.ClearBinderOverride(browser_service, interface_name);
+    return;
+  }
+
   // GetInterfaceProvider() is guaranteed not to return nullptr because this
   // method is called when the context is destroyed.
   service_manager::InterfaceProvider::TestApi test_api(GetInterfaceProvider());
-  std::string interface_name =
-      StringUTF8Adaptor(interface_name_).AsStringPiece().as_string();
   DCHECK(test_api.HasBinderForName(interface_name));
   test_api.ClearBinderForName(interface_name);
 }
@@ -97,10 +140,12 @@
   stop();
 }
 
-MojoInterfaceInterceptor::MojoInterfaceInterceptor(ScriptState* script_state,
-                                                   const String& interface_name)
-    : ContextLifecycleObserver(ExecutionContext::From(script_state)),
-      interface_name_(interface_name) {}
+MojoInterfaceInterceptor::MojoInterfaceInterceptor(ExecutionContext* context,
+                                                   const String& interface_name,
+                                                   bool process_scope)
+    : ContextLifecycleObserver(context),
+      interface_name_(interface_name),
+      process_scope_(process_scope) {}
 
 service_manager::InterfaceProvider*
 MojoInterfaceInterceptor::GetInterfaceProvider() const {
diff --git a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h
index e7c4dc4..4961f434 100644
--- a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h
+++ b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.h
@@ -21,7 +21,6 @@
 
 class ExceptionState;
 class ExecutionContext;
-class ScriptState;
 
 // A MojoInterfaceInterceptor can be constructed by test scripts in order to
 // intercept all outgoing requests for a specific named interface from the
@@ -37,8 +36,10 @@
   USING_GARBAGE_COLLECTED_MIXIN(MojoInterfaceInterceptor);
 
  public:
-  static MojoInterfaceInterceptor* Create(ScriptState*,
-                                          const String& interface_name);
+  static MojoInterfaceInterceptor* Create(ExecutionContext*,
+                                          const String& interface_name,
+                                          const String& scope,
+                                          ExceptionState&);
   ~MojoInterfaceInterceptor();
 
   void start(ExceptionState&);
@@ -59,9 +60,9 @@
   void ContextDestroyed(ExecutionContext*) final;
 
  private:
-  friend class V8MojoInterfaceInterceptor;
-
-  MojoInterfaceInterceptor(ScriptState*, const String& interface_name);
+  MojoInterfaceInterceptor(ExecutionContext*,
+                           const String& interface_name,
+                           bool process_scope);
 
   service_manager::InterfaceProvider* GetInterfaceProvider() const;
   void OnInterfaceRequest(mojo::ScopedMessagePipeHandle);
@@ -69,6 +70,7 @@
 
   const String interface_name_;
   bool started_ = false;
+  bool process_scope_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.idl b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.idl
index 0edcc16..d616c219 100644
--- a/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.idl
+++ b/third_party/WebKit/Source/core/mojo/test/MojoInterfaceInterceptor.idl
@@ -4,10 +4,11 @@
 
 [
     ActiveScriptWrappable,
-    Constructor(DOMString interfaceName),
-    ConstructorCallWith=ScriptState,
+    Constructor(DOMString interfaceName, optional MojoScope scope = "context"),
+    ConstructorCallWith=ExecutionContext,
     DependentLifetime,
     Exposed=(Window,Worker),
+    RaisesException=Constructor,
     RuntimeEnabled=MojoJSTest
 ] interface MojoInterfaceInterceptor : EventTarget {
     [RaisesException] void start();
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
index e8ed94e..6d99b8f 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -248,14 +248,19 @@
     OpacityMode opacity_mode =
         context_->CreationAttributes().hasAlpha() ? kNonOpaque : kOpaque;
     std::unique_ptr<ImageBufferSurface> surface;
-    if (RuntimeEnabledFeatures::Accelerated2dCanvasEnabled()) {
+    // TODO(zakerinasab): crbug.com/761424
+    // Remove the check for canvas color extensions to allow OffscreenCanvas
+    // use accelerated code path with color management.
+    if (!CanvasColorParams::ColorCorrectRenderingInAnyColorSpace() &&
+        RuntimeEnabledFeatures::Accelerated2dCanvasEnabled()) {
       surface.reset(
           new AcceleratedImageBufferSurface(surface_size, opacity_mode));
     }
 
     if (!surface || !surface->IsValid()) {
       surface.reset(new UnacceleratedImageBufferSurface(
-          surface_size, opacity_mode, kInitializeImagePixels));
+          surface_size, opacity_mode, kInitializeImagePixels,
+          context_->color_params()));
     }
 
     image_buffer_ = ImageBuffer::Create(std::move(surface));
@@ -389,14 +394,9 @@
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
 
-  Document* document =
-      ExecutionContext::From(script_state)->IsDocument()
-          ? static_cast<Document*>(ExecutionContext::From(script_state))
-          : nullptr;
-
   CanvasAsyncBlobCreator* async_creator = CanvasAsyncBlobCreator::Create(
       image_data->data(), encoding_mime_type, image_data->Size(), start_time,
-      document, resolver);
+      ExecutionContext::From(script_state), resolver);
 
   async_creator->ScheduleAsyncBlobCreation(options.quality());
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
index 512064bd..5feec35 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
@@ -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 "bindings/core/v8/NodeOrString.h"
+#include "bindings/core/v8/node_or_string.h"
 #include "core/exported/WebRemoteFrameImpl.h"
 #include "core/frame/BrowserControls.h"
 #include "core/frame/FrameTestHelpers.h"
diff --git a/third_party/WebKit/Source/core/page/scrolling/SmoothScrollTest.cpp b/third_party/WebKit/Source/core/page/scrolling/SmoothScrollTest.cpp
index 4d4d8cb8..dfe2b0c 100644
--- a/third_party/WebKit/Source/core/page/scrolling/SmoothScrollTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/SmoothScrollTest.cpp
@@ -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 "bindings/core/v8/ScrollIntoViewOptionsOrBoolean.h"
+#include "bindings/core/v8/scroll_into_view_options_or_boolean.h"
 #include "core/frame/ScrollIntoViewOptions.h"
 #include "core/frame/ScrollToOptions.h"
 #include "core/frame/WebLocalFrameImpl.h"
diff --git a/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
index 1424e57..695f307 100644
--- a/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
+++ b/third_party/WebKit/Source/core/resize_observer/ResizeObserver.cpp
@@ -4,7 +4,7 @@
 
 #include "core/resize_observer/ResizeObserver.h"
 
-#include "bindings/core/v8/ResizeObserverCallback.h"
+#include "bindings/core/v8/resize_observer_callback.h"
 #include "core/dom/Element.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/layout/LayoutObject.h"
diff --git a/third_party/WebKit/Source/core/svg/SVGScriptElement.cpp b/third_party/WebKit/Source/core/svg/SVGScriptElement.cpp
index 4b86e351..d2409558 100644
--- a/third_party/WebKit/Source/core/svg/SVGScriptElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGScriptElement.cpp
@@ -20,8 +20,8 @@
 
 #include "core/svg/SVGScriptElement.h"
 
-#include "bindings/core/v8/HTMLScriptElementOrSVGScriptElement.h"
 #include "bindings/core/v8/ScriptEventListener.h"
+#include "bindings/core/v8/html_script_element_or_svg_script_element.h"
 #include "core/HTMLNames.h"
 #include "core/XLinkNames.h"
 #include "core/dom/Attribute.h"
diff --git a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp
index 8d9aeab..e4811a4 100644
--- a/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp
+++ b/third_party/WebKit/Source/core/testing/CallbackFunctionTest.cpp
@@ -4,12 +4,12 @@
 
 #include "core/testing/CallbackFunctionTest.h"
 
-#include "bindings/core/v8/TestCallback.h"
-#include "bindings/core/v8/TestEnumCallback.h"
-#include "bindings/core/v8/TestInterfaceCallback.h"
-#include "bindings/core/v8/TestReceiverObjectCallback.h"
-#include "bindings/core/v8/TestSequenceCallback.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/test_callback.h"
+#include "bindings/core/v8/test_enum_callback.h"
+#include "bindings/core/v8/test_interface_callback.h"
+#include "bindings/core/v8/test_receiver_object_callback.h"
+#include "bindings/core/v8/test_sequence_callback.h"
 #include "core/html/HTMLDivElement.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/testing/DictionaryTest.h b/third_party/WebKit/Source/core/testing/DictionaryTest.h
index 8314af5..efef8312 100644
--- a/third_party/WebKit/Source/core/testing/DictionaryTest.h
+++ b/third_party/WebKit/Source/core/testing/DictionaryTest.h
@@ -5,9 +5,9 @@
 #ifndef DictionaryTest_h
 #define DictionaryTest_h
 
-#include "bindings/core/v8/DoubleOrString.h"
 #include "bindings/core/v8/Nullable.h"
 #include "bindings/core/v8/ScriptValue.h"
+#include "bindings/core/v8/double_or_string.h"
 #include "core/dom/Element.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/core/testing/DummyModulator.cpp b/third_party/WebKit/Source/core/testing/DummyModulator.cpp
index 0cdf87ed..fecf212 100644
--- a/third_party/WebKit/Source/core/testing/DummyModulator.cpp
+++ b/third_party/WebKit/Source/core/testing/DummyModulator.cpp
@@ -136,4 +136,9 @@
   NOTREACHED();
 }
 
+ModuleScriptFetcher* DummyModulator::CreateModuleScriptFetcher() {
+  NOTREACHED();
+  return nullptr;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/testing/DummyModulator.h b/third_party/WebKit/Source/core/testing/DummyModulator.h
index e492eb0..ce656fa 100644
--- a/third_party/WebKit/Source/core/testing/DummyModulator.h
+++ b/third_party/WebKit/Source/core/testing/DummyModulator.h
@@ -63,6 +63,7 @@
   ScriptValue GetError(const ModuleScript*) override;
   Vector<ModuleRequest> ModuleRequestsFromScriptModule(ScriptModule) override;
   void ExecuteModule(const ModuleScript*) override;
+  ModuleScriptFetcher* CreateModuleScriptFetcher() override;
 
   Member<ScriptModuleResolver> resolver_;
 };
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index d9a3cbb..8cb319d 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -149,8 +149,8 @@
 
     [RaisesException] long lastSpellCheckRequestSequence(Document document);
     [RaisesException] long lastSpellCheckProcessedSequence(Document document);
-    [RuntimeEnabled=IdleTimeSpellChecking, RaisesException] DOMString idleTimeSpellCheckerState(Document document);
-    [RuntimeEnabled=IdleTimeSpellChecking, RaisesException] void runIdleTimeSpellChecker(Document document);
+    [RaisesException] DOMString idleTimeSpellCheckerState(Document document);
+    [RaisesException] void runIdleTimeSpellChecker(Document document);
 
     sequence<DOMString> userPreferredLanguages();
     void setUserPreferredLanguages(sequence<DOMString> languages);
diff --git a/third_party/WebKit/Source/core/testing/MockHyphenation.cpp b/third_party/WebKit/Source/core/testing/MockHyphenation.cpp
index de93bf18..ef1f6b0 100644
--- a/third_party/WebKit/Source/core/testing/MockHyphenation.cpp
+++ b/third_party/WebKit/Source/core/testing/MockHyphenation.cpp
@@ -10,10 +10,10 @@
                                            size_t before_index) const {
   String str = text.ToString();
   if (str.EndsWithIgnoringASCIICase("phenation")) {
-    if (before_index - (str.length() - 9) > 4)
+    if (before_index > 4 + (str.length() - 9))
       return 4 + (str.length() - 9);
     if (str.EndsWithIgnoringASCIICase("hyphenation") &&
-        before_index - (str.length() - 11) > 2) {
+        before_index > 2 + (str.length() - 11)) {
       return 2 + (str.length() - 11);
     }
   }
diff --git a/third_party/WebKit/Source/core/testing/RecordTest.h b/third_party/WebKit/Source/core/testing/RecordTest.h
index 76299ab..d7ab697 100644
--- a/third_party/WebKit/Source/core/testing/RecordTest.h
+++ b/third_party/WebKit/Source/core/testing/RecordTest.h
@@ -6,9 +6,9 @@
 #define RecordTest_h
 
 #include <utility>
-#include "bindings/core/v8/BooleanOrByteStringByteStringRecord.h"
-#include "bindings/core/v8/FloatOrStringElementRecord.h"
 #include "bindings/core/v8/Nullable.h"
+#include "bindings/core/v8/boolean_or_byte_string_byte_string_record.h"
+#include "bindings/core/v8/float_or_string_element_record.h"
 #include "core/dom/Element.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/core/testing/SequenceTest.h b/third_party/WebKit/Source/core/testing/SequenceTest.h
index 31a343c5..dd9c049 100644
--- a/third_party/WebKit/Source/core/testing/SequenceTest.h
+++ b/third_party/WebKit/Source/core/testing/SequenceTest.h
@@ -5,8 +5,8 @@
 #ifndef SequenceTest_h
 #define SequenceTest_h
 
-#include "bindings/core/v8/DoubleOrDoubleSequence.h"
 #include "bindings/core/v8/Nullable.h"
+#include "bindings/core/v8/double_or_double_sequence.h"
 #include "core/dom/Element.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/core/testing/UnionTypesTest.h b/third_party/WebKit/Source/core/testing/UnionTypesTest.h
index 6589770..3ef1503 100644
--- a/third_party/WebKit/Source/core/testing/UnionTypesTest.h
+++ b/third_party/WebKit/Source/core/testing/UnionTypesTest.h
@@ -5,10 +5,10 @@
 #ifndef UnionTypesTest_h
 #define UnionTypesTest_h
 
-#include "bindings/core/v8/DoubleOrInternalEnum.h"
-#include "bindings/core/v8/DoubleOrString.h"
-#include "bindings/core/v8/DoubleOrStringOrStringSequence.h"
-#include "bindings/core/v8/NodeListOrElement.h"
+#include "bindings/core/v8/double_or_internal_enum.h"
+#include "bindings/core/v8/double_or_string.h"
+#include "bindings/core/v8/double_or_string_or_string_sequence.h"
+#include "bindings/core/v8/node_list_or_element.h"
 #include "platform/wtf/text/WTFString.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
index 7ffc27bc..519ee69 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
@@ -4,8 +4,8 @@
 
 #include "core/timing/Performance.h"
 
-#include "bindings/core/v8/PerformanceObserverCallback.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/performance_observer_callback.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/testing/DummyPageHolder.h"
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
index 596f2277..722c608 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
@@ -7,8 +7,8 @@
 #include <algorithm>
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/PerformanceObserverCallback.h"
 #include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/performance_observer_callback.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/timing/DOMWindowPerformance.h"
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
index 5caa271..d408e4f 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
@@ -4,8 +4,8 @@
 
 #include "core/timing/PerformanceObserver.h"
 
-#include "bindings/core/v8/PerformanceObserverCallback.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/performance_observer_callback.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/timing/Performance.h"
diff --git a/third_party/WebKit/Source/core/typed_arrays/DOMArrayPiece.cpp b/third_party/WebKit/Source/core/typed_arrays/DOMArrayPiece.cpp
index cee5b8c..70523f85b 100644
--- a/third_party/WebKit/Source/core/typed_arrays/DOMArrayPiece.cpp
+++ b/third_party/WebKit/Source/core/typed_arrays/DOMArrayPiece.cpp
@@ -4,7 +4,7 @@
 
 #include "core/typed_arrays/DOMArrayPiece.h"
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/url/URLSearchParams.h b/third_party/WebKit/Source/core/url/URLSearchParams.h
index 8f2edee0f..1c70d3cd 100644
--- a/third_party/WebKit/Source/core/url/URLSearchParams.h
+++ b/third_party/WebKit/Source/core/url/URLSearchParams.h
@@ -8,7 +8,7 @@
 #include <base/gtest_prod_util.h>
 #include <utility>
 #include "bindings/core/v8/Iterable.h"
-#include "bindings/core/v8/USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString.h"
+#include "bindings/core/v8/usv_string_sequence_sequence_or_usv_string_usv_string_record_or_usv_string.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
 #include "platform/network/EncodedFormData.h"
diff --git a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.cpp b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.cpp
index 2d440c6..b98df5c 100644
--- a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.cpp
@@ -4,7 +4,7 @@
 
 #include "core/workers/WorkletModuleResponsesMap.h"
 
-#include "core/loader/modulescript/ModuleScriptFetcher.h"
+#include "core/loader/modulescript/DocumentModuleScriptFetcher.h"
 #include "platform/wtf/Optional.h"
 
 namespace blink {
@@ -28,10 +28,10 @@
   Entry() = default;
   ~Entry() = default;
 
-  void Fetch(const FetchParameters fetch_params, ResourceFetcher* fetcher) {
+  void Fetch(FetchParameters& fetch_params, ResourceFetcher* fetcher) {
     AdvanceState(State::kFetching);
-    module_fetcher_ = new ModuleScriptFetcher(fetch_params, fetcher, this);
-    module_fetcher_->Fetch();
+    module_fetcher_ = new DocumentModuleScriptFetcher(fetcher);
+    module_fetcher_->Fetch(fetch_params, this);
   }
 
   State GetState() const { return state_; }
@@ -106,7 +106,7 @@
 
   State state_ = State::kInitial;
 
-  Member<ModuleScriptFetcher> module_fetcher_;
+  Member<DocumentModuleScriptFetcher> module_fetcher_;
 
   WTF::Optional<ModuleScriptCreationParams> params_;
   HeapVector<Member<WorkletModuleResponsesMap::Client>> clients_;
@@ -122,7 +122,7 @@
 // "To perform the fetch given request, perform the following steps:"
 // Step 1: "Let cache be the moduleResponsesMap."
 // Step 2: "Let url be request's url."
-void WorkletModuleResponsesMap::ReadEntry(const FetchParameters& fetch_params,
+void WorkletModuleResponsesMap::ReadEntry(FetchParameters& fetch_params,
                                           Client* client) {
   DCHECK(IsMainThread());
   if (!is_available_ || !IsValidURL(fetch_params.Url())) {
diff --git a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.h b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.h
index b812198..9102473 100644
--- a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.h
+++ b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMap.h
@@ -25,9 +25,9 @@
 // scripts, but also performs fetch when needed. The creation params are added
 // and retrieved using ReadEntry(). If a module script for a given URL has
 // already been fetched, ReadEntry() returns the cached creation params.
-// Otherwise, ReadEntry() internally creates ModuleScriptFetcher with the
-// ResourceFetcher that is given to its ctor. Once the module script is fetched,
-// its creation params are cached and ReadEntry() returns it.
+// Otherwise, ReadEntry() internally creates DocumentModuleScriptFetcher with
+// thie ResourceFetcher that is given to its ctor. Once the module script is
+// fetched, its creation params are cached and ReadEntry() returns it.
 class CORE_EXPORT WorkletModuleResponsesMap
     : public GarbageCollectedFinalized<WorkletModuleResponsesMap> {
  public:
@@ -45,7 +45,7 @@
   // Reads an entry for the given URL. If the entry is already fetched,
   // synchronously calls Client::OnRead(). Otherwise, it's called on the
   // completion of the fetch. See also the class-level comment.
-  void ReadEntry(const FetchParameters&, Client*);
+  void ReadEntry(FetchParameters&, Client*);
 
   // Invalidates the entry and calls OnFailed() for waiting clients.
   void InvalidateEntry(const KURL&);
diff --git a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapProxy.cpp b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapProxy.cpp
index dfacafe..3cbd764 100644
--- a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapProxy.cpp
@@ -97,13 +97,13 @@
 }
 
 void WorkletModuleResponsesMapProxy::ReadEntryOnMainThread(
-    std::unique_ptr<CrossThreadFetchParametersData> fetch_params,
+    std::unique_ptr<CrossThreadFetchParametersData> cross_thread_fetch_params,
     Client* client) {
   DCHECK(IsMainThread());
+  FetchParameters fetch_params(std::move(cross_thread_fetch_params));
   ClientAdapter* wrapper =
       ClientAdapter::Create(client, inside_settings_task_runner_);
-  module_responses_map_->ReadEntry(FetchParameters(std::move(fetch_params)),
-                                   wrapper);
+  module_responses_map_->ReadEntry(fetch_params, wrapper);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapTest.cpp b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapTest.cpp
index ce01feb..0234271 100644
--- a/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapTest.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkletModuleResponsesMapTest.cpp
@@ -63,6 +63,12 @@
     map_ = new WorkletModuleResponsesMap(fetcher_);
   }
 
+  void ReadEntry(const KURL& url, ClientImpl* client) {
+    ResourceRequest resource_request(url);
+    FetchParameters fetch_params(resource_request);
+    map_->ReadEntry(fetch_params, client);
+  }
+
  protected:
   ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_;
   std::unique_ptr<DummyPageHolder> dummy_page_holder_;
@@ -78,18 +84,18 @@
 
   // An initial read call initiates a fetch request.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl)), clients[0]);
+  ReadEntry(kUrl, clients[0]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
   EXPECT_FALSE(clients[0]->GetParams().has_value());
 
   // The entry is now being fetched. Following read calls should wait for the
   // completion.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl)), clients[1]);
+  ReadEntry(kUrl, clients[1]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
 
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl)), clients[2]);
+  ReadEntry(kUrl, clients[2]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
 
   // Serve the fetch request. This should notify the waiting clients.
@@ -107,18 +113,18 @@
 
   // An initial read call initiates a fetch request.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl)), clients[0]);
+  ReadEntry(kUrl, clients[0]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
   EXPECT_FALSE(clients[0]->GetParams().has_value());
 
   // The entry is now being fetched. Following read calls should wait for the
   // completion.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl)), clients[1]);
+  ReadEntry(kUrl, clients[1]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
 
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl)), clients[2]);
+  ReadEntry(kUrl, clients[2]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
 
   // Serve the fetch request with 404. This should fail the waiting clients.
@@ -139,26 +145,26 @@
 
   // An initial read call for |kUrl1| initiates a fetch request.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl1)), clients[0]);
+  ReadEntry(kUrl1, clients[0]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
   EXPECT_FALSE(clients[0]->GetParams().has_value());
 
   // The entry is now being fetched. Following read calls for |kUrl1| should
   // wait for the completion.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl1)), clients[1]);
+  ReadEntry(kUrl1, clients[1]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
 
   // An initial read call for |kUrl2| initiates a fetch request.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl2)), clients[2]);
+  ReadEntry(kUrl2, clients[2]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
   EXPECT_FALSE(clients[2]->GetParams().has_value());
 
   // The entry is now being fetched. Following read calls for |kUrl2| should
   // wait for the completion.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl2)), clients[3]);
+  ReadEntry(kUrl2, clients[3]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[3]->GetResult());
 
   // The read call for |kUrl2| should not affect the other entry for |kUrl1|.
@@ -180,21 +186,21 @@
   const KURL kEmptyURL;
   ASSERT_TRUE(kEmptyURL.IsEmpty());
   ClientImpl* client1 = new ClientImpl;
-  map_->ReadEntry(FetchParameters(ResourceRequest(kEmptyURL)), client1);
+  ReadEntry(kEmptyURL, client1);
   EXPECT_EQ(ClientImpl::Result::kFailed, client1->GetResult());
   EXPECT_FALSE(client1->GetParams().has_value());
 
   const KURL kNullURL = NullURL();
   ASSERT_TRUE(kNullURL.IsNull());
   ClientImpl* client2 = new ClientImpl;
-  map_->ReadEntry(FetchParameters(ResourceRequest(kNullURL)), client2);
+  ReadEntry(kNullURL, client2);
   EXPECT_EQ(ClientImpl::Result::kFailed, client2->GetResult());
   EXPECT_FALSE(client2->GetParams().has_value());
 
   const KURL kInvalidURL(kParsedURLString, String());
   ASSERT_FALSE(kInvalidURL.IsValid());
   ClientImpl* client3 = new ClientImpl;
-  map_->ReadEntry(FetchParameters(ResourceRequest(kInvalidURL)), client3);
+  ReadEntry(kInvalidURL, client3);
   EXPECT_EQ(ClientImpl::Result::kFailed, client3->GetResult());
   EXPECT_FALSE(client3->GetParams().has_value());
 }
@@ -211,27 +217,27 @@
   // An initial read call for |kUrl1| creates a placeholder entry and asks the
   // client to fetch a module script.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl1)), clients[0]);
+  ReadEntry(kUrl1, clients[0]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[0]->GetResult());
   EXPECT_FALSE(clients[0]->GetParams().has_value());
 
   // The entry is now being fetched. Following read calls for |kUrl1| should
   // wait for the completion.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl1)), clients[1]);
+  ReadEntry(kUrl1, clients[1]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[1]->GetResult());
 
   // An initial read call for |kUrl2| also creates a placeholder entry and asks
   // the client to fetch a module script.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl2)), clients[2]);
+  ReadEntry(kUrl2, clients[2]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[2]->GetResult());
   EXPECT_FALSE(clients[2]->GetParams().has_value());
 
   // The entry is now being fetched. Following read calls for |kUrl2| should
   // wait for the completion.
   clients.push_back(new ClientImpl);
-  map_->ReadEntry(FetchParameters(ResourceRequest(kUrl2)), clients[3]);
+  ReadEntry(kUrl2, clients[3]);
   EXPECT_EQ(ClientImpl::Result::kInitial, clients[3]->GetResult());
 
   // Dispose() should notify to all waiting clients.
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
index 29d2c56..83040c71 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -24,9 +24,9 @@
 #include "core/xmlhttprequest/XMLHttpRequest.h"
 
 #include <memory>
-#include "bindings/core/v8/ArrayBufferOrArrayBufferViewOrBlobOrDocumentOrStringOrFormDataOrURLSearchParams.h"
-#include "bindings/core/v8/ArrayBufferOrArrayBufferViewOrBlobOrUSVString.h"
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_document_or_string_or_form_data_or_url_search_params.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/DOMImplementation.h"
 #include "core/dom/DocumentInit.h"
@@ -262,26 +262,30 @@
 XMLHttpRequest* XMLHttpRequest::Create(ScriptState* script_state) {
   ExecutionContext* context = ExecutionContext::From(script_state);
   DOMWrapperWorld& world = script_state->World();
-  if (!world.IsIsolatedWorld())
-    return Create(context);
+  v8::Isolate* isolate = script_state->GetIsolate();
 
   XMLHttpRequest* xml_http_request =
-      new XMLHttpRequest(context, true, world.IsolatedWorldSecurityOrigin());
+      world.IsIsolatedWorld()
+          ? new XMLHttpRequest(context, isolate, true,
+                               world.IsolatedWorldSecurityOrigin())
+          : new XMLHttpRequest(context, isolate, false, nullptr);
   xml_http_request->SuspendIfNeeded();
-
   return xml_http_request;
 }
 
 XMLHttpRequest* XMLHttpRequest::Create(ExecutionContext* context) {
-  XMLHttpRequest* xml_http_request =
-      new XMLHttpRequest(context, false, nullptr);
-  xml_http_request->SuspendIfNeeded();
+  v8::Isolate* isolate = ToIsolate(context);
+  CHECK(isolate);
 
+  XMLHttpRequest* xml_http_request =
+      new XMLHttpRequest(context, isolate, false, nullptr);
+  xml_http_request->SuspendIfNeeded();
   return xml_http_request;
 }
 
 XMLHttpRequest::XMLHttpRequest(
     ExecutionContext* context,
+    v8::Isolate* isolate,
     bool is_isolated_world,
     RefPtr<SecurityOrigin> isolated_world_security_origin)
     : SuspendableObject(context),
@@ -293,6 +297,7 @@
       progress_event_throttle_(
           XMLHttpRequestProgressEventThrottle::Create(this)),
       response_type_code_(kResponseTypeDefault),
+      isolate_(isolate),
       is_isolated_world_(is_isolated_world),
       isolated_world_security_origin_(
           std::move(isolated_world_security_origin)),
@@ -309,7 +314,11 @@
       send_flag_(false),
       response_array_buffer_failure_(false) {}
 
-XMLHttpRequest::~XMLHttpRequest() {}
+XMLHttpRequest::~XMLHttpRequest() {
+  binary_response_builder_.Clear();
+  length_downloaded_to_file_ = 0;
+  ReportMemoryUsageToV8();
+}
 
 Document* XMLHttpRequest::GetDocument() const {
   DCHECK(GetExecutionContext()->IsDocument());
@@ -434,6 +443,7 @@
         blob_data->SetContentType(
             FinalResponseMIMETypeWithFallback().LowerASCII());
         binary_response_builder_.Clear();
+        ReportMemoryUsageToV8();
       }
       response_blob_ =
           Blob::Create(BlobDataHandle::Create(std::move(blob_data), size));
@@ -463,6 +473,7 @@
       // of the 'received bytes' payload when the response buffer allocation
       // fails.
       binary_response_builder_.Clear();
+      ReportMemoryUsageToV8();
       // Mark allocation as failed; subsequent calls to the accessor must
       // continue to report |null|.
       //
@@ -1236,6 +1247,8 @@
   binary_response_builder_.Clear();
   response_array_buffer_.Clear();
   response_array_buffer_failure_ = false;
+
+  ReportMemoryUsageToV8();
 }
 
 void XMLHttpRequest::ClearRequest() {
@@ -1819,6 +1832,7 @@
     if (!binary_response_builder_)
       binary_response_builder_ = SharedBuffer::Create();
     binary_response_builder_->Append(data, len);
+    ReportMemoryUsageToV8();
   }
 
   if (blob_loader_) {
@@ -1848,6 +1862,7 @@
     return;
 
   length_downloaded_to_file_ += data_length;
+  ReportMemoryUsageToV8();
 
   TrackProgress(data_length);
 }
@@ -1902,6 +1917,23 @@
   return SuspendableObject::GetExecutionContext();
 }
 
+void XMLHttpRequest::ReportMemoryUsageToV8() {
+  // binary_response_builder_
+  size_t size = binary_response_builder_ ? binary_response_builder_->size() : 0;
+  int64_t diff =
+      static_cast<int64_t>(size) -
+      static_cast<int64_t>(binary_response_builder_last_reported_size_);
+  binary_response_builder_last_reported_size_ = size;
+
+  // Blob (downloading_to_file_, length_downloaded_to_file_)
+  diff += static_cast<int64_t>(length_downloaded_to_file_) -
+          static_cast<int64_t>(length_downloaded_to_file_last_reported_);
+  length_downloaded_to_file_last_reported_ = length_downloaded_to_file_;
+
+  if (diff)
+    isolate_->AdjustAmountOfExternalAllocatedMemory(diff);
+}
+
 DEFINE_TRACE(XMLHttpRequest) {
   visitor->Trace(response_blob_);
   visitor->Trace(loader_);
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
index 7dfd686a..b2e7cada 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
@@ -170,6 +170,7 @@
  private:
   class BlobLoader;
   XMLHttpRequest(ExecutionContext*,
+                 v8::Isolate*,
                  bool is_isolated_world,
                  RefPtr<SecurityOrigin>);
 
@@ -287,6 +288,17 @@
 
   XMLHttpRequestProgressEventThrottle& ProgressEventThrottle();
 
+  // Report the memory usage associated with this object to V8 so that V8 can
+  // schedule GC accordingly.  This function should be called whenever the
+  // internal memory usage changes except for the following members.
+  // - response_text_ of type ScriptString
+  //   ScriptString internally creates and holds a v8::String, so V8 is aware of
+  //   its memory usage.
+  // - response_array_buffer_ of type DOMArrayBuffer
+  //   DOMArrayBuffer supports the memory usage reporting system on their own,
+  //   so there is no need.
+  void ReportMemoryUsageToV8();
+
   Member<XMLHttpRequestUpload> upload_;
 
   KURL url_;
@@ -310,7 +322,9 @@
   Member<DocumentParser> response_document_parser_;
 
   RefPtr<SharedBuffer> binary_response_builder_;
+  size_t binary_response_builder_last_reported_size_ = 0;
   long long length_downloaded_to_file_;
+  long long length_downloaded_to_file_last_reported_ = 0;
 
   TraceWrapperMember<DOMArrayBuffer> response_array_buffer_;
 
@@ -328,6 +342,7 @@
   // attribute.
   ResponseTypeCode response_type_code_;
 
+  v8::Isolate* const isolate_;
   // Set to true if the XMLHttpRequest was created in an isolated world.
   bool is_isolated_world_;
   // Stores the SecurityOrigin associated with the isolated world if any.
diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
index ee328aa..30d8d88 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
@@ -115,8 +115,11 @@
       return null;
 
     var inspectedURL = SDK.targetManager.mainTarget().inspectedURL();
-    if (/^about:/.test(inspectedURL))
-      return Common.UIString('Cannot audit about:* pages. Navigate to a different page to start an audit.');
+    if (!/^(http|chrome-extension)/.test(inspectedURL)) {
+      return Common.UIString(
+          'Can only audit HTTP/HTTPS pages and Chrome extensions. ' +
+          'Navigate to a different page to start an audit.');
+    }
 
     if (!Runtime.queryParam('can_dock'))
       return Common.UIString('Can only audit tabs. Navigate to this page in a separate tab to start an audit.');
@@ -411,7 +414,14 @@
     this._statusIcon.classList.add('error');
     this._statusElement.createTextChild(Common.UIString('Ah, sorry! We ran into an error: '));
     this._statusElement.createChild('em').createTextChild(err.message);
-    this._createBugReportLink(err, this._statusElement);
+    if (Audits2.Audits2Panel.KnownBugPatterns.some(pattern => pattern.test(err.message))) {
+      var message = Common.UIString(
+          'Try to navigate to the URL in a fresh Chrome profile without any other tabs or ' +
+          'extensions open and try again.');
+      this._statusElement.createChild('p').createTextChild(message);
+    } else {
+      this._createBugReportLink(err, this._statusElement);
+    }
   }
 
   /**
@@ -431,7 +441,7 @@
 ${err.stack}
 \`\`\`
     `;
-    var body = '&body=' + encodeURI(issueBody.trim());
+    var body = '&body=' + encodeURIComponent(issueBody.trim());
     var reportErrorEl = parentElem.createChild('a', 'audits2-link audits2-report-error');
     reportErrorEl.href = baseURI + title + body;
     reportErrorEl.textContent = Common.UIString('Report this bug');
@@ -500,6 +510,14 @@
   }
 }
 
+/** @type {!Array.<!RegExp>} */
+Audits2.Audits2Panel.KnownBugPatterns = [
+  /Tracing already started/,
+  /^Unable to load the page/,
+  /^You must provide a url to the runner/,
+  /^You probably have multiple tabs open/,
+];
+
 /** @typedef {{setting: !Common.Setting, configID: string, title: string, description: string}} */
 Audits2.Audits2Panel.Preset;
 
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings_test_runner/IsolatedFilesystemTestRunner.js b/third_party/WebKit/Source/devtools/front_end/bindings_test_runner/IsolatedFilesystemTestRunner.js
index 6c77c419..e545693ea 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings_test_runner/IsolatedFilesystemTestRunner.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings_test_runner/IsolatedFilesystemTestRunner.js
@@ -69,7 +69,7 @@
 
   addFileMapping: function(urlPrefix, pathPrefix) {
     var fileSystemMapping = new Persistence.FileSystemMapping(Persistence.isolatedFileSystemManager);
-    fileSystemMapping.addFileSystem(this.fileSystemPath);
+    fileSystemMapping._addFileSystemPath(this.fileSystemPath);
     fileSystemMapping.addFileMapping(this.fileSystemPath, urlPrefix, pathPrefix);
     fileSystemMapping.dispose();
     Persistence.fileSystemMapping._loadFromSettings();
diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemMapping.js b/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemMapping.js
index efdf27d..3922fea 100644
--- a/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemMapping.js
@@ -28,9 +28,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/**
- * @unrestricted
- */
 Persistence.FileSystemMapping = class extends Common.Object {
   /**
    * @param {!Persistence.IsolatedFileSystemManager} fileSystemManager
@@ -38,6 +35,11 @@
   constructor(fileSystemManager) {
     super();
     this._fileSystemMappingSetting = Common.settings.createLocalSetting('fileSystemMapping', {});
+    /** @type {!Object<string, !Persistence.FileSystemMapping.Entry>} */
+    this._mappingForURLPrefix = {};
+    /** @type {!Array<string>} */
+    this._urlPrefixes = [];
+
     /** @type {!Object.<string, !Array.<!Persistence.FileSystemMapping.Entry>>} */
     this._fileSystemMappings = {};
     this._loadFromSettings();
@@ -56,7 +58,7 @@
    */
   _fileSystemsLoaded(fileSystems) {
     for (var fileSystem of fileSystems)
-      this.addFileSystem(fileSystem.path());
+      this._addFileSystemPath(fileSystem.path());
   }
 
   /**
@@ -64,7 +66,7 @@
    */
   _fileSystemAdded(event) {
     var fileSystem = /** @type {!Persistence.IsolatedFileSystem} */ (event.data);
-    this.addFileSystem(fileSystem.path());
+    this._addFileSystemPath(fileSystem.path());
   }
 
   /**
@@ -72,7 +74,7 @@
    */
   _fileSystemRemoved(event) {
     var fileSystem = /** @type {!Persistence.IsolatedFileSystem} */ (event.data);
-    this.removeFileSystem(fileSystem.path());
+    this._removeFileSystemPath(fileSystem.path());
   }
 
   _loadFromSettings() {
@@ -109,23 +111,17 @@
   _rebuildIndexes() {
     // We are building an index here to search for the longest url prefix match faster.
     this._mappingForURLPrefix = {};
-    this._urlPrefixes = [];
-    for (var fileSystemPath in this._fileSystemMappings) {
-      var fileSystemMapping = this._fileSystemMappings[fileSystemPath];
-      for (var i = 0; i < fileSystemMapping.length; ++i) {
-        var entry = fileSystemMapping[i];
+    for (var fileSystemMapping of Object.values(this._fileSystemMappings)) {
+      for (var entry of fileSystemMapping)
         this._mappingForURLPrefix[entry.urlPrefix] = entry;
-        if (this._urlPrefixes.indexOf(entry.urlPrefix) === -1)
-          this._urlPrefixes.push(entry.urlPrefix);
-      }
     }
-    this._urlPrefixes.sort();
+    this._urlPrefixes = Object.keys(this._mappingForURLPrefix).sort();
   }
 
   /**
    * @param {string} fileSystemPath
    */
-  addFileSystem(fileSystemPath) {
+  _addFileSystemPath(fileSystemPath) {
     if (this._fileSystemMappings[fileSystemPath])
       return;
 
@@ -136,7 +132,7 @@
   /**
    * @param {string} fileSystemPath
    */
-  removeFileSystem(fileSystemPath) {
+  _removeFileSystemPath(fileSystemPath) {
     if (!this._fileSystemMappings[fileSystemPath])
       return;
     delete this._fileSystemMappings[fileSystemPath];
@@ -330,9 +326,6 @@
   FileMappingRemoved: Symbol('FileMappingRemoved')
 };
 
-/**
- * @unrestricted
- */
 Persistence.FileSystemMapping.Entry = class {
   /**
    * @param {string} fileSystemPath
@@ -340,8 +333,11 @@
    * @param {string} pathPrefix
    */
   constructor(fileSystemPath, urlPrefix, pathPrefix) {
+    /** @const */
     this.fileSystemPath = fileSystemPath;
+    /** @const */
     this.urlPrefix = urlPrefix;
+    /** @const */
     this.pathPrefix = pathPrefix;
   }
 };
diff --git a/third_party/WebKit/Source/modules/BUILD.gn b/third_party/WebKit/Source/modules/BUILD.gn
index bd0ad08..0130611 100644
--- a/third_party/WebKit/Source/modules/BUILD.gn
+++ b/third_party/WebKit/Source/modules/BUILD.gn
@@ -178,7 +178,7 @@
   }
 }
 
-source_set("modules_testing") {
+jumbo_source_set("modules_testing") {
   sources = [
     "$bindings_modules_v8_output_dir/V8InternalsPartial.cpp",
     "$bindings_modules_v8_output_dir/V8InternalsPartial.h",
@@ -230,7 +230,7 @@
   ]
 }
 
-source_set("unit_tests") {
+jumbo_source_set("unit_tests") {
   testonly = true
 
   sources = [
diff --git a/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp b/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp
index f3ad82b0..4502134 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp
@@ -136,6 +136,8 @@
                    AXDefaultActionVerb::kActivate);
 STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kCheck, AXDefaultActionVerb::kCheck);
 STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kClick, AXDefaultActionVerb::kClick);
+STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kClickAncestor,
+                   AXDefaultActionVerb::kClickAncestor);
 STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kJump, AXDefaultActionVerb::kJump);
 STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kOpen, AXDefaultActionVerb::kOpen);
 STATIC_ASSERT_ENUM(WebAXDefaultActionVerb::kPress, AXDefaultActionVerb::kPress);
diff --git a/third_party/WebKit/Source/modules/accessibility/AXEnums.h b/third_party/WebKit/Source/modules/accessibility/AXEnums.h
index 73ea4ce..d3d7ca6 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXEnums.h
+++ b/third_party/WebKit/Source/modules/accessibility/AXEnums.h
@@ -140,6 +140,13 @@
   kActivate,
   kCheck,
   kClick,
+
+  // A click will be performed on one of the object's ancestors.
+  // This happens when the object itself is not clickable, but one of its
+  // ancestors has click handlers attached which are able to capture the click
+  // as it bubbles up.
+  kClickAncestor,
+
   kJump,
   kOpen,
   kPress,
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index 4f745aa..ce1fe47 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -986,12 +986,6 @@
 
   for (Element* element = ToElement(node); element;
        element = element->parentElement()) {
-    // It's a pretty common practice to put click listeners on the body or
-    // document, but that's almost never what the user wants when clicking on an
-    // accessible element.
-    if (isHTMLBodyElement(element))
-      break;
-
     if (element->HasEventListeners(EventTypeNames::click) ||
         element->HasEventListeners(EventTypeNames::mousedown) ||
         element->HasEventListeners(EventTypeNames::mouseup) ||
@@ -999,7 +993,7 @@
       return element;
   }
 
-  return 0;
+  return nullptr;
 }
 
 AccessibilityRole AXNodeObject::RemapAriaRoleDueToParent(
@@ -1286,18 +1280,20 @@
 }
 
 bool AXNodeObject::IsClickable() const {
-  if (GetNode()) {
-    if (GetNode()->IsElementNode() &&
-        ToElement(GetNode())->IsDisabledFormControl())
-      return false;
+  Node* node = GetNode();
+  if (!node)
+    return false;
+  if (node->IsElementNode() && ToElement(node)->IsDisabledFormControl()) {
+    return false;
+  }
 
-    // Note: we can't call getNode()->willRespondToMouseClickEvents() because
-    // that triggers a style recalc and can delete this.
-    if (GetNode()->HasEventListeners(EventTypeNames::mouseup) ||
-        GetNode()->HasEventListeners(EventTypeNames::mousedown) ||
-        GetNode()->HasEventListeners(EventTypeNames::click) ||
-        GetNode()->HasEventListeners(EventTypeNames::DOMActivate))
-      return true;
+  // Note: we can't call |node->WillRespondToMouseClickEvents()| because that
+  // triggers a style recalc and can delete this.
+  if (node->HasEventListeners(EventTypeNames::mouseup) ||
+      node->HasEventListeners(EventTypeNames::mousedown) ||
+      node->HasEventListeners(EventTypeNames::click) ||
+      node->HasEventListeners(EventTypeNames::DOMActivate)) {
+    return true;
   }
 
   return AXObject::IsClickable();
@@ -1673,10 +1669,6 @@
 }
 
 String AXNodeObject::GetText() const {
-  // If this is a user defined static text, use the accessible name computation.
-  if (AriaRoleAttribute() == kStaticTextRole)
-    return ComputedName();
-
   if (!IsTextControl())
     return String();
 
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
index 70e5931..5efed77 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -1368,7 +1368,8 @@
 }
 
 AXDefaultActionVerb AXObject::Action() const {
-  if (!ActionElement())
+  Element* action_element = ActionElement();
+  if (!action_element)
     return AXDefaultActionVerb::kNone;
 
   // TODO(dmazzoni): Ensure that combo box text field is handled here.
@@ -1398,7 +1399,9 @@
     case kPopUpButtonRole:
       return AXDefaultActionVerb::kOpen;
     default:
-      return AXDefaultActionVerb::kClick;
+      if (action_element == GetNode())
+        return AXDefaultActionVerb::kClick;
+      return AXDefaultActionVerb::kClickAncestor;
   }
 }
 
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp
index 4b6cdfc..ede47957 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManager.cpp
@@ -5,8 +5,8 @@
 #include "modules/background_fetch/BackgroundFetchManager.h"
 
 #include "bindings/core/v8/ScriptPromiseResolver.h"
-#include "bindings/modules/v8/RequestOrUSVString.h"
-#include "bindings/modules/v8/RequestOrUSVStringOrRequestOrUSVStringSequence.h"
+#include "bindings/modules/v8/request_or_usv_string.h"
+#include "bindings/modules/v8/request_or_usv_string_or_request_or_usv_string_sequence.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/frame/Deprecation.h"
diff --git a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManagerTest.cpp b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManagerTest.cpp
index 5f8da88f..cc9cb04c 100644
--- a/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManagerTest.cpp
+++ b/third_party/WebKit/Source/modules/background_fetch/BackgroundFetchManagerTest.cpp
@@ -8,8 +8,8 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
-#include "bindings/modules/v8/RequestOrUSVString.h"
-#include "bindings/modules/v8/RequestOrUSVStringOrRequestOrUSVStringSequence.h"
+#include "bindings/modules/v8/request_or_usv_string.h"
+#include "bindings/modules/v8/request_or_usv_string_or_request_or_usv_string_sequence.h"
 #include "core/dom/ExceptionCode.h"
 #include "modules/fetch/Request.h"
 #include "platform/bindings/ScriptState.h"
diff --git a/third_party/WebKit/Source/modules/battery/BatteryManager.cpp b/third_party/WebKit/Source/modules/battery/BatteryManager.cpp
index 3c41a49ad..18bfc8e 100644
--- a/third_party/WebKit/Source/modules/battery/BatteryManager.cpp
+++ b/third_party/WebKit/Source/modules/battery/BatteryManager.cpp
@@ -23,7 +23,7 @@
 
 BatteryManager::BatteryManager(ExecutionContext* context)
     : SuspendableObject(context),
-      PlatformEventController(ToDocument(context)->GetFrame()) {}
+      PlatformEventController(ToDocument(context)) {}
 
 ScriptPromise BatteryManager::StartRequest(ScriptState* script_state) {
   if (!battery_property_) {
diff --git a/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.cpp b/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.cpp
index cfb1c9b0..ff19b2c 100644
--- a/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.cpp
+++ b/third_party/WebKit/Source/modules/beacon/NavigatorBeacon.cpp
@@ -5,7 +5,7 @@
 #include "modules/beacon/NavigatorBeacon.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/modules/v8/ArrayBufferViewOrBlobOrStringOrFormData.h"
+#include "bindings/modules/v8/array_buffer_view_or_blob_or_string_or_form_data.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/fileapi/Blob.h"
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h
index 4208ec90..cea49f5 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.h
@@ -5,7 +5,7 @@
 #ifndef BluetoothRemoteGATTServer_h
 #define BluetoothRemoteGATTServer_h
 
-#include "bindings/modules/v8/StringOrUnsignedLong.h"
+#include "bindings/modules/v8/string_or_unsigned_long.h"
 #include "core/dom/ContextLifecycleObserver.h"
 #include "modules/bluetooth/BluetoothDevice.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h
index a68a891..9ca795a 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.h
@@ -6,7 +6,7 @@
 #define BluetoothRemoteGATTService_h
 
 #include <memory>
-#include "bindings/modules/v8/StringOrUnsignedLong.h"
+#include "bindings/modules/v8/string_or_unsigned_long.h"
 #include "modules/bluetooth/BluetoothDevice.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.h
index 9af25653..90439e9 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.h
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothUUID.h
@@ -5,7 +5,7 @@
 #ifndef BluetoothUUID_h
 #define BluetoothUUID_h
 
-#include "bindings/modules/v8/StringOrUnsignedLong.h"
+#include "bindings/modules/v8/string_or_unsigned_long.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
 
diff --git a/third_party/WebKit/Source/modules/broadcastchannel/DEPS b/third_party/WebKit/Source/modules/broadcastchannel/DEPS
index 97c1ffe..16764a92 100644
--- a/third_party/WebKit/Source/modules/broadcastchannel/DEPS
+++ b/third_party/WebKit/Source/modules/broadcastchannel/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
-  "+components/webmessaging/public/interfaces/broadcast_channel.mojom-blink.h",
   "+mojo/public/cpp/bindings",
 ]
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
index a53b730..ec86083 100644
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
@@ -5,8 +5,8 @@
 #ifndef BaseRenderingContext2D_h
 #define BaseRenderingContext2D_h
 
-#include "bindings/modules/v8/CanvasImageSource.h"
-#include "bindings/modules/v8/StringOrCanvasGradientOrCanvasPattern.h"
+#include "bindings/modules/v8/canvas_image_source.h"
+#include "bindings/modules/v8/string_or_canvas_gradient_or_canvas_pattern.h"
 #include "core/html/ImageData.h"
 #include "modules/ModulesExport.h"
 #include "modules/canvas2d/CanvasGradient.h"
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index 077f55a..9313023 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -35,7 +35,7 @@
 
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/modules/v8/RenderingContext.h"
+#include "bindings/modules/v8/rendering_context.h"
 #include "core/CSSPropertyNames.h"
 #include "core/css/CSSFontSelector.h"
 #include "core/css/StyleEngine.h"
@@ -117,17 +117,17 @@
       try_restore_context_attempt_count_(0),
       dispatch_context_lost_event_timer_(
           TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI,
-                                canvas->GetDocument().GetFrame()),
+                                &canvas->GetDocument()),
           this,
           &CanvasRenderingContext2D::DispatchContextLostEvent),
       dispatch_context_restored_event_timer_(
           TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI,
-                                canvas->GetDocument().GetFrame()),
+                                &canvas->GetDocument()),
           this,
           &CanvasRenderingContext2D::DispatchContextRestoredEvent),
       try_restore_context_event_timer_(
           TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI,
-                                canvas->GetDocument().GetFrame()),
+                                &canvas->GetDocument()),
           this,
           &CanvasRenderingContext2D::TryRestoreContextEvent),
       should_prune_local_font_cache_(false) {
diff --git a/third_party/WebKit/Source/modules/credentialmanager/PasswordCredential.h b/third_party/WebKit/Source/modules/credentialmanager/PasswordCredential.h
index 331e284..182be1b 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/PasswordCredential.h
+++ b/third_party/WebKit/Source/modules/credentialmanager/PasswordCredential.h
@@ -6,7 +6,7 @@
 #define PasswordCredential_h
 
 #include "bindings/core/v8/serialization/SerializedScriptValue.h"
-#include "bindings/modules/v8/FormDataOrURLSearchParams.h"
+#include "bindings/modules/v8/form_data_or_url_search_params.h"
 #include "modules/ModulesExport.h"
 #include "modules/credentialmanager/Credential.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp b/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp
index 5e558c9..47beadd 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp
+++ b/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp
@@ -5,9 +5,9 @@
 #include "modules/credentialmanager/WebAuthenticationClient.h"
 
 #include <utility>
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
diff --git a/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp b/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp
index a2dd228f..5b1df320 100644
--- a/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp
+++ b/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.cpp
@@ -32,10 +32,10 @@
 
 #include <algorithm>
 #include <memory>
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/V8ArrayBuffer.h"
 #include "bindings/core/v8/V8ArrayBufferView.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
 #include "bindings/modules/v8/V8CryptoKey.h"
 #include "core/typed_arrays/DOMArrayPiece.h"
 #include "core/typed_arrays/DOMTypedArray.h"
diff --git a/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.h b/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.h
index 76d08b22..670cf93 100644
--- a/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.h
+++ b/third_party/WebKit/Source/modules/crypto/NormalizeAlgorithm.h
@@ -31,7 +31,7 @@
 #ifndef NormalizeAlgorithm_h
 #define NormalizeAlgorithm_h
 
-#include "bindings/modules/v8/DictionaryOrString.h"
+#include "bindings/modules/v8/dictionary_or_string.h"
 #include "modules/ModulesExport.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Assertions.h"
diff --git a/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h b/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h
index fa544254..467d292 100644
--- a/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h
+++ b/third_party/WebKit/Source/modules/crypto/SubtleCrypto.h
@@ -31,10 +31,10 @@
 #ifndef SubtleCrypto_h
 #define SubtleCrypto_h
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
 #include "bindings/core/v8/ScriptPromise.h"
-#include "bindings/modules/v8/ArrayBufferOrArrayBufferViewOrDictionary.h"
-#include "bindings/modules/v8/DictionaryOrString.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
+#include "bindings/modules/v8/array_buffer_or_array_buffer_view_or_dictionary.h"
+#include "bindings/modules/v8/dictionary_or_string.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Forward.h"
diff --git a/third_party/WebKit/Source/modules/encoding/TextDecoder.h b/third_party/WebKit/Source/modules/encoding/TextDecoder.h
index 26f59d20..4f46ff6 100644
--- a/third_party/WebKit/Source/modules/encoding/TextDecoder.h
+++ b/third_party/WebKit/Source/modules/encoding/TextDecoder.h
@@ -32,7 +32,7 @@
 #define TextDecoder_h
 
 #include <memory>
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
 #include "modules/encoding/TextDecodeOptions.h"
 #include "modules/encoding/TextDecoderOptions.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeyStatusMap.cpp b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeyStatusMap.cpp
index 116f7de..1c5bf37 100644
--- a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeyStatusMap.cpp
+++ b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeyStatusMap.cpp
@@ -4,7 +4,7 @@
 
 #include "modules/encryptedmedia/MediaKeyStatusMap.h"
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
 #include "core/typed_arrays/DOMArrayBuffer.h"
 #include "core/typed_arrays/DOMArrayPiece.h"
 #include "platform/SharedBuffer.h"
diff --git a/third_party/WebKit/Source/modules/fetch/BytesConsumerTestUtil.cpp b/third_party/WebKit/Source/modules/fetch/BytesConsumerTestUtil.cpp
index e06f03ba..f478ae7 100644
--- a/third_party/WebKit/Source/modules/fetch/BytesConsumerTestUtil.cpp
+++ b/third_party/WebKit/Source/modules/fetch/BytesConsumerTestUtil.cpp
@@ -13,12 +13,14 @@
 
 namespace blink {
 
+namespace {
 using Result = BytesConsumer::Result;
 using ::testing::_;
 using ::testing::ByMove;
 using ::testing::DoAll;
 using ::testing::Return;
 using ::testing::SetArgPointee;
+}  // namespace
 
 BytesConsumerTestUtil::MockBytesConsumer::MockBytesConsumer() {
   ON_CALL(*this, BeginRead(_, _))
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.cpp b/third_party/WebKit/Source/modules/fetch/Headers.cpp
index f9bfb1c..dd0a47c 100644
--- a/third_party/WebKit/Source/modules/fetch/Headers.cpp
+++ b/third_party/WebKit/Source/modules/fetch/Headers.cpp
@@ -6,7 +6,7 @@
 
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/V8IteratorResultValue.h"
-#include "bindings/modules/v8/ByteStringSequenceSequenceOrByteStringByteStringRecord.h"
+#include "bindings/modules/v8/byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
 #include "core/dom/Iterator.h"
 #include "platform/loader/fetch/FetchUtils.h"
 #include "platform/wtf/text/WTFString.h"
diff --git a/third_party/WebKit/Source/modules/fetch/Request.h b/third_party/WebKit/Source/modules/fetch/Request.h
index bda396e..6e8fad56 100644
--- a/third_party/WebKit/Source/modules/fetch/Request.h
+++ b/third_party/WebKit/Source/modules/fetch/Request.h
@@ -6,7 +6,7 @@
 #define Request_h
 
 #include "bindings/core/v8/Dictionary.h"
-#include "bindings/modules/v8/RequestOrUSVString.h"
+#include "bindings/modules/v8/request_or_usv_string.h"
 #include "modules/ModulesExport.h"
 #include "modules/fetch/Body.h"
 #include "modules/fetch/FetchRequestData.h"
diff --git a/third_party/WebKit/Source/modules/fetch/RequestInit.h b/third_party/WebKit/Source/modules/fetch/RequestInit.h
index 24912ef3..afc1846 100644
--- a/third_party/WebKit/Source/modules/fetch/RequestInit.h
+++ b/third_party/WebKit/Source/modules/fetch/RequestInit.h
@@ -5,7 +5,7 @@
 #ifndef RequestInit_h
 #define RequestInit_h
 
-#include "bindings/modules/v8/ByteStringSequenceSequenceOrByteStringByteStringRecord.h"
+#include "bindings/modules/v8/byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
 #include "modules/fetch/Headers.h"
 #include "platform/heap/Handle.h"
 #include "platform/network/EncodedFormData.h"
diff --git a/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.cpp b/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.cpp
index e079b4f..9042d8db 100644
--- a/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.cpp
+++ b/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.cpp
@@ -171,7 +171,8 @@
     : Supplement<Navigator>(navigator),
       ContextLifecycleObserver(
           navigator.GetFrame() ? navigator.GetFrame()->GetDocument() : nullptr),
-      PlatformEventController(navigator.GetFrame()),
+      PlatformEventController(
+          navigator.GetFrame() ? navigator.GetFrame()->GetDocument() : nullptr),
       dispatch_one_event_runner_(AsyncMethodRunner<NavigatorGamepad>::Create(
           this,
           &NavigatorGamepad::DispatchOneEvent)) {
diff --git a/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapRenderingContext.cpp b/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapRenderingContext.cpp
index 8e42fbb..fcba977 100644
--- a/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapRenderingContext.cpp
+++ b/third_party/WebKit/Source/modules/imagebitmap/ImageBitmapRenderingContext.cpp
@@ -4,7 +4,7 @@
 
 #include "modules/imagebitmap/ImageBitmapRenderingContext.h"
 
-#include "bindings/modules/v8/RenderingContext.h"
+#include "bindings/modules/v8/rendering_context.h"
 #include "core/imagebitmap/ImageBitmap.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/StaticBitmapImage.h"
diff --git a/third_party/WebKit/Source/modules/imagecapture/OWNERS b/third_party/WebKit/Source/modules/imagecapture/OWNERS
index 26e1bed..57aa41f 100644
--- a/third_party/WebKit/Source/modules/imagecapture/OWNERS
+++ b/third_party/WebKit/Source/modules/imagecapture/OWNERS
@@ -2,4 +2,4 @@
 reillyg@chromium.org
 
 # COMPONENT: Blink>ImageCapture
-# TEAM: device-dev@chromium.org
+# TEAM: media-dev@chromium.org
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
index 16df2f1..d2169c1e 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
@@ -28,8 +28,8 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/Nullable.h"
 #include "bindings/core/v8/serialization/SerializedScriptValue.h"
-#include "bindings/modules/v8/IDBObserverCallback.h"
 #include "bindings/modules/v8/V8BindingForModules.h"
+#include "bindings/modules/v8/idb_observer_callback.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/events/EventQueue.h"
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
index de8d7b9..e0100d3d 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
@@ -28,7 +28,7 @@
 
 #include <memory>
 
-#include "bindings/modules/v8/StringOrStringSequence.h"
+#include "bindings/modules/v8/string_or_string_sequence.h"
 #include "core/dom/ContextLifecycleObserver.h"
 #include "core/dom/DOMStringList.h"
 #include "modules/EventModules.h"
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.h b/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.h
index 78c867b..9e462fb 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBKeyPath.h
@@ -26,7 +26,7 @@
 #ifndef IDBKeyPath_h
 #define IDBKeyPath_h
 
-#include "bindings/modules/v8/StringOrStringSequence.h"
+#include "bindings/modules/v8/string_or_string_sequence.h"
 #include "modules/ModulesExport.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Vector.h"
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp
index a14a81e..6cbb5aa 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp
@@ -7,9 +7,9 @@
 #include <bitset>
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/modules/v8/IDBObserverCallback.h"
 #include "bindings/modules/v8/ToV8ForModules.h"
 #include "bindings/modules/v8/V8BindingForModules.h"
+#include "bindings/modules/v8/idb_observer_callback.h"
 #include "core/dom/ExceptionCode.h"
 #include "modules/IndexedDBNames.h"
 #include "modules/indexeddb/IDBDatabase.h"
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp b/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp
index 52bc0d94..c62678a 100644
--- a/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp
+++ b/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp
@@ -82,8 +82,8 @@
   if (frame_rate == 0) {
     draw_listener_ = OnRequestCanvasDrawListener::Create(std::move(handler));
   } else {
-    draw_listener_ =
-        TimedCanvasDrawListener::Create(std::move(handler), frame_rate);
+    draw_listener_ = TimedCanvasDrawListener::Create(
+        std::move(handler), frame_rate, element->GetExecutionContext());
   }
   canvas_element_->AddListener(draw_listener_.Get());
 }
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.cpp b/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.cpp
index 0ba9da0..e9ffa5e 100644
--- a/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.cpp
+++ b/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.cpp
@@ -22,13 +22,15 @@
 namespace blink {
 
 MediaStream* HTMLCanvasElementCapture::captureStream(
+    ScriptState* script_state,
     HTMLCanvasElement& element,
     ExceptionState& exception_state) {
-  return HTMLCanvasElementCapture::captureStream(element, false, 0,
-                                                 exception_state);
+  return HTMLCanvasElementCapture::captureStream(script_state, element, false,
+                                                 0, exception_state);
 }
 
 MediaStream* HTMLCanvasElementCapture::captureStream(
+    ScriptState* script_state,
     HTMLCanvasElement& element,
     double frame_rate,
     ExceptionState& exception_state) {
@@ -38,11 +40,12 @@
     return nullptr;
   }
 
-  return HTMLCanvasElementCapture::captureStream(element, true, frame_rate,
-                                                 exception_state);
+  return HTMLCanvasElementCapture::captureStream(script_state, element, true,
+                                                 frame_rate, exception_state);
 }
 
 MediaStream* HTMLCanvasElementCapture::captureStream(
+    ScriptState* script_state,
     HTMLCanvasElement& element,
     bool given_frame_rate,
     double frame_rate,
@@ -81,7 +84,7 @@
 
   MediaStreamTrackVector tracks;
   tracks.push_back(canvas_track);
-  return MediaStream::Create(element.GetExecutionContext(), tracks);
+  return MediaStream::Create(ExecutionContext::From(script_state), tracks);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.h b/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.h
index 06d3187..533191fc 100644
--- a/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.h
+++ b/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.h
@@ -18,13 +18,17 @@
   STATIC_ONLY(HTMLCanvasElementCapture);
 
  public:
-  static MediaStream* captureStream(HTMLCanvasElement&, ExceptionState&);
-  static MediaStream* captureStream(HTMLCanvasElement&,
+  static MediaStream* captureStream(ScriptState*,
+                                    HTMLCanvasElement&,
+                                    ExceptionState&);
+  static MediaStream* captureStream(ScriptState*,
+                                    HTMLCanvasElement&,
                                     double frame_rate,
                                     ExceptionState&);
 
  private:
-  static MediaStream* captureStream(HTMLCanvasElement&,
+  static MediaStream* captureStream(ScriptState*,
+                                    HTMLCanvasElement&,
                                     bool given_frame_rate,
                                     double frame_rate,
                                     ExceptionState&);
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.idl b/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.idl
index 5c1acf6..1ad04fbf 100644
--- a/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.idl
+++ b/third_party/WebKit/Source/modules/mediacapturefromelement/HTMLCanvasElementCapture.idl
@@ -6,5 +6,5 @@
 [
     RuntimeEnabled=MediaCaptureFromCanvas
 ] partial interface HTMLCanvasElement {
-    [RaisesException] MediaStream captureStream (optional double frameRate);
+    [RaisesException, CallWith=ScriptState] MediaStream captureStream (optional double frameRate);
 };
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp b/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp
index 8e4b8958..3cd8bc0 100644
--- a/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp
+++ b/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp
@@ -4,27 +4,32 @@
 
 #include "modules/mediacapturefromelement/TimedCanvasDrawListener.h"
 
-#include "third_party/skia/include/core/SkImage.h"
 #include <memory>
+#include "core/dom/TaskRunnerHelper.h"
+#include "third_party/skia/include/core/SkImage.h"
 
 namespace blink {
 
 TimedCanvasDrawListener::TimedCanvasDrawListener(
     std::unique_ptr<WebCanvasCaptureHandler> handler,
-    double frame_rate)
+    double frame_rate,
+    ExecutionContext* context)
     : CanvasDrawListener(std::move(handler)),
       frame_interval_(1 / frame_rate),
-      request_frame_timer_(this,
-                           &TimedCanvasDrawListener::RequestFrameTimerFired) {}
+      request_frame_timer_(
+          TaskRunnerHelper::Get(TaskType::kUnthrottled, context),
+          this,
+          &TimedCanvasDrawListener::RequestFrameTimerFired) {}
 
 TimedCanvasDrawListener::~TimedCanvasDrawListener() {}
 
 // static
 TimedCanvasDrawListener* TimedCanvasDrawListener::Create(
     std::unique_ptr<WebCanvasCaptureHandler> handler,
-    double frame_rate) {
+    double frame_rate,
+    ExecutionContext* context) {
   TimedCanvasDrawListener* listener =
-      new TimedCanvasDrawListener(std::move(handler), frame_rate);
+      new TimedCanvasDrawListener(std::move(handler), frame_rate, context);
   listener->request_frame_timer_.StartRepeating(listener->frame_interval_,
                                                 BLINK_FROM_HERE);
   return listener;
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.h b/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.h
index 1d1e867..5e5418b 100644
--- a/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.h
+++ b/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.h
@@ -13,6 +13,7 @@
 #include <memory>
 
 namespace blink {
+class ExecutionContext;
 
 class TimedCanvasDrawListener final
     : public GarbageCollectedFinalized<TimedCanvasDrawListener>,
@@ -23,19 +24,21 @@
   ~TimedCanvasDrawListener();
   static TimedCanvasDrawListener* Create(
       std::unique_ptr<WebCanvasCaptureHandler>,
-      double frame_rate);
+      double frame_rate,
+      ExecutionContext*);
   void SendNewFrame(sk_sp<SkImage>) override;
 
   DEFINE_INLINE_TRACE() {}
 
  private:
   TimedCanvasDrawListener(std::unique_ptr<WebCanvasCaptureHandler>,
-                          double frame_rate);
+                          double frame_rate,
+                          ExecutionContext*);
   // Implementation of TimerFiredFunction.
   void RequestFrameTimerFired(TimerBase*);
 
   double frame_interval_;
-  UnthrottledThreadTimer<TimedCanvasDrawListener> request_frame_timer_;
+  TaskRunnerTimer<TimedCanvasDrawListener> request_frame_timer_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediarecorder/OWNERS b/third_party/WebKit/Source/modules/mediarecorder/OWNERS
index cd2027e..c824512 100644
--- a/third_party/WebKit/Source/modules/mediarecorder/OWNERS
+++ b/third_party/WebKit/Source/modules/mediarecorder/OWNERS
@@ -2,3 +2,4 @@
 peter@chromium.org
 
 # COMPONENT: Blink>MediaRecording
+# TEAM: media-dev@chromium.org
diff --git a/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp b/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp
index 3bb1f9f..0acaa52 100644
--- a/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp
+++ b/third_party/WebKit/Source/modules/mediasession/MediaSession.cpp
@@ -5,7 +5,7 @@
 #include "modules/mediasession/MediaSession.h"
 
 #include <memory>
-#include "bindings/modules/v8/MediaSessionActionHandler.h"
+#include "bindings/modules/v8/media_session_action_handler.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/UserGestureIndicator.h"
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index f87fd07c..26272f9 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -544,7 +544,7 @@
                     "speech/SpeechRecognitionEventInit.idl",
                     "storage/StorageEventInit.idl",
                     "vr/VRDisplayEventInit.idl",
-                    "vr/VRLayer.idl",
+                    "vr/VRLayerInit.idl",
                     "webaudio/AnalyserOptions.idl",
                     "webaudio/AudioBufferOptions.idl",
                     "webaudio/AudioBufferSourceOptions.idl",
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.h b/third_party/WebKit/Source/modules/nfc/NFC.h
index b20f62e2..9ece8e4 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.h
+++ b/third_party/WebKit/Source/modules/nfc/NFC.h
@@ -6,7 +6,7 @@
 #define NFC_h
 
 #include "bindings/core/v8/ScriptPromise.h"
-#include "bindings/modules/v8/StringOrArrayBufferOrNFCMessage.h"
+#include "bindings/modules/v8/string_or_array_buffer_or_nfc_message.h"
 #include "core/dom/ContextLifecycleObserver.h"
 #include "core/page/PageVisibilityObserver.h"
 #include "modules/nfc/MessageCallback.h"
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index 4a4d44b5..bf2c9b2 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -4,7 +4,7 @@
 
 #include "modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h"
 
-#include "bindings/modules/v8/OffscreenRenderingContext.h"
+#include "bindings/modules/v8/offscreen_rendering_context.h"
 #include "core/css/OffscreenFontSelector.h"
 #include "core/css/parser/CSSParser.h"
 #include "core/css/resolver/FontStyleResolver.h"
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index 7c3066d..dcf9597 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -1021,7 +1021,7 @@
       options_(options),
       client_binding_(this),
       complete_timer_(
-          TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, GetFrame()),
+          TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, execution_context),
           this,
           &PaymentRequest::OnCompleteTimeout) {
   if (!GetExecutionContext()->IsSecureContext()) {
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCDataChannelTest.cpp b/third_party/WebKit/Source/modules/peerconnection/RTCDataChannelTest.cpp
index 314641a..a7752ed 100644
--- a/third_party/WebKit/Source/modules/peerconnection/RTCDataChannelTest.cpp
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCDataChannelTest.cpp
@@ -8,6 +8,7 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/events/Event.h"
+#include "core/testing/NullExecutionContext.h"
 #include "core/typed_arrays/DOMArrayBuffer.h"
 #include "platform/heap/Heap.h"
 #include "platform/wtf/PtrUtil.h"
@@ -76,7 +77,8 @@
 
 TEST(RTCDataChannelTest, BufferedAmount) {
   MockHandler* handler = new MockHandler();
-  RTCDataChannel* channel = RTCDataChannel::Create(0, WTF::WrapUnique(handler));
+  RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
+                                                   WTF::WrapUnique(handler));
 
   handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
   String message(std::string(100, 'A').c_str());
@@ -86,7 +88,8 @@
 
 TEST(RTCDataChannelTest, BufferedAmountLow) {
   MockHandler* handler = new MockHandler();
-  RTCDataChannel* channel = RTCDataChannel::Create(0, WTF::WrapUnique(handler));
+  RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
+                                                   WTF::WrapUnique(handler));
 
   // Add and drain 100 bytes
   handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
@@ -149,7 +152,8 @@
 
 TEST(RTCDataChannelTest, SendAfterContextDestroyed) {
   MockHandler* handler = new MockHandler();
-  RTCDataChannel* channel = RTCDataChannel::Create(0, WTF::WrapUnique(handler));
+  RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
+                                                   WTF::WrapUnique(handler));
   handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
   channel->ContextDestroyed(nullptr);
 
@@ -162,7 +166,8 @@
 
 TEST(RTCDataChannelTest, CloseAfterContextDestroyed) {
   MockHandler* handler = new MockHandler();
-  RTCDataChannel* channel = RTCDataChannel::Create(0, WTF::WrapUnique(handler));
+  RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext,
+                                                   WTF::WrapUnique(handler));
   handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen);
   channel->ContextDestroyed(nullptr);
   channel->close();
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
index 756bd06..6ab5ec0 100644
--- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
+++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
@@ -40,9 +40,9 @@
 #include "bindings/core/v8/Nullable.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "bindings/core/v8/ScriptValue.h"
-#include "bindings/modules/v8/RTCIceCandidateInitOrRTCIceCandidate.h"
 #include "bindings/modules/v8/V8MediaStreamTrack.h"
 #include "bindings/modules/v8/V8RTCCertificate.h"
+#include "bindings/modules/v8/rtc_ice_candidate_init_or_rtc_ice_candidate.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/DOMTimeStamp.h"
 #include "core/dom/Document.h"
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushMessageData.cpp b/third_party/WebKit/Source/modules/push_messaging/PushMessageData.cpp
index c826520..265f92f 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushMessageData.cpp
+++ b/third_party/WebKit/Source/modules/push_messaging/PushMessageData.cpp
@@ -8,7 +8,7 @@
 
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/V8BindingForCore.h"
-#include "bindings/modules/v8/ArrayBufferOrArrayBufferViewOrUSVString.h"
+#include "bindings/modules/v8/array_buffer_or_array_buffer_view_or_usv_string.h"
 #include "core/fileapi/Blob.h"
 #include "core/typed_arrays/DOMArrayBuffer.h"
 #include "platform/bindings/ScriptState.h"
diff --git a/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
index b2a2bf4..d798f70b 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
@@ -4,7 +4,7 @@
 
 #include "modules/remoteplayback/AvailabilityCallbackWrapper.h"
 
-#include "bindings/modules/v8/RemotePlaybackAvailabilityCallback.h"
+#include "bindings/modules/v8/remote_playback_availability_callback.h"
 #include "modules/remoteplayback/RemotePlayback.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
index 2aa7e6e..7d6eb0a 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
@@ -5,7 +5,7 @@
 #include "modules/remoteplayback/RemotePlayback.h"
 
 #include "bindings/core/v8/ScriptPromiseResolver.h"
-#include "bindings/modules/v8/RemotePlaybackAvailabilityCallback.h"
+#include "bindings/modules/v8/remote_playback_availability_callback.h"
 #include "core/HTMLNames.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
index 51c23328..86d964ac 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
@@ -6,7 +6,7 @@
 
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
-#include "bindings/modules/v8/RemotePlaybackAvailabilityCallback.h"
+#include "bindings/modules/v8/remote_playback_availability_callback.h"
 #include "core/dom/UserGestureIndicator.h"
 #include "core/frame/LocalFrame.h"
 #include "core/html/HTMLMediaElement.h"
diff --git a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp
index 197eb3e..2de2253 100644
--- a/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp
+++ b/third_party/WebKit/Source/modules/screen_orientation/ScreenOrientationControllerImpl.cpp
@@ -42,7 +42,7 @@
     WebScreenOrientationClient* client)
     : ScreenOrientationController(frame),
       ContextLifecycleObserver(frame.GetDocument()),
-      PlatformEventController(&frame),
+      PlatformEventController(frame.GetDocument()),
       client_(client),
       dispatch_event_timer_(
           TaskRunnerHelper::Get(TaskType::kMiscPlatformAPI, &frame),
diff --git a/third_party/WebKit/Source/modules/sensor/OrientationSensor.h b/third_party/WebKit/Source/modules/sensor/OrientationSensor.h
index d903ba42..15fb020 100644
--- a/third_party/WebKit/Source/modules/sensor/OrientationSensor.h
+++ b/third_party/WebKit/Source/modules/sensor/OrientationSensor.h
@@ -5,7 +5,7 @@
 #ifndef OrientationSensor_h
 #define OrientationSensor_h
 
-#include "bindings/modules/v8/Float32ArrayOrFloat64ArrayOrDOMMatrix.h"
+#include "bindings/modules/v8/float32_array_or_float64_array_or_dom_matrix.h"
 #include "core/typed_arrays/DOMTypedArray.h"
 #include "modules/sensor/Sensor.h"
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.h
index 3fb1cd8..d2bc3bf 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.h
@@ -31,7 +31,7 @@
 #define ServiceWorkerGlobalScope_h
 
 #include <memory>
-#include "bindings/modules/v8/RequestOrUSVString.h"
+#include "bindings/modules/v8/request_or_usv_string.h"
 #include "core/workers/WorkerGlobalScope.h"
 #include "modules/ModulesExport.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/modules/shapedetection/OWNERS b/third_party/WebKit/Source/modules/shapedetection/OWNERS
index 26e1bed..57aa41f 100644
--- a/third_party/WebKit/Source/modules/shapedetection/OWNERS
+++ b/third_party/WebKit/Source/modules/shapedetection/OWNERS
@@ -2,4 +2,4 @@
 reillyg@chromium.org
 
 # COMPONENT: Blink>ImageCapture
-# TEAM: device-dev@chromium.org
+# TEAM: media-dev@chromium.org
diff --git a/third_party/WebKit/Source/modules/vibration/VibrationController.cpp b/third_party/WebKit/Source/modules/vibration/VibrationController.cpp
index 577ac82a..8a9f907 100644
--- a/third_party/WebKit/Source/modules/vibration/VibrationController.cpp
+++ b/third_party/WebKit/Source/modules/vibration/VibrationController.cpp
@@ -19,7 +19,7 @@
 
 #include "modules/vibration/VibrationController.h"
 
-#include "bindings/modules/v8/UnsignedLongOrUnsignedLongSequence.h"
+#include "bindings/modules/v8/unsigned_long_or_unsigned_long_sequence.h"
 #include "core/dom/Document.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/frame/LocalFrame.h"
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
index 352844f..d86ca3c 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -26,7 +26,7 @@
 #include "modules/vr/VRDisplayCapabilities.h"
 #include "modules/vr/VREyeParameters.h"
 #include "modules/vr/VRFrameData.h"
-#include "modules/vr/VRLayer.h"
+#include "modules/vr/VRLayerInit.h"
 #include "modules/vr/VRPose.h"
 #include "modules/vr/VRStageParameters.h"
 #include "modules/webgl/WebGLRenderingContextBase.h"
@@ -289,7 +289,7 @@
 }
 
 ScriptPromise VRDisplay::requestPresent(ScriptState* script_state,
-                                        const HeapVector<VRLayer>& layers) {
+                                        const HeapVector<VRLayerInit>& layers) {
   DVLOG(1) << __FUNCTION__;
   ExecutionContext* execution_context = ExecutionContext::From(script_state);
   UseCounter::Count(execution_context, WebFeature::kVRRequestPresent);
@@ -601,8 +601,8 @@
       WebSize(source_width_, source_height_));
 }
 
-HeapVector<VRLayer> VRDisplay::getLayers() {
-  HeapVector<VRLayer> layers;
+HeapVector<VRLayerInit> VRDisplay::getLayers() {
+  HeapVector<VRLayerInit> layers;
 
   if (is_presenting_) {
     layers.push_back(layer_);
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.h b/third_party/WebKit/Source/modules/vr/VRDisplay.h
index 7de006f..c7eff605 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.h
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.h
@@ -11,7 +11,7 @@
 #include "core/dom/events/EventTarget.h"
 #include "device/vr/vr_service.mojom-blink.h"
 #include "modules/vr/VRDisplayCapabilities.h"
-#include "modules/vr/VRLayer.h"
+#include "modules/vr/VRLayerInit.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "platform/Timer.h"
 #include "platform/heap/Handle.h"
@@ -71,10 +71,11 @@
   int requestAnimationFrame(FrameRequestCallback*);
   void cancelAnimationFrame(int id);
 
-  ScriptPromise requestPresent(ScriptState*, const HeapVector<VRLayer>& layers);
+  ScriptPromise requestPresent(ScriptState*,
+                               const HeapVector<VRLayerInit>& layers);
   ScriptPromise exitPresent(ScriptState*);
 
-  HeapVector<VRLayer> getLayers();
+  HeapVector<VRLayerInit> getLayers();
 
   void submitFrame();
 
@@ -180,7 +181,7 @@
   // VR compositor so that it knows which poses to use, when to apply bounds
   // updates, etc.
   int16_t vr_frame_id_ = -1;
-  VRLayer layer_;
+  VRLayerInit layer_;
   double depth_near_ = 0.01;
   double depth_far_ = 10000.0;
 
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.idl b/third_party/WebKit/Source/modules/vr/VRDisplay.idl
index 4add31b..121ac6f 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.idl
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.idl
@@ -36,17 +36,18 @@
     long requestAnimationFrame(FrameRequestCallback callback);
     void cancelAnimationFrame(long handle);
 
-    // Begin presenting to the VRDisplay. Must be called in response to a user gesture.
-    // Repeat calls while already presenting will update the VRLayer being displayed.
-    [CallWith=ScriptState] Promise requestPresent(sequence<VRLayer> layers);
+    // Begin presenting to the VRDisplay. Must be called in response to a user
+    // gesture. Repeat calls while already presenting will update the layer
+    // being displayed.
+    [CallWith=ScriptState] Promise requestPresent(sequence<VRLayerInit> layers);
 
     // Stops presenting to the VRDisplay.
     [CallWith=ScriptState] Promise exitPresent();
 
     // Get the sources currently being presented.
-    sequence<VRLayer> getLayers();
+    sequence<VRLayerInit> getLayers();
 
-    // The VRLayer provided to the `VRDisplay` will be captured and presented
+    // The layer provided to the `VRDisplay` will be captured and presented
     // in the HMD. Calling this function has the same effect on the source
     // canvas as any other operation that uses its source image, and canvases
     // created without preserveDrawingBuffer set to true will be cleared.
diff --git a/third_party/WebKit/Source/modules/vr/VRLayer.idl b/third_party/WebKit/Source/modules/vr/VRLayer.idl
deleted file mode 100644
index 3fab721..0000000
--- a/third_party/WebKit/Source/modules/vr/VRLayer.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-typedef (HTMLCanvasElement or OffscreenCanvas) VRSource;
-
-// https://w3c.github.io/webvr/#interface-vrlayer
-
-dictionary VRLayer {
-  // The canvas to be presented to the VRDisplay
-  VRSource? source = null;
-
-  // The left and right bounds contain 4 git statvalues defining the texture bounds
-  // within the canvas to present to the eye in UV space.
-  // [0] left offset of the bounds (0.0 - 1.0)
-  // [1] top offset of the bounds (0.0 - 1.0)
-  // [2] width of the bounds (0.0 - 1.0)
-  // [3] height of the bounds (0.0 - 1.0)
-  sequence<float> leftBounds = []; //= [0.0, 0.0, 0.5, 1.0];
-  sequence<float> rightBounds = []; //= [0.5, 0.0, 0.5, 1.0];
-};
diff --git a/third_party/WebKit/Source/modules/vr/VRLayerInit.idl b/third_party/WebKit/Source/modules/vr/VRLayerInit.idl
new file mode 100644
index 0000000..114de359
--- /dev/null
+++ b/third_party/WebKit/Source/modules/vr/VRLayerInit.idl
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+typedef (HTMLCanvasElement or OffscreenCanvas) VRSource;
+
+// https://w3c.github.io/webvr/#interface-vrlayerinit
+
+dictionary VRLayerInit {
+  // The canvas to be presented to the VRDisplay
+  VRSource? source = null;
+
+  // The left and right bounds contain 4 git statvalues defining the texture bounds
+  // within the canvas to present to the eye in UV space.
+  // [0] left offset of the bounds (0.0 - 1.0)
+  // [1] top offset of the bounds (0.0 - 1.0)
+  // [2] width of the bounds (0.0 - 1.0)
+  // [3] height of the bounds (0.0 - 1.0)
+  sequence<float> leftBounds = []; //= [0.0, 0.0, 0.5, 1.0];
+  sequence<float> rightBounds = []; //= [0.5, 0.0, 0.5, 1.0];
+};
diff --git a/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp b/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp
index ba9f1661..53486ef 100644
--- a/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp
@@ -25,8 +25,8 @@
 
 #include "modules/webaudio/AsyncAudioDecoder.h"
 
-#include "bindings/modules/v8/DecodeErrorCallback.h"
-#include "bindings/modules/v8/DecodeSuccessCallback.h"
+#include "bindings/modules/v8/decode_error_callback.h"
+#include "bindings/modules/v8/decode_success_callback.h"
 #include "core/typed_arrays/DOMArrayBuffer.h"
 #include "modules/webaudio/AudioBuffer.h"
 #include "modules/webaudio/BaseAudioContext.h"
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
index ff69727..10cbba7 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
@@ -29,8 +29,8 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
-#include "bindings/modules/v8/DecodeErrorCallback.h"
-#include "bindings/modules/v8/DecodeSuccessCallback.h"
+#include "bindings/modules/v8/decode_error_callback.h"
+#include "bindings/modules/v8/decode_success_callback.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
diff --git a/third_party/WebKit/Source/modules/webdatabase/DOMWindowWebDatabase.cpp b/third_party/WebKit/Source/modules/webdatabase/DOMWindowWebDatabase.cpp
index 345e5f9..92a34d8 100644
--- a/third_party/WebKit/Source/modules/webdatabase/DOMWindowWebDatabase.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/DOMWindowWebDatabase.cpp
@@ -27,7 +27,7 @@
 #include "modules/webdatabase/DOMWindowWebDatabase.h"
 
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/modules/v8/DatabaseCallback.h"
+#include "bindings/modules/v8/database_callback.h"
 #include "core/dom/Document.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "modules/webdatabase/Database.h"
diff --git a/third_party/WebKit/Source/modules/webdatabase/Database.cpp b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
index b50f332..327c77d 100644
--- a/third_party/WebKit/Source/modules/webdatabase/Database.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
@@ -26,7 +26,7 @@
 #include "modules/webdatabase/Database.h"
 
 #include <memory>
-#include "bindings/modules/v8/DatabaseCallback.h"
+#include "bindings/modules/v8/database_callback.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/TaskRunnerHelper.h"
diff --git a/third_party/WebKit/Source/modules/webdatabase/DatabaseTracker.cpp b/third_party/WebKit/Source/modules/webdatabase/DatabaseTracker.cpp
index 3c8f74b8..0b2bcae 100644
--- a/third_party/WebKit/Source/modules/webdatabase/DatabaseTracker.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/DatabaseTracker.cpp
@@ -148,10 +148,21 @@
   DCHECK(
       database->GetDatabaseContext()->GetExecutionContext()->IsContextThread());
   if (Platform::Current()->DatabaseObserver()) {
+    // This is an asynchronous call to the browser to open the database,
+    // however we can't actually use the database until we revieve an RPC back
+    // that advises is of the actual size of the database, so there is a race
+    // condition where the database is in an unusable state. To assist, we
+    // will record the size of the database straight away so we can use it
+    // immediately, and the real size will eventually be updated by the RPC from
+    // the browser.
     Platform::Current()->DatabaseObserver()->DatabaseOpened(
         WebSecurityOrigin(database->GetSecurityOrigin()),
         database->StringIdentifier(), database->DisplayName(),
         database->EstimatedSize());
+    // We write a temporary size of 0 to the QuotaTracker - we will be updated
+    // with the correct size via RPC asynchronously.
+    QuotaTracker::Instance().UpdateDatabaseSize(
+        database->GetSecurityOrigin(), database->StringIdentifier(), 0);
   }
 }
 
diff --git a/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp b/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp
index 00ee3e08..f3722d5 100644
--- a/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/SQLTransactionClient.cpp
@@ -45,34 +45,11 @@
 
 namespace blink {
 
-namespace {
-
-void DatabaseModified(const WebSecurityOrigin& origin,
-                      const String& database_name) {
-  if (Platform::Current()->DatabaseObserver())
-    Platform::Current()->DatabaseObserver()->DatabaseModified(origin,
-                                                              database_name);
-}
-
-void DatabaseModifiedCrossThread(const String& origin_string,
-                                 const String& database_name) {
-  DatabaseModified(WebSecurityOrigin::CreateFromString(origin_string),
-                   database_name);
-}
-
-}  // namespace
-
 void SQLTransactionClient::DidCommitWriteTransaction(Database* database) {
-  String database_name = database->StringIdentifier();
-  ExecutionContext* execution_context =
-      database->GetDatabaseContext()->GetExecutionContext();
-  SecurityOrigin* origin = database->GetSecurityOrigin();
-  if (!execution_context->IsContextThread()) {
-    database->GetDatabaseTaskRunner()->PostTask(
-        BLINK_FROM_HERE, CrossThreadBind(&DatabaseModifiedCrossThread,
-                                         origin->ToRawString(), database_name));
-  } else {
-    DatabaseModified(WebSecurityOrigin(origin), database_name);
+  if (Platform::Current()->DatabaseObserver()) {
+    Platform::Current()->DatabaseObserver()->DatabaseModified(
+        WebSecurityOrigin(database->GetSecurityOrigin()),
+        database->StringIdentifier());
   }
 }
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp
index a4cd61a..33d37b9 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.cpp
@@ -5,8 +5,8 @@
 #include "modules/webgl/WebGL2RenderingContext.h"
 
 #include <memory>
-#include "bindings/modules/v8/OffscreenRenderingContext.h"
-#include "bindings/modules/v8/RenderingContext.h"
+#include "bindings/modules/v8/offscreen_rendering_context.h"
+#include "bindings/modules/v8/rendering_context.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameClient.h"
 #include "core/frame/Settings.h"
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
index 9416c51..bf57f50 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
@@ -26,8 +26,8 @@
 #include "modules/webgl/WebGLRenderingContext.h"
 
 #include <memory>
-#include "bindings/modules/v8/OffscreenRenderingContext.h"
-#include "bindings/modules/v8/RenderingContext.h"
+#include "bindings/modules/v8/offscreen_rendering_context.h"
+#include "bindings/modules/v8/rendering_context.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameClient.h"
 #include "core/frame/Settings.h"
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 10dec89..ac129037 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -29,8 +29,8 @@
 
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
-#include "bindings/modules/v8/HTMLCanvasElementOrOffscreenCanvas.h"
 #include "bindings/modules/v8/WebGLAny.h"
+#include "bindings/modules/v8/html_canvas_element_or_offscreen_canvas.h"
 #include "build/build_config.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/TaskRunnerHelper.h"
diff --git a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
index 5db17a3..0e74e15 100644
--- a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
+++ b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
@@ -33,7 +33,7 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptController.h"
 #include "bindings/core/v8/SourceLocation.h"
-#include "bindings/modules/v8/StringOrStringSequence.h"
+#include "bindings/modules/v8/string_or_string_sequence.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
diff --git a/third_party/WebKit/Source/modules/webusb/USBDevice.h b/third_party/WebKit/Source/modules/webusb/USBDevice.h
index c1b7862b..79229b1e 100644
--- a/third_party/WebKit/Source/modules/webusb/USBDevice.h
+++ b/third_party/WebKit/Source/modules/webusb/USBDevice.h
@@ -5,8 +5,8 @@
 #ifndef USBDevice_h
 #define USBDevice_h
 
-#include "bindings/core/v8/ArrayBufferOrArrayBufferView.h"
 #include "bindings/core/v8/ScriptPromise.h"
+#include "bindings/core/v8/array_buffer_or_array_buffer_view.h"
 #include "core/dom/ContextLifecycleObserver.h"
 #include "device/usb/public/interfaces/device.mojom-blink.h"
 #include "platform/bindings/ScriptWrappable.h"
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 0f55f19..a7dc70c9 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -727,6 +727,7 @@
     "fonts/FontSelector.h",
     "fonts/FontSelectorClient.h",
     "fonts/FontSmoothingMode.h",
+    "fonts/FontVariantEastAsian.h",
     "fonts/FontVariantNumeric.h",
     "fonts/FontWidthVariant.h",
     "fonts/GenericFontFamilySettings.cpp",
@@ -1875,6 +1876,7 @@
     "text/SuffixTreeTest.cpp",
     "text/TextBreakIteratorTest.cpp",
     "text/TextEncodingDetectorTest.cpp",
+    "text/TextRunTest.cpp",
     "text/UnicodeUtilitiesTest.cpp",
     "text/WritingModeUtilsTest.cpp",
     "threading/BackgroundTaskRunnerTest.cpp",
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index b23de52..494131d 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -498,11 +498,6 @@
     },
     {
       name: "IdleTimeColdModeSpellChecking",
-      depends_on: ["IdleTimeSpellChecking"],
-      status: "test",
-    },
-    {
-      name: "IdleTimeSpellChecking",
       status: "test",
     },
     {
diff --git a/third_party/WebKit/Source/platform/Timer.cpp b/third_party/WebKit/Source/platform/Timer.cpp
index 781095c4..c2d89a3 100644
--- a/third_party/WebKit/Source/platform/Timer.cpp
+++ b/third_party/WebKit/Source/platform/Timer.cpp
@@ -115,11 +115,6 @@
   return Platform::Current()->CurrentThread()->Scheduler()->TimerTaskRunner();
 }
 
-// static
-RefPtr<WebTaskRunner> TimerBase::GetUnthrottledTaskRunner() {
-  return Platform::Current()->CurrentThread()->GetWebTaskRunner();
-}
-
 RefPtr<WebTaskRunner> TimerBase::TimerTaskRunner() const {
   return web_task_runner_;
 }
diff --git a/third_party/WebKit/Source/platform/Timer.h b/third_party/WebKit/Source/platform/Timer.h
index b556e62..c246af7 100644
--- a/third_party/WebKit/Source/platform/Timer.h
+++ b/third_party/WebKit/Source/platform/Timer.h
@@ -91,7 +91,6 @@
 
  protected:
   static RefPtr<WebTaskRunner> GetTimerTaskRunner();
-  static RefPtr<WebTaskRunner> GetUnthrottledTaskRunner();
 
  private:
   virtual void Fired() = 0;
@@ -186,26 +185,6 @@
                                          timer_fired_function) {}
 };
 
-// This subclass of Timer posts its tasks on the current thread's default task
-// runner.  Tasks posted on there are not throttled when the tab is in the
-// background.
-//
-// DEPRECATED: Use TaskRunnerHelper::get with TaskType::Unthrottled.
-template <typename TimerFiredClass>
-class UnthrottledThreadTimer : public TaskRunnerTimer<TimerFiredClass> {
- public:
-  using TimerFiredFunction =
-      typename TaskRunnerTimer<TimerFiredClass>::TimerFiredFunction;
-
-  ~UnthrottledThreadTimer() override {}
-
-  UnthrottledThreadTimer(TimerFiredClass* timer_fired_class,
-                         TimerFiredFunction timer_fired_function)
-      : TaskRunnerTimer<TimerFiredClass>(TimerBase::GetUnthrottledTaskRunner(),
-                                         timer_fired_class,
-                                         timer_fired_function) {}
-};
-
 NO_SANITIZE_ADDRESS
 inline bool TimerBase::IsActive() const {
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.h b/third_party/WebKit/Source/platform/fonts/FontCache.h
index 6c98add..b822050 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.h
@@ -190,7 +190,7 @@
                                    int32_t font_height);
   static int32_t MenuFontHeight() { return menu_font_height_; }
   static const AtomicString& MenuFontFamily() {
-    return *small_caption_font_family_name_;
+    return *menu_font_family_name_;
   }
   static int32_t SmallCaptionFontHeight() { return small_caption_font_height_; }
   static const AtomicString& SmallCaptionFontFamily() {
diff --git a/third_party/WebKit/Source/platform/fonts/FontDescription.cpp b/third_party/WebKit/Source/platform/fonts/FontDescription.cpp
index 7bd46d8..a56a3b8 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDescription.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontDescription.cpp
@@ -164,6 +164,11 @@
   UpdateTypesettingFeatures();
 }
 
+void FontDescription::SetVariantEastAsian(
+    const FontVariantEastAsian variant_east_asian) {
+  fields_.variant_east_asian_ = variant_east_asian.fields_as_unsigned_;
+}
+
 void FontDescription::SetVariantLigatures(const VariantLigatures& ligatures) {
   fields_.common_ligatures_state_ = ligatures.common;
   fields_.discretionary_ligatures_state_ = ligatures.discretionary;
diff --git a/third_party/WebKit/Source/platform/fonts/FontDescription.h b/third_party/WebKit/Source/platform/fonts/FontDescription.h
index 82c9703..5e712a9 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDescription.h
+++ b/third_party/WebKit/Source/platform/fonts/FontDescription.h
@@ -34,6 +34,7 @@
 #include "platform/fonts/FontOrientation.h"
 #include "platform/fonts/FontSelectionTypes.h"
 #include "platform/fonts/FontSmoothingMode.h"
+#include "platform/fonts/FontVariantEastAsian.h"
 #include "platform/fonts/FontVariantNumeric.h"
 #include "platform/fonts/FontWidthVariant.h"
 #include "platform/fonts/TextRenderingMode.h"
@@ -164,6 +165,10 @@
            Family().Family() == FontFamilyNames::webkit_monospace;
   }
   Kerning GetKerning() const { return static_cast<Kerning>(fields_.kerning_); }
+  FontVariantEastAsian GetVariantEastAsian() const {
+    return FontVariantEastAsian::InitializeFromUnsigned(
+        fields_.variant_east_asian_);
+  }
   VariantLigatures GetVariantLigatures() const;
   FontVariantNumeric VariantNumeric() const {
     return FontVariantNumeric::InitializeFromUnsigned(fields_.variant_numeric_);
@@ -243,6 +248,7 @@
   void SetStretch(FontSelectionValue s) { font_selection_request_.width = s; }
 
   void SetVariantCaps(FontVariantCaps);
+  void SetVariantEastAsian(const FontVariantEastAsian);
   void SetVariantLigatures(const VariantLigatures&);
   void SetVariantNumeric(const FontVariantNumeric&);
   void SetIsAbsoluteSize(bool s) { fields_.is_absolute_size_ = s; }
@@ -380,6 +386,7 @@
     unsigned subpixel_text_position_ : 1;
     unsigned typesetting_features_ : 3;
     unsigned variant_numeric_ : 8;
+    unsigned variant_east_asian_ : 6;
     mutable unsigned subpixel_ascent_descent_ : 1;
   };
 
diff --git a/third_party/WebKit/Source/platform/fonts/FontVariantEastAsian.h b/third_party/WebKit/Source/platform/fonts/FontVariantEastAsian.h
new file mode 100644
index 0000000..0efae1d
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/FontVariantEastAsian.h
@@ -0,0 +1,80 @@
+// 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 FontVariantEastAsian_h
+#define FontVariantEastAsian_h
+
+#include "platform/wtf/Allocator.h"
+
+namespace blink {
+
+class FontVariantEastAsian {
+  STACK_ALLOCATED();
+
+ public:
+  enum EastAsianForm {
+    kNormalForm,
+    kJis78,
+    kJis83,
+    kJis90,
+    kJis04,
+    kSimplified,
+    kTraditional
+    // Ensure |BitFields| has enough bits when adding values.
+  };
+
+  enum EastAsianWidth {
+    kNormalWidth,
+    kFullWidth,
+    kProportionalWidth
+    // Ensure |BitFields| has enough bits when adding values.
+  };
+
+  FontVariantEastAsian() : fields_as_unsigned_(0) {}
+
+  static FontVariantEastAsian InitializeFromUnsigned(unsigned init_value) {
+    return FontVariantEastAsian(init_value);
+  }
+
+  EastAsianForm Form() const {
+    return static_cast<EastAsianForm>(fields_.form_);
+  }
+  EastAsianWidth Width() const {
+    return static_cast<EastAsianWidth>(fields_.width_);
+  }
+  bool Ruby() const { return fields_.ruby_; }
+
+  void SetForm(EastAsianForm form) { fields_.form_ = form; };
+  void SetWidth(EastAsianWidth width) { fields_.width_ = width; };
+  void SetRuby(bool ruby) { fields_.ruby_ = ruby; };
+
+  bool IsAllNormal() const { return !fields_as_unsigned_; }
+
+  bool operator==(const FontVariantEastAsian& other) const {
+    return fields_as_unsigned_ == other.fields_as_unsigned_;
+  }
+
+ private:
+  FontVariantEastAsian(unsigned init_value) : fields_as_unsigned_(init_value) {}
+
+  struct BitFields {
+    unsigned form_ : 3;
+    unsigned width_ : 2;
+    unsigned ruby_ : 1;
+    // Ensure |FontDescription| has enough bits when adding values.
+  };
+
+  union {
+    BitFields fields_;
+    unsigned fields_as_unsigned_;
+  };
+  static_assert(sizeof(BitFields) == sizeof(unsigned),
+                "Mapped union types must match in size.");
+
+  // Used in setVariant to store the value in m_fields.m_variantNumeric;
+  friend class FontDescription;
+};
+}  // namespace blink
+
+#endif  // FontVariantEastAsian_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
index 253ee4c4..2035f7d 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -411,6 +411,8 @@
   return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */};
 }
 
+// TODO(kojii): crbug.com/762493 This list is getting long enough to extract out
+// of HarfBuzzShaper.cpp.
 void SetFontFeatures(const Font* font, FeaturesVector* features) {
   const FontDescription& description = font->GetFontDescription();
 
@@ -492,6 +494,58 @@
       break;
   }
 
+  // font-variant-east-asian:
+  const FontVariantEastAsian east_asian = description.GetVariantEastAsian();
+  if (UNLIKELY(!east_asian.IsAllNormal())) {
+    static hb_feature_t jp78 = CreateFeature(HB_TAG('j', 'p', '7', '8'), 1);
+    static hb_feature_t jp83 = CreateFeature(HB_TAG('j', 'p', '8', '3'), 1);
+    static hb_feature_t jp90 = CreateFeature(HB_TAG('j', 'p', '9', '0'), 1);
+    static hb_feature_t jp04 = CreateFeature(HB_TAG('j', 'p', '0', '4'), 1);
+    static hb_feature_t smpl = CreateFeature(HB_TAG('s', 'm', 'p', 'l'), 1);
+    static hb_feature_t trad = CreateFeature(HB_TAG('t', 'r', 'a', 'd'), 1);
+    switch (east_asian.Form()) {
+      case FontVariantEastAsian::kNormalForm:
+        break;
+      case FontVariantEastAsian::kJis78:
+        features->push_back(jp78);
+        break;
+      case FontVariantEastAsian::kJis83:
+        features->push_back(jp83);
+        break;
+      case FontVariantEastAsian::kJis90:
+        features->push_back(jp90);
+        break;
+      case FontVariantEastAsian::kJis04:
+        features->push_back(jp04);
+        break;
+      case FontVariantEastAsian::kSimplified:
+        features->push_back(smpl);
+        break;
+      case FontVariantEastAsian::kTraditional:
+        features->push_back(trad);
+        break;
+      default:
+        NOTREACHED();
+    }
+    static hb_feature_t fwid = CreateFeature(HB_TAG('f', 'w', 'i', 'd'), 1);
+    static hb_feature_t pwid = CreateFeature(HB_TAG('p', 'w', 'i', 'd'), 1);
+    switch (east_asian.Width()) {
+      case FontVariantEastAsian::kNormalWidth:
+        break;
+      case FontVariantEastAsian::kFullWidth:
+        features->push_back(fwid);
+        break;
+      case FontVariantEastAsian::kProportionalWidth:
+        features->push_back(pwid);
+        break;
+      default:
+        NOTREACHED();
+    }
+    static hb_feature_t ruby = CreateFeature(HB_TAG('r', 'u', 'b', 'y'), 1);
+    if (east_asian.Ruby())
+      features->push_back(ruby);
+  }
+
   // font-variant-numeric:
   static hb_feature_t lnum = CreateFeature(HB_TAG('l', 'n', 'u', 'm'), 1);
   if (description.VariantNumeric().NumericFigureValue() ==
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
index b834fb3..c3169ad 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
@@ -42,6 +42,23 @@
   return static_cast<ShapeResultTestInfo*>(result.Get());
 }
 
+TEST_F(HarfBuzzShaperTest, MutableUnique) {
+  RefPtr<ShapeResult> result =
+      ShapeResult::Create(&font, 0, TextDirection::kLtr);
+  EXPECT_EQ(1, result->RefCount());
+
+  // At this point, |result| has only one ref count.
+  RefPtr<ShapeResult> result2 = result->MutableUnique();
+  EXPECT_EQ(result.Get(), result2.Get());
+  EXPECT_EQ(2, result2->RefCount());
+
+  // Since |result| has 2 ref counts, it should return a clone.
+  RefPtr<ShapeResult> result3 = result->MutableUnique();
+  EXPECT_NE(result.Get(), result3.Get());
+  EXPECT_EQ(1, result3->RefCount());
+  EXPECT_EQ(2, result->RefCount());
+}
+
 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLatin) {
   String latin_common = To16Bit("ABC DEF.", 8);
   HarfBuzzShaper shaper(latin_common.Characters16(), 8);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
index e270c98..3994c1b4 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -205,6 +205,12 @@
   return StartIndexForResult() + NumCharacters();
 }
 
+RefPtr<ShapeResult> ShapeResult::MutableUnique() const {
+  if (HasOneRef())
+    return const_cast<ShapeResult*>(this);
+  return ShapeResult::Create(*this);
+}
+
 // If the position is outside of the result, returns the start or the end offset
 // depends on the position.
 unsigned ShapeResult::OffsetForPosition(float target_x,
@@ -305,15 +311,19 @@
   }
 }
 
+// TODO(kojii): VC2015 fails to explicit instantiation of a member function.
+// Typed functions + this private function are to instantiate instances.
 template <typename TextContainerType>
-void ShapeResult::ApplySpacing(ShapeResultSpacing<TextContainerType>& spacing,
-                               const TextContainerType& text) {
+void ShapeResult::ApplySpacingImpl(
+    ShapeResultSpacing<TextContainerType>& spacing,
+    int text_start_offset) {
   float offset_x, offset_y;
   float& offset = spacing.IsVerticalOffset() ? offset_y : offset_x;
   float total_space = 0;
   for (auto& run : runs_) {
     if (!run)
       continue;
+    unsigned run_start_index = run->start_index_ + text_start_offset;
     float total_space_for_run = 0;
     for (size_t i = 0; i < run->glyph_data_.size(); i++) {
       HarfBuzzRunGlyphData& glyph_data = run->glyph_data_[i];
@@ -325,7 +335,7 @@
       } else {
         offset_x = offset_y = 0;
         float space = spacing.ComputeSpacing(
-            text, run->start_index_ + glyph_data.character_index, offset);
+            run_start_index + glyph_data.character_index, offset);
         glyph_data.advance += space;
         total_space_for_run += space;
         glyph_data.offset.Expand(offset_x, offset_y);
@@ -340,15 +350,19 @@
   glyph_bounding_box_.SetWidth(glyph_bounding_box_.Width() + total_space);
 }
 
-void ShapeResult::ApplySpacing(ShapeResultSpacing<String>& spacing) {
-  ApplySpacing(spacing, spacing.Text());
+void ShapeResult::ApplySpacing(ShapeResultSpacing<String>& spacing,
+                               int text_start_offset) {
+  ApplySpacingImpl(spacing, text_start_offset);
 }
 
 PassRefPtr<ShapeResult> ShapeResult::ApplySpacingToCopy(
     ShapeResultSpacing<TextRun>& spacing,
     const TextRun& run) const {
+  unsigned index_of_sub_run = spacing.Text().IndexOfSubRun(run);
+  DCHECK_NE(std::numeric_limits<unsigned>::max(), index_of_sub_run);
   RefPtr<ShapeResult> result = ShapeResult::Create(*this);
-  result->ApplySpacing(spacing, run);
+  if (index_of_sub_run != std::numeric_limits<unsigned>::max())
+    result->ApplySpacingImpl(spacing, index_of_sub_run);
   return result;
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
index ee3c50ec..dc3a25b6 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
@@ -65,6 +65,10 @@
       unsigned count);
   ~ShapeResult();
 
+  // Returns a mutalbe unique instance. If |this| has more than 1 ref count,
+  // a clone is created.
+  RefPtr<ShapeResult> MutableUnique() const;
+
   // The logical width of this result.
   float Width() const { return width_; }
   LayoutUnit SnappedWidth() const { return LayoutUnit::FromFloatCeil(width_); }
@@ -99,7 +103,12 @@
     return LayoutUnit::FromFloatCeil(PositionForOffset(offset));
   }
 
-  void ApplySpacing(ShapeResultSpacing<String>&);
+  // Apply spacings (letter-spacing, word-spacing, and justification) as
+  // configured to |ShapeResultSpacing|.
+  // |text_start_offset| adjusts the character index in the ShapeResult before
+  // giving it to |ShapeResultSpacing|. It can be negative if
+  // |StartIndexForResult()| is larger than the text in |ShapeResultSpacing|.
+  void ApplySpacing(ShapeResultSpacing<String>&, int text_start_offset = 0);
   PassRefPtr<ShapeResult> ApplySpacingToCopy(ShapeResultSpacing<TextRun>&,
                                              const TextRun&) const;
 
@@ -116,8 +125,8 @@
   }
 
   template <typename TextContainerType>
-  void ApplySpacing(ShapeResultSpacing<TextContainerType>&,
-                    const TextContainerType&);
+  void ApplySpacingImpl(ShapeResultSpacing<TextContainerType>&,
+                        int text_start_offset = 0);
   template <bool is_horizontal_run>
   void ComputeGlyphPositions(ShapeResult::RunInfo*,
                              unsigned start_glyph,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.cpp
index 3a95cb5..b9cca07 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.cpp
@@ -43,6 +43,20 @@
 }
 
 template <typename TextContainerType>
+void ShapeResultSpacing<TextContainerType>::SetExpansion(
+    float expansion,
+    TextDirection direction,
+    TextJustify text_justify,
+    bool allows_leading_expansion,
+    bool allows_trailing_expansion) {
+  DCHECK_GT(expansion, 0);
+  expansion_ = expansion;
+  ComputeExpansion(allows_leading_expansion, allows_trailing_expansion,
+                   direction, text_justify);
+  has_spacing_ |= HasExpansion();
+}
+
+template <typename TextContainerType>
 void ShapeResultSpacing<TextContainerType>::SetSpacingAndExpansion(
     const FontDescription& font_description) {
   // Available only for TextRun since it has expansion data.
@@ -79,8 +93,12 @@
   DCHECK_GT(expansion_, 0);
 
   text_justify_ = text_justify;
-  is_after_expansion_ = !allows_leading_expansion;
+  if (text_justify_ == TextJustify::kNone) {
+    expansion_opportunity_count_ = 0;
+    return;
+  }
 
+  is_after_expansion_ = !allows_leading_expansion;
   bool is_after_expansion = is_after_expansion_;
   if (text_.Is8Bit()) {
     expansion_opportunity_count_ = Character::ExpansionOpportunityCount(
@@ -119,27 +137,11 @@
   return expansion_per_opportunity_;
 }
 
-// Test if the |run| is the first sub-run of the original text container, for
-// containers that can create sub-runs such as TextRun or StringView.
 template <typename TextContainerType>
-inline bool ShapeResultSpacing<TextContainerType>::IsFirstRun(
-    const TextContainerType& run) const {
-  return &run == &text_ || run.Bytes() == text_.Bytes();
-}
-
-template <>
-inline bool ShapeResultSpacing<String>::IsFirstRun(const String& run) const {
-  // String::Substring() should not be used because it copies to a new buffer.
-  return &run == &text_ || run.Impl() == text_.Impl();
-}
-
-template <typename TextContainerType>
-float ShapeResultSpacing<TextContainerType>::ComputeSpacing(
-    const TextContainerType& run,
-    size_t index,
-    float& offset) {
+float ShapeResultSpacing<TextContainerType>::ComputeSpacing(unsigned index,
+                                                            float& offset) {
   DCHECK(has_spacing_);
-  UChar32 character = run[index];
+  UChar32 character = text_[index];
   bool treat_as_space =
       (Character::TreatAsSpace(character) ||
        (normalize_space_ &&
@@ -152,8 +154,7 @@
   if (letter_spacing_ && !Character::TreatAsZeroWidthSpace(character))
     spacing += letter_spacing_;
 
-  if (treat_as_space &&
-      (index || !IsFirstRun(run) || character == kNoBreakSpaceCharacter))
+  if (treat_as_space && (index || character == kNoBreakSpaceCharacter))
     spacing += word_spacing_;
 
   if (!HasExpansion())
@@ -162,15 +163,15 @@
   if (treat_as_space)
     return spacing + NextExpansion();
 
-  if (run.Is8Bit() || text_justify_ != TextJustify::kAuto)
+  if (text_.Is8Bit() || text_justify_ != TextJustify::kAuto)
     return spacing;
 
   // isCJKIdeographOrSymbol() has expansion opportunities both before and
   // after each character.
   // http://www.w3.org/TR/jlreq/#line_adjustment
-  if (U16_IS_LEAD(character) && index + 1 < run.length() &&
-      U16_IS_TRAIL(run[index + 1]))
-    character = U16_GET_SUPPLEMENTARY(character, run[index + 1]);
+  if (U16_IS_LEAD(character) && index + 1 < text_.length() &&
+      U16_IS_TRAIL(text_[index + 1]))
+    character = U16_GET_SUPPLEMENTARY(character, text_[index + 1]);
   if (!Character::IsCJKIdeographOrSymbol(character)) {
     is_after_expansion_ = false;
     return spacing;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h
index 4c30d2f..bd0cf74 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h
@@ -20,7 +20,7 @@
   STACK_ALLOCATED();
 
  public:
-  ShapeResultSpacing(const TextContainerType&);
+  explicit ShapeResultSpacing(const TextContainerType&);
 
   const TextContainerType& Text() const { return text_; }
   float LetterSpacing() const { return letter_spacing_; }
@@ -31,18 +31,25 @@
   // Set letter-spacing and word-spacing.
   bool SetSpacing(const FontDescription&);
 
+  // Set the expansion for the justification.
+  void SetExpansion(float expansion,
+                    TextDirection,
+                    TextJustify,
+                    bool allows_leading_expansion = false,
+                    bool allows_trailing_expansion = false);
+
   // Set letter-spacing, word-spacing, and justification.
   // Available only for TextRun.
   void SetSpacingAndExpansion(const FontDescription&);
 
-  // Compute the sum of all spacings for the specified index.
+  // Compute the sum of all spacings for the specified |index|.
+  // The |index| is for the |TextContainerType| given in the constructor.
   // For justification, this function must be called incrementally since it
   // keeps states and counts consumed justification opportunities.
-  float ComputeSpacing(const TextContainerType&, size_t, float& offset);
+  float ComputeSpacing(unsigned index, float& offset);
 
  private:
   bool IsAfterExpansion() const { return is_after_expansion_; }
-  bool IsFirstRun(const TextContainerType&) const;
 
   void ComputeExpansion(bool allows_leading_expansion,
                         bool allows_trailing_expansion,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
index e54714af..59247dc 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
@@ -80,6 +80,19 @@
                           : LayoutUnit::FromFloatFloor(value);
 }
 
+bool IsAllSpaces(const String& text, unsigned start, unsigned end) {
+  return StringView(text, start, end - start)
+      .IsAllSpecialCharacters<LazyLineBreakIterator::IsBreakableSpace>();
+}
+
+bool ShouldHyphenate(const String& text, unsigned start, unsigned end) {
+  // Do not hyphenate the last word in a paragraph, except when it's a single
+  // word paragraph.
+  if (IsAllSpaces(text, end, text.length()))
+    return IsAllSpaces(text, 0, start);
+  return true;
+}
+
 }  // namespace
 
 inline const String& ShapingLineBreaker::GetText() const {
@@ -98,15 +111,23 @@
   if (word_len <= Hyphenation::kMinimumSuffixLength)
     return 0;
 
-  // TODO(kojii): Check min-width?
-
   const String& text = GetText();
   if (backwards) {
-    return hyphenation_->LastHyphenLocation(
-        StringView(text, word_start, word_len), offset - word_start);
+    unsigned before_index = offset - word_start;
+    if (before_index <= Hyphenation::kMinimumPrefixLength)
+      return 0;
+    unsigned prefix_length = hyphenation_->LastHyphenLocation(
+        StringView(text, word_start, word_len), before_index);
+    DCHECK(!prefix_length || prefix_length < before_index);
+    return prefix_length;
   } else {
-    return hyphenation_->FirstHyphenLocation(
-        StringView(text, word_start, word_len), offset - word_start);
+    unsigned after_index = offset - word_start;
+    if (word_len <= after_index + Hyphenation::kMinimumSuffixLength)
+      return 0;
+    unsigned prefix_length = hyphenation_->FirstHyphenLocation(
+        StringView(text, word_start, word_len), after_index);
+    DCHECK(!prefix_length || prefix_length > after_index);
+    return prefix_length;
   }
 }
 
@@ -115,23 +136,30 @@
                                        bool backwards,
                                        bool* is_hyphenated) const {
   const String& text = GetText();
+  unsigned word_end = break_iterator_->NextBreakOpportunity(offset);
+  if (word_end == offset) {
+    DCHECK_EQ(offset, break_iterator_->PreviousBreakOpportunity(offset, start));
+    *is_hyphenated = false;
+    return word_end;
+  }
   unsigned previous_break_opportunity =
       break_iterator_->PreviousBreakOpportunity(offset, start);
   unsigned word_start = previous_break_opportunity;
   if (!break_iterator_->BreakAfterSpace()) {
-    while (word_start < text.length() && text[word_start] == kSpaceCharacter)
+    while (word_start < text.length() &&
+           LazyLineBreakIterator::IsBreakableSpace(text[word_start]))
       word_start++;
   }
-  unsigned word_end = break_iterator_->NextBreakOpportunity(offset + 1);
-
-  unsigned prefix_length = Hyphenate(offset, word_start, word_end, backwards);
-  if (!prefix_length) {
-    *is_hyphenated = false;
-    return backwards ? previous_break_opportunity : word_end;
+  if (offset >= word_start &&
+      ShouldHyphenate(text, previous_break_opportunity, word_end)) {
+    unsigned prefix_length = Hyphenate(offset, word_start, word_end, backwards);
+    if (prefix_length) {
+      *is_hyphenated = true;
+      return word_start + prefix_length;
+    }
   }
-
-  *is_hyphenated = true;
-  return word_start + prefix_length;
+  *is_hyphenated = false;
+  return backwards ? previous_break_opportunity : word_end;
 }
 
 unsigned ShapingLineBreaker::PreviousBreakOpportunity(
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
index 55e6d410..45ad8d1 100644
--- a/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
@@ -123,7 +123,8 @@
   PaintImageBuilder builder;
   InitPaintImageBuilder(builder);
   builder.set_paint_image_generator(std::move(generator))
-      .set_frame_index(index);
+      .set_frame_index(index)
+      .set_repetition_count(repetition_count_);
 
   // The caching of the decoded image data by the external users of this image
   // is keyed based on the uniqueID of the underlying SkImage for this
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 6ac87d184..0e6c1347 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -303,7 +303,7 @@
   return filter_quality_ == kNone_SkFilterQuality ? GL_NEAREST : GL_LINEAR;
 }
 
-bool Canvas2DLayerBridge::PrepareIOSurfaceMailboxFromImage(
+bool Canvas2DLayerBridge::PrepareGpuMemoryBufferMailboxFromImage(
     SkImage* image,
     MailboxInfo* info,
     viz::TextureMailbox* out_mailbox) {
@@ -313,7 +313,7 @@
       context_provider_wrapper_->ContextProvider()->GetGrContext();
   gr_context->flush();
 
-  RefPtr<ImageInfo> image_info = CreateIOSurfaceBackedTexture();
+  RefPtr<ImageInfo> image_info = CreateGpuMemoryBufferBackedTexture();
   if (!image_info)
     return false;
 
@@ -362,7 +362,7 @@
 }
 
 RefPtr<Canvas2DLayerBridge::ImageInfo>
-Canvas2DLayerBridge::CreateIOSurfaceBackedTexture() {
+Canvas2DLayerBridge::CreateGpuMemoryBufferBackedTexture() {
   if (!image_info_cache_.IsEmpty()) {
     RefPtr<Canvas2DLayerBridge::ImageInfo> info = image_info_cache_.back();
     image_info_cache_.pop_back();
@@ -434,11 +434,11 @@
   sk_sp<SkImage> skia_image = image->PaintImageForCurrentFrame().GetSkImage();
 
   if (RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled()) {
-    if (PrepareIOSurfaceMailboxFromImage(skia_image.get(), mailbox_info,
-                                         out_mailbox))
+    if (PrepareGpuMemoryBufferMailboxFromImage(skia_image.get(), mailbox_info,
+                                               out_mailbox))
       return true;
-    // Note: if IOSurface backed texture creation failed we fall back to the
-    // non-IOSurface path.
+    // Note: if GpuMemoryBuffer-backed texture creation failed we fall back to
+    // the non-GpuMemoryBuffer path.
   }
 
   mailbox_info->image_ = std::move(image);
@@ -1131,12 +1131,14 @@
   if (!GetOrCreateSurface(hint))
     return nullptr;
   FlushInternal();
-  // A readback operation may alter the texture parameters, which may affect
-  // the compositor's behavior. Therefore, we must trigger copy-on-write
-  // even though we are not technically writing to the texture, only to its
-  // parameters.
-  GetOrCreateSurface()->notifyContentWillChange(
-      SkSurface::kRetain_ContentChangeMode);
+  if (IsAccelerated()) {
+    // A readback operation may alter the texture parameters, which may affect
+    // the compositor's behavior. Therefore, we must trigger copy-on-write
+    // even though we are not technically writing to the texture, only to its
+    // parameters.
+    GetOrCreateSurface()->notifyContentWillChange(
+        SkSurface::kRetain_ContentChangeMode);
+  }
   RefPtr<StaticBitmapImage> image = StaticBitmapImage::Create(
       surface_->makeImageSnapshot(), ContextProviderWrapper());
   if (image->IsTextureBacked()) {
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index a6799f3..c84a381 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -175,7 +175,7 @@
   struct MailboxInfo {
     RefPtr<StaticBitmapImage> image_;
 
-    // If this mailbox wraps an IOSurface-backed texture, the ids of the
+    // If this mailbox wraps an GpuMemoryBuffer-backed texture, the ids of the
     // CHROMIUM image and the texture.
     RefPtr<ImageInfo> image_info_;
 
@@ -204,18 +204,19 @@
   // Returns the GL filter associated with |m_filterQuality|.
   GLenum GetGLFilter();
 
-  // Creates an IOSurface-backed texture. Copies |image| into the texture.
+  // Creates an GpuMemoryBuffer-backed texture. Copies |image| into the texture.
   // Prepares a mailbox from the texture. The caller must have created a new
   // MailboxInfo, and prepended it to |m_mailboxs|. Returns whether the
   // mailbox was successfully prepared. |mailbox| is an out parameter only
   // populated on success.
-  bool PrepareIOSurfaceMailboxFromImage(SkImage*,
-                                        MailboxInfo*,
-                                        viz::TextureMailbox*);
+  bool PrepareGpuMemoryBufferMailboxFromImage(SkImage*,
+                                              MailboxInfo*,
+                                              viz::TextureMailbox*);
 
-  // Creates an IOSurface-backed texture. Returns an ImageInfo, which is empty
-  // on failure. The caller takes ownership of both the texture and the image.
-  RefPtr<ImageInfo> CreateIOSurfaceBackedTexture();
+  // Creates an GpuMemoryBuffer-backed texture. Returns an ImageInfo, which is
+  // empty on failure. The caller takes ownership of both the texture and the
+  // image.
+  RefPtr<ImageInfo> CreateGpuMemoryBufferBackedTexture();
 
   // Releases all resources in the CHROMIUM image cache.
   void ClearCHROMIUMImageCache();
@@ -270,8 +271,8 @@
   CanvasColorParams color_params_;
   int recording_pixel_count_;
 
-  // Each element in this vector represents an IOSurface backed texture that
-  // is ready to be reused.
+  // Each element in this vector represents an GpuMemoryBuffer-backed texture
+  // that is ready to be reused.
   // Elements in this vector can safely be purged in low memory conditions.
   Vector<RefPtr<ImageInfo>> image_info_cache_;
 };
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
index 435a8df4..cb72bc7 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -25,12 +25,14 @@
 
 #include "platform/graphics/Canvas2DLayerBridge.h"
 
+#include "build/build_config.h"
 #include "components/viz/common/quads/single_release_callback.h"
 #include "components/viz/common/quads/texture_mailbox.h"
 #include "components/viz/test/test_gpu_memory_buffer_manager.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/common/capabilities.h"
 #include "platform/CrossThreadFunctional.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/WaitableEvent.h"
 #include "platform/WebTaskRunner.h"
 #include "platform/graphics/ImageBuffer.h"
@@ -1088,12 +1090,10 @@
   EXPECT_TRUE(bridge->IsValid());
 }
 
-#if USE_IOSURFACE_FOR_2D_CANVAS
-TEST_F(Canvas2DLayerBridgeTest, DeleteIOSurfaceAfterTeardown)
-#else
-TEST_F(Canvas2DLayerBridgeTest, DISABLED_DeleteIOSurfaceAfterTeardown)
+TEST_F(Canvas2DLayerBridgeTest, DeleteGpuMemoryBufferAfterTeardown) {
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+  RuntimeEnabledFeatures::SetCanvas2dImageChromiumEnabled(true);
 #endif
-{
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
 
   viz::TextureMailbox texture_mailbox;
@@ -1109,9 +1109,13 @@
 
   bool lost_resource = false;
   release_callback->Run(gpu::SyncToken(), lost_resource);
-
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
   EXPECT_EQ(1u, gl_.CreateImageCount());
   EXPECT_EQ(1u, gl_.DestroyImageCount());
+#else
+  EXPECT_EQ(0u, gl_.CreateImageCount());
+  EXPECT_EQ(0u, gl_.DestroyImageCount());
+#endif
 }
 
 TEST_F(Canvas2DLayerBridgeTest, NoUnnecessaryFlushes) {
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 5cebe4b..e21546f 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -559,33 +559,78 @@
     return json;
   }
 
-  void Walk(const GraphicsLayer& layer,
-            int parent_transform_id,
-            const FloatPoint& parent_offset) {
-    FloatPoint offset = parent_offset;
-    int transform_id = parent_transform_id;
-    std::unique_ptr<JSONObject> transform_json;
-    if (!layer.transform_.IsIdentity() || layer.rendering_context3d_) {
-      transform_json = JSONObject::Create();
-      transform_id = next_transform_id_++;
-      transform_json->SetInteger("id", transform_id);
-      if (parent_transform_id)
-        transform_json->SetInteger("parent", parent_transform_id);
-      layer.AddTransformJSONProperties(*transform_json, rendering_context_map_);
-      transforms_json_->PushObject(std::move(transform_json));
+  JSONObject* AddTransformJSON(int& transform_id) {
+    auto transform_json = JSONObject::Create();
+    int parent_transform_id = transform_id;
+    transform_id = next_transform_id_++;
+    transform_json->SetInteger("id", transform_id);
+    if (parent_transform_id)
+      transform_json->SetInteger("parent", parent_transform_id);
+    auto* result = transform_json.get();
+    transforms_json_->PushObject(std::move(transform_json));
+    return result;
+  }
 
-      offset = FloatPoint();
+  static FloatPoint ScrollPosition(const GraphicsLayer& layer) {
+    const auto* scrollable_area = layer.GetScrollableArea();
+    if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
+      // The LayoutView layer's scrollable area is on the "Frame Scrolling
+      // Layer" ancestor.
+      if (layer.DebugName() == "LayoutView #document")
+        scrollable_area = layer.Parent()->Parent()->GetScrollableArea();
+      else if (layer.DebugName() == "Frame Scrolling Layer")
+        scrollable_area = nullptr;
+    }
+    return scrollable_area ? scrollable_area->ScrollPosition() : FloatPoint();
+  }
+
+  void AddLayer(const GraphicsLayer& layer,
+                int& transform_id,
+                FloatPoint& position) {
+    FloatPoint scroll_position = ScrollPosition(layer);
+    if (scroll_position != FloatPoint()) {
+      // Output scroll position as a transform.
+      auto* scroll_translate_json = AddTransformJSON(transform_id);
+      scroll_translate_json->SetArray(
+          "transform", TransformAsJSONArray(TransformationMatrix().Translate(
+                           -scroll_position.X(), -scroll_position.Y())));
+      layer.AddFlattenInheritedTransformJSON(*scroll_translate_json);
+    }
+
+    if (!layer.transform_.IsIdentity() || layer.rendering_context3d_) {
+      if (position != FloatPoint()) {
+        // Output position offset as a transform.
+        auto* position_translate_json = AddTransformJSON(transform_id);
+        position_translate_json->SetArray(
+            "transform", TransformAsJSONArray(TransformationMatrix().Translate(
+                             position.X(), position.Y())));
+        layer.AddFlattenInheritedTransformJSON(*position_translate_json);
+        if (layer.Parent() && !layer.Parent()->should_flatten_transform_) {
+          position_translate_json->SetBoolean("flattenInheritedTransform",
+                                              false);
+        }
+      }
+
+      auto* transform_json = AddTransformJSON(transform_id);
+      layer.AddTransformJSONProperties(*transform_json, rendering_context_map_);
+      position = FloatPoint();
     }
 
     auto json =
-        layer.LayerAsJSONInternal(flags_, rendering_context_map_, offset);
+        layer.LayerAsJSONInternal(flags_, rendering_context_map_, position);
     if (transform_id)
       json->SetInteger("transform", transform_id);
     layers_json_->PushObject(std::move(json));
+  }
 
-    offset += layer.position_;
+  void Walk(const GraphicsLayer& layer,
+            int parent_transform_id,
+            const FloatPoint& parent_position) {
+    FloatPoint position = parent_position + layer.position_;
+    int transform_id = parent_transform_id;
+    AddLayer(layer, transform_id, position);
     for (auto& child : layer.children_)
-      Walk(*child, transform_id, offset);
+      Walk(*child, transform_id, position);
   }
 
  private:
@@ -610,7 +655,7 @@
 std::unique_ptr<JSONObject> GraphicsLayer::LayerAsJSONInternal(
     LayerTreeFlags flags,
     RenderingContextMap& rendering_context_map,
-    const FloatPoint& offset) const {
+    const FloatPoint& position) const {
   std::unique_ptr<JSONObject> json = JSONObject::Create();
 
   if (flags & kLayerTreeIncludesDebugInfo)
@@ -618,7 +663,6 @@
 
   json->SetString("name", DebugName());
 
-  FloatPoint position = offset + position_;
   if (position != FloatPoint())
     json->SetArray("position", PointAsJSONArray(position));
 
@@ -662,8 +706,16 @@
                     background_color_.NameForLayoutTreeAsText());
   }
 
-  if (flags & kOutputAsLayerTree)
+  if (flags & kOutputAsLayerTree) {
     AddTransformJSONProperties(*json, rendering_context_map);
+    if (!should_flatten_transform_)
+      json->SetBoolean("shouldFlattenTransform", false);
+    if (scrollable_area_ &&
+        scrollable_area_->ScrollPosition() != FloatPoint()) {
+      json->SetArray("scrollPosition",
+                     PointAsJSONArray(scrollable_area_->ScrollPosition()));
+    }
+  }
 
   if (flags & kLayerTreeIncludesPaintInvalidations)
     GetRasterInvalidationTrackingMap().AsJSON(this, json.get());
@@ -727,8 +779,8 @@
 
   if (mask_layer_) {
     std::unique_ptr<JSONArray> mask_layer_json = JSONArray::Create();
-    mask_layer_json->PushObject(
-        mask_layer_->LayerAsJSONInternal(flags, rendering_context_map));
+    mask_layer_json->PushObject(mask_layer_->LayerAsJSONInternal(
+        flags, rendering_context_map, mask_layer_->position_));
     json->SetArray("maskLayer", std::move(mask_layer_json));
   }
 
@@ -737,7 +789,8 @@
         JSONArray::Create();
     contents_clipping_mask_layer_json->PushObject(
         contents_clipping_mask_layer_->LayerAsJSONInternal(
-            flags, rendering_context_map));
+            flags, rendering_context_map,
+            contents_clipping_mask_layer_->position_));
     json->SetArray("contentsClippingMaskLayer",
                    std::move(contents_clipping_mask_layer_json));
   }
@@ -749,7 +802,7 @@
     LayerTreeFlags flags,
     RenderingContextMap& rendering_context_map) const {
   std::unique_ptr<JSONObject> json =
-      LayerAsJSONInternal(flags, rendering_context_map);
+      LayerAsJSONInternal(flags, rendering_context_map, position_);
 
   if (children_.size()) {
     std::unique_ptr<JSONArray> children_json = JSONArray::Create();
@@ -772,8 +825,7 @@
   if (!transform_.IsIdentityOrTranslation())
     json.SetArray("origin", PointAsJSONArray(transform_origin_));
 
-  if (!should_flatten_transform_)
-    json.SetBoolean("flattenInheritedTransform", false);
+  AddFlattenInheritedTransformJSON(json);
 
   if (rendering_context3d_) {
     auto it = rendering_context_map.find(rendering_context3d_);
@@ -787,6 +839,11 @@
   }
 }
 
+void GraphicsLayer::AddFlattenInheritedTransformJSON(JSONObject& json) const {
+  if (Parent() && !Parent()->should_flatten_transform_)
+    json.SetBoolean("flattenInheritedTransform", false);
+}
+
 String GraphicsLayer::GetLayerTreeAsTextForTesting(LayerTreeFlags flags) const {
   return LayerTreeAsJSON(flags)->ToPrettyJSONString();
 }
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
index 3fe1675..0afce88 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
@@ -331,8 +331,9 @@
   std::unique_ptr<JSONObject> LayerAsJSONInternal(
       LayerTreeFlags,
       RenderingContextMap&,
-      const FloatPoint& = FloatPoint()) const;
+      const FloatPoint& position) const;
   void AddTransformJSONProperties(JSONObject&, RenderingContextMap&) const;
+  void AddFlattenInheritedTransformJSON(JSONObject&) const;
   class LayersAsJSONArray;
 
   sk_sp<PaintRecord> CaptureRecord();
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
index 101f9d0b..c94d123 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -134,6 +134,9 @@
 
   const gfx::Rect bounds(width_, height_);
   const int kRenderPassId = 1;
+  bool is_clipped = false;
+  // TODO(crbug.com/705019): optimize for contexts that have {alpha: false}
+  bool are_contents_opaque = false;
   std::unique_ptr<cc::RenderPass> pass = cc::RenderPass::Create();
   pass->SetNew(kRenderPassId, bounds,
                gfx::Rect(damage_rect.x(), damage_rect.y(), damage_rect.width(),
@@ -141,8 +144,8 @@
                gfx::Transform());
 
   viz::SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
-  sqs->SetAll(gfx::Transform(), bounds, bounds, bounds, false, 1.f,
-              SkBlendMode::kSrcOver, 0);
+  sqs->SetAll(gfx::Transform(), bounds, bounds, bounds, is_clipped,
+              are_contents_opaque, 1.f, SkBlendMode::kSrcOver, 0);
 
   viz::TransferableResource resource;
   offscreen_canvas_resource_provider_->TransferResource(&resource);
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
index e264ecb..4641174 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
@@ -14,10 +14,12 @@
 void VideoFrameResourceProvider::AppendQuads(cc::RenderPass& render_pass) {
   gfx::Rect rect(0, 0, 10000, 10000);
   gfx::Rect visible_rect(0, 0, 10000, 10000);
+  bool is_clipped = false;
+  bool are_contents_opaque = true;
   viz::SharedQuadState* shared_state =
       render_pass.CreateAndAppendSharedQuadState();
-  shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1,
-                       SkBlendMode::kSrcOver, 0);
+  shared_state->SetAll(gfx::Transform(), rect, rect, rect, is_clipped,
+                       are_contents_opaque, 1, SkBlendMode::kSrcOver, 0);
   cc::SolidColorDrawQuad* solid_color_quad =
       render_pass.CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>();
   // Fluxuate colors for placeholder testing.
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.cpp b/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.cpp
index d1eadac3..c047fe6 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/ContentLayerClientImpl.cpp
@@ -47,16 +47,16 @@
   if (it != context.transform_id_map.end())
     return it->value;
 
-  if ((transform->Matrix().IsIdentity() && !transform->RenderingContextId()) ||
-      // Don't output scroll translations in transform tree.
-      transform->ScrollNode()) {
-    context.transform_id_map.Set(transform, 0);
-    return 0;
+  int parent_id = GetTransformId(transform->Parent(), context);
+  if (transform->Matrix().IsIdentity() && !transform->RenderingContextId()) {
+    context.transform_id_map.Set(transform, parent_id);
+    return parent_id;
   }
 
-  int parent_id = GetTransformId(transform->Parent(), context);
-  auto json = JSONObject::Create();
   int transform_id = context.next_transform_id++;
+  context.transform_id_map.Set(transform, transform_id);
+
+  auto json = JSONObject::Create();
   json->SetInteger("id", transform_id);
   if (parent_id)
     json->SetInteger("parent", parent_id);
diff --git a/third_party/WebKit/Source/platform/image-decoders/DEPS b/third_party/WebKit/Source/platform/image-decoders/DEPS
new file mode 100644
index 0000000..3c137cbc
--- /dev/null
+++ b/third_party/WebKit/Source/platform/image-decoders/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+    "+cc/paint/image_animation_count.h",
+]
\ No newline at end of file
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageAnimation.h b/third_party/WebKit/Source/platform/image-decoders/ImageAnimation.h
index 26c8442..f51a568c 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageAnimation.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageAnimation.h
@@ -26,26 +26,12 @@
 #ifndef ImageAnimation_h
 #define ImageAnimation_h
 
+#include "cc/paint/image_animation_count.h"
+
 namespace blink {
-
-// GIF and WebP support animation. The explanation below is in terms of GIF,
-// but the same constants are used for WebP, too.
-// GIFs have an optional 16-bit unsigned loop count that describes how an
-// animated GIF should be cycled.  If the loop count is absent, the animation
-// cycles once; if it is 0, the animation cycles infinitely; otherwise the
-// animation plays n + 1 cycles (where n is the specified loop count).  If the
-// GIF decoder defaults to kAnimationLoopOnce in the absence of any loop count
-// and translates an explicit "0" loop count to kAnimationLoopInfinite, then we
-// get a couple of nice side effects:
-//   * By making kAnimationLoopOnce be 0, we allow the animation cycling code in
-//     BitmapImage.cpp to avoid special-casing it, and simply treat all
-//     non-negative loop counts identically.
-//   * By making the other two constants negative, we avoid conflicts with any
-//     real loop count values.
-const int kAnimationLoopOnce = 0;
-const int kAnimationLoopInfinite = -1;
-const int kAnimationNone = -2;
-
+using cc::kAnimationLoopOnce;
+using cc::kAnimationLoopInfinite;
+using cc::kAnimationNone;
 }  // namespace blink
 
 #endif
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.h b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.h
index e44e3375..838a1ed 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.h
@@ -53,6 +53,7 @@
 // one in CrossThreadFetchParametersData and write copying logic.
 class PLATFORM_EXPORT FetchParameters {
   DISALLOW_NEW();
+  WTF_MAKE_NONCOPYABLE(FetchParameters);
 
  public:
   enum DeferOption { kNoDefer, kLazyLoad, kIdleLoad };
diff --git a/third_party/WebKit/Source/platform/scheduler/DEPS b/third_party/WebKit/Source/platform/scheduler/DEPS
index e4af261..6017b541 100644
--- a/third_party/WebKit/Source/platform/scheduler/DEPS
+++ b/third_party/WebKit/Source/platform/scheduler/DEPS
@@ -16,6 +16,7 @@
   "+base/metrics/field_trial.h",
   "+base/metrics/field_trial_params.h",
   "+base/metrics/histogram_macros.h",
+  "+base/observer_list.h",
   "+base/optional.h",
   "+base/pending_task.h",
   "+base/run_loop.h",
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h
index 03a6cda..e786fc7 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler.h
@@ -78,6 +78,21 @@
   // WebFrameSchedulers.
   virtual void SetVirtualTimePolicy(VirtualTimePolicy) = 0;
 
+  class VirtualTimeObserver {
+   public:
+    virtual ~VirtualTimeObserver() {}
+
+    // Called the next microtask after virtual time pauses for any reason.
+    // |virtual_time_offset| is the offset between the current virtual time and
+    // the initial virtual time when EnableVirtualTime() was called.
+    virtual void OnVirtualTimePaused(base::TimeDelta virtual_time_offset) = 0;
+  };
+
+  // Adds a VirtualTimeObserver instance to be notified when virtual time has
+  // been paused.
+  virtual void AddVirtualTimeObserver(VirtualTimeObserver*) = 0;
+  virtual void RemoveVirtualTimeObserver(VirtualTimeObserver*) = 0;
+
   // Set the remaining virtual time budget to |budget|. Once the budget runs
   // out, |budget_exhausted_callback| is called. Note that the virtual time
   // policy is not affected when the budget expires.
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
index cbf4f738..728b05c 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
@@ -181,6 +181,8 @@
   virtual_time_control_task_queue_ = WebTaskRunnerImpl::Create(
       renderer_scheduler_->VirtualTimeControlTaskQueue());
   ApplyVirtualTimePolicyToTimers();
+
+  initial_virtual_time_ = renderer_scheduler_->GetVirtualTimeDomain()->Now();
 }
 
 void WebViewSchedulerImpl::DisableVirtualTimeForTesting() {
@@ -215,6 +217,9 @@
   if (!virtual_time_)
     return;
 
+  if (!allow_virtual_time_to_advance)
+    NotifyVirtualTimePaused();
+
   renderer_scheduler_->GetVirtualTimeDomain()->SetCanAdvanceVirtualTime(
       allow_virtual_time_to_advance);
   ApplyVirtualTimePolicyToTimers();
@@ -297,6 +302,26 @@
           BLINK_FROM_HERE, std::move(budget_exhausted_callback), budget);
 }
 
+void WebViewSchedulerImpl::AddVirtualTimeObserver(
+    VirtualTimeObserver* observer) {
+  virtual_time_observers_.AddObserver(observer);
+}
+
+void WebViewSchedulerImpl::RemoveVirtualTimeObserver(
+    VirtualTimeObserver* observer) {
+  virtual_time_observers_.RemoveObserver(observer);
+}
+
+void WebViewSchedulerImpl::NotifyVirtualTimePaused() {
+  DCHECK(!allow_virtual_time_to_advance_);
+
+  for (auto& observer : virtual_time_observers_) {
+    observer.OnVirtualTimePaused(
+        renderer_scheduler_->GetVirtualTimeDomain()->Now() -
+        initial_virtual_time_);
+  }
+}
+
 void WebViewSchedulerImpl::AudioStateChanged(bool is_audio_playing) {
   is_audio_playing_ = is_audio_playing;
   renderer_scheduler_->OnAudioStateChanged();
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
index edc7eef..bd7a3fd 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "platform/PlatformExport.h"
 #include "platform/scheduler/base/task_queue.h"
 #include "platform/scheduler/child/web_scheduler.h"
@@ -54,6 +55,8 @@
   void AudioStateChanged(bool is_audio_playing) override;
   bool HasActiveConnectionForTest() const override;
   void RequestBeginMainFrameNotExpected(bool new_state) override;
+  void AddVirtualTimeObserver(VirtualTimeObserver*) override;
+  void RemoveVirtualTimeObserver(VirtualTimeObserver*) override;
 
   // Virtual for testing.
   virtual void ReportIntervention(const std::string& message);
@@ -101,6 +104,8 @@
   // number of active connections.
   void UpdateBackgroundBudgetPoolThrottlingState();
 
+  void NotifyVirtualTimePaused();
+
   std::set<WebFrameSchedulerImpl*> frame_schedulers_;
   std::set<unsigned long> pending_loads_;
   std::set<WebFrameSchedulerImpl*> provisional_loads_;
@@ -122,6 +127,8 @@
   bool has_active_connection_;
   CPUTimeBudgetPool* background_time_budget_pool_;  // Not owned.
   WebViewScheduler::WebViewSchedulerDelegate* delegate_;  // Not owned.
+  base::ObserverList<VirtualTimeObserver> virtual_time_observers_;
+  base::TimeTicks initial_virtual_time_;
 
   DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImpl);
 };
diff --git a/third_party/WebKit/Source/platform/scheduler/test/DEPS b/third_party/WebKit/Source/platform/scheduler/test/DEPS
deleted file mode 100644
index 8905565..0000000
--- a/third_party/WebKit/Source/platform/scheduler/test/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
-  "+components/scheduler/base",
-  "+components/scheduler/child",
-  "+components/scheduler/renderer",
-]
diff --git a/third_party/WebKit/Source/platform/text/CharacterPropertyDataGenerator.cpp b/third_party/WebKit/Source/platform/text/CharacterPropertyDataGenerator.cpp
index f3000190..0346f49 100644
--- a/third_party/WebKit/Source/platform/text/CharacterPropertyDataGenerator.cpp
+++ b/third_party/WebKit/Source/platform/text/CharacterPropertyDataGenerator.cpp
@@ -55,7 +55,9 @@
           "#include <cstdint>\n\n"
           "namespace blink {\n\n"
           "extern const int32_t kSerializedCharacterDataSize = %d;\n"
-          "extern const uint8_t kSerializedCharacterData[] = {",
+          // The utrie2_openFromSerialized function requires character data to
+          // be aligned to 4 bytes.
+          "alignas(4) extern const uint8_t kSerializedCharacterData[] = {",
           size);
   for (int32_t i = 0; i < size;) {
     fprintf(fp, "\n   ");
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
index a8f6091..4de5d3c 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
+++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
@@ -53,17 +53,6 @@
   return num;
 }
 
-static inline bool IsBreakableSpace(UChar ch) {
-  switch (ch) {
-    case ' ':
-    case '\n':
-    case '\t':
-      return true;
-    default:
-      return false;
-  }
-}
-
 static const UChar kAsciiLineBreakTableFirstChar = '!';
 static const UChar kAsciiLineBreakTableLastChar = 127;
 
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.h b/third_party/WebKit/Source/platform/text/TextBreakIterator.h
index e1d1127e..2c5e810 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIterator.h
+++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.h
@@ -24,6 +24,7 @@
 
 #include "platform/PlatformExport.h"
 #include "platform/wtf/text/AtomicString.h"
+#include "platform/wtf/text/CharacterNames.h"
 #include "platform/wtf/text/Unicode.h"
 
 #include <unicode/brkiter.h>
@@ -246,6 +247,11 @@
   // Returns the break opportunity at or before |offset|.
   unsigned PreviousBreakOpportunity(unsigned offset, unsigned min = 0) const;
 
+  static bool IsBreakableSpace(UChar ch) {
+    return ch == kSpaceCharacter || ch == kTabulationCharacter ||
+           ch == kNewlineCharacter;
+  }
+
  private:
   void ReleaseIterator() const {
     if (iterator_)
diff --git a/third_party/WebKit/Source/platform/text/TextRun.cpp b/third_party/WebKit/Source/platform/text/TextRun.cpp
index 6ef96b5..b21d1d75 100644
--- a/third_party/WebKit/Source/platform/text/TextRun.cpp
+++ b/third_party/WebKit/Source/platform/text/TextRun.cpp
@@ -102,4 +102,14 @@
   return WrapArrayUnique(buffer);
 }
 
+unsigned TextRun::IndexOfSubRun(const TextRun& sub_run) const {
+  if (Is8Bit() == sub_run.Is8Bit() && sub_run.Bytes() >= Bytes()) {
+    size_t start_index = Is8Bit() ? sub_run.Characters8() - Characters8()
+                                  : sub_run.Characters16() - Characters16();
+    if (start_index + sub_run.length() <= length())
+      return start_index;
+  }
+  return std::numeric_limits<unsigned>::max();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/text/TextRun.h b/third_party/WebKit/Source/platform/text/TextRun.h
index de79933e..3d7b2ea 100644
--- a/third_party/WebKit/Source/platform/text/TextRun.h
+++ b/third_party/WebKit/Source/platform/text/TextRun.h
@@ -32,6 +32,7 @@
 #include "platform/text/TextDirection.h"
 #include "platform/text/TextJustify.h"
 #include "platform/wtf/Allocator.h"
+#include "platform/wtf/Optional.h"
 #include "platform/wtf/text/StringView.h"
 #include "platform/wtf/text/WTFString.h"
 
@@ -150,6 +151,10 @@
     return result;
   }
 
+  // Returns the start index of a sub run if it was created by |SubRun|.
+  // std::numeric_limits<unsigned>::max() if not a sub run.
+  unsigned IndexOfSubRun(const TextRun&) const;
+
   UChar operator[](unsigned i) const {
     SECURITY_DCHECK(i < len_);
     return Is8Bit() ? data_.characters8[i] : data_.characters16[i];
diff --git a/third_party/WebKit/Source/platform/text/TextRunTest.cpp b/third_party/WebKit/Source/platform/text/TextRunTest.cpp
new file mode 100644
index 0000000..6ca7294
--- /dev/null
+++ b/third_party/WebKit/Source/platform/text/TextRunTest.cpp
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/text/TextRun.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(TextRunTest, IndexOfSubRun) {
+  TextRun run(String("1234567890"));
+  EXPECT_EQ(0u, run.IndexOfSubRun(run.SubRun(0, 4)));
+  EXPECT_EQ(4u, run.IndexOfSubRun(run.SubRun(4, 4)));
+  EXPECT_EQ(6u, run.IndexOfSubRun(run.SubRun(6, 4)));
+  const unsigned kNotSubRun = std::numeric_limits<unsigned>::max();
+  EXPECT_EQ(kNotSubRun, run.IndexOfSubRun(run.SubRun(7, 4)));
+  EXPECT_EQ(kNotSubRun, run.IndexOfSubRun(TextRun(String("1"))));
+  EXPECT_EQ(kNotSubRun, run.IndexOfSubRun(TextRun(String(u"1"))));
+
+  TextRun run16(String(u"1234567890"));
+  EXPECT_EQ(0u, run16.IndexOfSubRun(run16.SubRun(0, 4)));
+  EXPECT_EQ(4u, run16.IndexOfSubRun(run16.SubRun(4, 4)));
+  EXPECT_EQ(6u, run16.IndexOfSubRun(run16.SubRun(6, 4)));
+  EXPECT_EQ(kNotSubRun, run16.IndexOfSubRun(run16.SubRun(7, 4)));
+  EXPECT_EQ(kNotSubRun, run16.IndexOfSubRun(TextRun(String("1"))));
+  EXPECT_EQ(kNotSubRun, run16.IndexOfSubRun(TextRun(String(u"1"))));
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/wtf/BUILD.gn b/third_party/WebKit/Source/platform/wtf/BUILD.gn
index 0d1d76ea..ee673e3 100644
--- a/third_party/WebKit/Source/platform/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/platform/wtf/BUILD.gn
@@ -149,6 +149,7 @@
     "allocator/Partitions.h",
     "debug/Alias.h",
     "debug/CrashLogging.h",
+    "debug/DumpWithoutCrashing.h",
     "debug/StackTrace.h",
     "dtoa.cpp",
     "dtoa.h",
diff --git a/third_party/WebKit/Source/platform/wtf/ScopedLogger.md b/third_party/WebKit/Source/platform/wtf/ScopedLogger.md
index 5ea0d0f..3593e16 100644
--- a/third_party/WebKit/Source/platform/wtf/ScopedLogger.md
+++ b/third_party/WebKit/Source/platform/wtf/ScopedLogger.md
@@ -90,7 +90,6 @@
 following:
 
 * `dcheck_always_on`: enables assertions and ScopedLogger
-* `blink_logging_always_on`: enables ScopedLogger, but not assertions
 
 The macro names are cumbersome to type, but most editors can be configured to
 make this easier.  For example, you can add the following to a Sublime Text key
diff --git a/third_party/WebKit/Source/platform/wtf/debug/DEPS b/third_party/WebKit/Source/platform/wtf/debug/DEPS
index 0445c08..68d50c3 100644
--- a/third_party/WebKit/Source/platform/wtf/debug/DEPS
+++ b/third_party/WebKit/Source/platform/wtf/debug/DEPS
@@ -3,5 +3,6 @@
     # directories and files instead of writing 'base/'.
     "+base/debug/alias.h",
     "+base/debug/crash_logging.h",
+    "+base/debug/dump_without_crashing.h",
     "+base/debug/stack_trace.h",
 ]
diff --git a/third_party/WebKit/Source/platform/wtf/debug/DumpWithoutCrashing.h b/third_party/WebKit/Source/platform/wtf/debug/DumpWithoutCrashing.h
new file mode 100644
index 0000000..6a402791
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/debug/DumpWithoutCrashing.h
@@ -0,0 +1,21 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WTF_DumpWithoutCrashing_h
+#define WTF_DumpWithoutCrashing_h
+
+#include "base/debug/dump_without_crashing.h"
+
+namespace WTF {
+namespace debug {
+
+// See base::debug::DumpWithoutCrashing for documentation.
+inline void DumpWithoutCrashing() {
+  base::debug::DumpWithoutCrashing();
+}
+
+}  // namespace debug
+}  // namespace WTF
+
+#endif  // WTF_DumpWithoutCrashing_h
diff --git a/third_party/WebKit/Tools/Scripts/test-webkitpy b/third_party/WebKit/Tools/Scripts/test-webkitpy
index b9a0bd7..487793b 100755
--- a/third_party/WebKit/Tools/Scripts/test-webkitpy
+++ b/third_party/WebKit/Tools/Scripts/test-webkitpy
@@ -28,7 +28,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import os
 import sys
 
 from webkitpy.common import path_finder
@@ -38,15 +37,10 @@
 
 
 def main():
-    ret = typ.main(top_level_dir=path_finder.get_scripts_dir(),
-                   path=[path_finder.get_webkitpy_thirdparty_dir()],
-                   win_multiprocessing='spawn')
-    if ret:
-        sys.exit(ret)
-    path_finder.add_blink_tools_dir_to_sys_path()
-    sys.exit(typ.main(top_level_dir=path_finder.get_blink_tools_dir(),
-                      path=[],
-                      win_multiprocessing='spawn'))
+    return typ.main(top_level_dirs=[path_finder.get_scripts_dir(),
+                                    path_finder.get_blink_tools_dir()],
+                    path=[path_finder.get_webkitpy_thirdparty_dir()])
+
 
 if __name__ == "__main__":
-    main()
+    sys.exit(main())
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py
index 15e379b..4badc9d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py
@@ -44,21 +44,22 @@
         margin: 0;
         padding: 0;
     }
-    iframe {
-      position: absolute;
-      top: 80px;
-      left: 0;
-      border: 0;
-      z-index: -1;
+    #overlay {
+        width: 2000px;
+        height: 2000px;
+        border: 1px solid black;
+    }
+    #test_frame {
+        position: absolute;
+        width: 800px;
+        height: 600px;
+        border: 0;
     }
     canvas {
-      position: absolute;
-      top: 80px;
-      left: 0;
-      z-index: 1;
+        position: absolute;
     }
-    #actual {
-      display: none;
+    #actual_canvas {
+        display: none;
     }
 </style>
 </head>
@@ -66,16 +67,17 @@
 <label><input id="show-test" type="checkbox" checked onchange="toggle_test(this.checked)">Show test</label>
 <label><input id="use-solid-colors" type="checkbox" onchange="toggle_solid_color(this.checked)">Use solid colors</label>
 <br>
-<span id='type'>Expected Invalidations</span>
-<div id=overlay>
-    <canvas id='expected' width='2000' height='2000'></canvas>
-    <canvas id='actual' width='2000' height='2000'></canvas>
+<span id="overlay_type">Expected Invalidations</span>
+<div id="overlay">
+    <iframe id="test_frame"></iframe>
+    <canvas id="expected_canvas" width="2000" height="2000"></canvas>
+    <canvas id="actual_canvas" width="2000" height="2000"></canvas>
 </div>
 <script>
 var overlay_opacity = 0.25;
 
 function toggle_test(show_test) {
-    iframe.style.display = show_test ? 'block' : 'none';
+    test_frame.style.display = show_test ? 'block' : 'none';
 }
 
 function toggle_solid_color(use_solid_color) {
@@ -86,10 +88,6 @@
 var expected = %(expected)s;
 var actual = %(actual)s;
 
-function rectsEqual(rect1, rect2) {
-    return rect1[0] == rect2[0] && rect1[1] == rect2[1] && rect1[2] == rect2[2] && rect1[3] == rect2[3];
-}
-
 function draw_rects(context, rects) {
     for (var i = 0; i < rects.length; ++i) {
         var rect = rects[i];
@@ -97,22 +95,31 @@
     }
 }
 
-function draw_layer_rects(context, result) {
+function draw_layer_rects(context, transforms, layer) {
     context.save();
-    if (result.position)
-        context.translate(result.position[0], result.position[1]);
-    var t = result.transform;
-    if (t) {
-        var origin = result.transformOrigin || [result.bounds[0] / 2, result.bounds[1] / 2];
-        context.translate(origin[0], origin[1]);
-        context.transform(t[0][0], t[0][1], t[1][0], t[1][1], t[3][0], t[3][1]);
-        context.translate(-origin[0], -origin[1]);
+    var transform_path = [];
+    for (var id = layer.transform; id; id = transforms[id].parent)
+      transform_path.push(transforms[id]);
+
+    for (var i = transform_path.length - 1; i >= 0; i--) {
+        var m = transform_path[i].transform;
+        if (!m)
+          continue;
+        var origin = transform_path[i].origin;
+        if (origin)
+            context.translate(origin[0], origin[1]);
+        context.transform(m[0][0], m[0][1], m[1][0], m[1][1], m[3][0], m[3][1]);
+        if (origin)
+            context.translate(-origin[0], -origin[1]);
     }
-    if (result.paintInvalidations) {
+    if (layer.position)
+        context.translate(layer.position[0], layer.position[1]);
+
+    if (layer.paintInvalidations) {
         var rects = [];
-        for (var i = 0; i < result.paintInvalidations.length; ++i) {
-            if (result.paintInvalidations[i].rect)
-                rects.push(result.paintInvalidations[i].rect);
+        for (var i = 0; i < layer.paintInvalidations.length; ++i) {
+            if (layer.paintInvalidations[i].rect)
+                rects.push(layer.paintInvalidations[i].rect);
         }
         draw_rects(context, rects);
     }
@@ -120,15 +127,19 @@
 }
 
 function draw_result_rects(context, result) {
+    var transforms = {};
+    if (result.transforms) {
+        for (var i = 0; i < result.transforms.length; ++i) {
+            var transform = result.transforms[i];
+            transforms[transform.id] = transform;
+        }
+    }
     if (result.layers) {
         for (var i = 0; i < result.layers.length; ++i)
-            draw_layer_rects(context, result.layers[i]);
+            draw_layer_rects(context, transforms, result.layers[i]);
     }
 }
 
-var expected_canvas = document.getElementById('expected');
-var actual_canvas = document.getElementById('actual');
-
 function draw_repaint_rects() {
     var expected_ctx = expected_canvas.getContext("2d");
     expected_ctx.clearRect(0, 0, 2000, 2000);
@@ -143,25 +154,16 @@
 
 draw_repaint_rects();
 
-var path = decodeURIComponent(location.search).substr(1);
-var iframe = document.createElement('iframe');
-iframe.id = 'test-frame';
-iframe.width = 800;
-iframe.height = 600;
-iframe.src = path;
+test_frame.src = decodeURIComponent(location.search).substr(1);
 
-var overlay = document.getElementById('overlay');
-overlay.appendChild(iframe);
-
-var type = document.getElementById('type');
 var expected_showing = true;
 function flip() {
     if (expected_showing) {
-        type.textContent = 'Actual Invalidations';
+        overlay_type.textContent = 'Actual Invalidations';
         expected_canvas.style.display = 'none';
         actual_canvas.style.display = 'block';
     } else {
-        type.textContent = 'Expected Invalidations';
+        overlay_type.textContent = 'Expected Invalidations';
         actual_canvas.style.display = 'none';
         expected_canvas.style.display = 'block';
     }
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay_unittest.py
index fd280b8..ed9120b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay_unittest.py
@@ -4,6 +4,7 @@
 
 import unittest
 
+from webkitpy.common.host import Host
 from webkitpy.layout_tests.controllers import repaint_overlay
 
 
@@ -46,3 +47,23 @@
 
     def test_extract_layer_tree(self):
         self.assertEquals(LAYER_TREE, repaint_overlay.extract_layer_tree(LAYER_TREE))
+
+    def test_generate_repaint_overlay_html(self):
+        test_name = 'paint/invalidation/repaint-overlay/layers.html'
+        host = Host()
+        port = host.port_factory.get()
+        layer_tree_file = port.expected_filename(test_name, '.txt')
+        if not layer_tree_file or not host.filesystem.exists(layer_tree_file):
+            # This can happen if the scripts are not in the standard blink directory.
+            return
+
+        layer_tree = str(host.filesystem.read_text_file(layer_tree_file))
+        self.assertTrue(repaint_overlay.result_contains_repaint_rects(layer_tree))
+        overlay_html = (
+            '<!-- Generated by Tools/Scripts/test-webkitpy\n' +
+            ' test case: TestRepaintOverlay.test_generate_repaint_overlay_html. -->\n' +
+            repaint_overlay.generate_repaint_overlay_html(test_name, layer_tree, layer_tree))
+        overlay_html_test_name = 'paint/invalidation/repaint-overlay/layers-overlay.html'
+        overlay_html_file = port.abspath_for_test(overlay_html_test_name)
+        host.filesystem.write_text_file(overlay_html_file, overlay_html)
+        # The correctness of overlay html will be tested as a layout test.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py
index 81f55466..ccf00188 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py
@@ -314,14 +314,43 @@
         return text and 'layer at (0,0) size 800x600' in text
 
     def _compare_text(self, expected_text, actual_text):
-        failures = []
-        if (expected_text and actual_text and
-                # Assuming expected_text is already normalized.
-                self._port.do_text_results_differ(expected_text, self._get_normalized_output_text(actual_text))):
-            failures.append(test_failures.FailureTextMismatch())
-        elif actual_text and not expected_text:
-            failures.append(test_failures.FailureMissingResult())
-        return failures
+        if not actual_text:
+            return []
+        if not expected_text:
+            return [test_failures.FailureMissingResult()]
+
+        normalized_actual_text = self._get_normalized_output_text(actual_text)
+        # Assuming expected_text is already normalized.
+        if not self._port.do_text_results_differ(expected_text, normalized_actual_text):
+            return []
+
+        # Determine the text mismatch type
+
+        def remove_chars(text, chars):
+            for char in chars:
+                text = text.replace(char, '')
+            return text
+
+        # General text mismatch
+        if self._port.do_text_results_differ(
+                remove_chars(expected_text, ' \t\n'),
+                remove_chars(normalized_actual_text, ' \t\n')):
+            return [test_failures.FailureTextMismatch()]
+
+        # Space-only mismatch
+        if not self._port.do_text_results_differ(
+                remove_chars(expected_text, ' \t'),
+                remove_chars(normalized_actual_text, ' \t')):
+            return [test_failures.FailureSpacesAndTabsTextMismatch()]
+
+        # Newline-only mismatch
+        if not self._port.do_text_results_differ(
+                remove_chars(expected_text, '\n'),
+                remove_chars(normalized_actual_text, '\n')):
+            return [test_failures.FailureLineBreaksTextMismatch()]
+
+        # Spaces and newlines
+        return [test_failures.FailureSpaceTabLineBreakTextMismatch()]
 
     def _compare_audio(self, expected_audio, actual_audio):
         failures = []
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures.py
index 0c23f06c..210a118 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures.py
@@ -41,6 +41,11 @@
     }
     return bool(input_failure_types & reftest_failure_types)
 
+
+def has_failure_type(failure_type, failure_list):
+    return any(isinstance(failure, failure_type) for failure in failure_list)
+
+
 # FIXME: This is backwards.  Each TestFailure subclass should know what
 # test_expectation type it corresponds too.  Then this method just
 # collects them all from the failure list and returns the worst one.
@@ -57,27 +62,26 @@
     if not failure_list or len(failure_list) == 0:
         return test_expectations.PASS
 
-    failure_types = [type(f) for f in failure_list]
-    if FailureCrash in failure_types:
+    if has_failure_type(FailureCrash, failure_list):
         return test_expectations.CRASH
-    elif FailureLeak in failure_types:
+    elif has_failure_type(FailureLeak, failure_list):
         return test_expectations.LEAK
-    elif FailureTimeout in failure_types:
+    elif has_failure_type(FailureTimeout, failure_list):
         return test_expectations.TIMEOUT
-    elif FailureEarlyExit in failure_types:
+    elif has_failure_type(FailureEarlyExit, failure_list):
         return test_expectations.SKIP
-    elif (FailureMissingResult in failure_types or
-          FailureMissingImage in failure_types or
-          FailureMissingImageHash in failure_types or
-          FailureMissingAudio in failure_types):
+    elif (has_failure_type(FailureMissingResult, failure_list) or
+          has_failure_type(FailureMissingImage, failure_list) or
+          has_failure_type(FailureMissingImageHash, failure_list) or
+          has_failure_type(FailureMissingAudio, failure_list)):
         return test_expectations.MISSING
     else:
-        is_text_failure = (FailureTextMismatch in failure_types or
-                           FailureTestHarnessAssertion in failure_types)
-        is_image_failure = (FailureImageHashIncorrect in failure_types or
-                            FailureImageHashMismatch in failure_types or
+        is_text_failure = (has_failure_type(FailureTextMismatch, failure_list) or
+                           has_failure_type(FailureTestHarnessAssertion, failure_list))
+        is_image_failure = (has_failure_type(FailureImageHashIncorrect, failure_list) or
+                            has_failure_type(FailureImageHashMismatch, failure_list) or
                             is_reftest_failure(failure_list))
-        is_audio_failure = (FailureAudioMismatch in failure_types)
+        is_audio_failure = has_failure_type(FailureAudioMismatch, failure_list)
         if is_text_failure and is_image_failure:
             return test_expectations.IMAGE_PLUS_TEXT
         elif is_text_failure:
@@ -87,6 +91,7 @@
         elif is_audio_failure:
             return test_expectations.AUDIO
         else:
+            failure_types = [type(failure) for failure in failure_list]
             raise ValueError('unclassifiable set of failures: '
                              + str(failure_types))
 
@@ -180,6 +185,36 @@
     def message(self):
         return 'text diff'
 
+    def text_mismatch_category(self):
+        return 'general text mismatch'
+
+
+class FailureSpacesAndTabsTextMismatch(FailureTextMismatch):
+
+    def message(self):
+        return 'text diff by spaces and tabs only'
+
+    def text_mismatch_category(self):
+        return 'spaces and tabs only'
+
+
+class FailureLineBreaksTextMismatch(FailureTextMismatch):
+
+    def message(self):
+        return 'text diff by newlines only'
+
+    def text_mismatch_category(self):
+        return 'newlines only'
+
+
+class FailureSpaceTabLineBreakTextMismatch(FailureTextMismatch):
+
+    def message(self):
+        return 'text diff by spaces, tabs and newlines only'
+
+    def text_mismatch_category(self):
+        return 'spaces, tabs and newlines only'
+
 
 class FailureMissingImageHash(TestFailure):
 
@@ -267,7 +302,9 @@
 # need to enumerate over them all.
 ALL_FAILURE_CLASSES = (FailureTimeout, FailureCrash, FailureMissingResult,
                        FailureTestHarnessAssertion,
-                       FailureTextMismatch, FailureMissingImageHash,
+                       FailureTextMismatch, FailureSpacesAndTabsTextMismatch,
+                       FailureLineBreaksTextMismatch, FailureSpaceTabLineBreakTextMismatch,
+                       FailureMissingImageHash,
                        FailureMissingImage, FailureImageHashMismatch,
                        FailureImageHashIncorrect, FailureReftestMismatch,
                        FailureReftestMismatchDidNotOccur,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py
index b7c6b035..679e0f21 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py
@@ -257,6 +257,12 @@
         if len(crash_sites) > 0:
             test_dict['crash_site'] = crash_sites[0]
 
+        if test_failures.has_failure_type(test_failures.FailureTextMismatch, result.failures):
+            for failure in result.failures:
+                if isinstance(failure, test_failures.FailureTextMismatch):
+                    test_dict['text_mismatch'] = failure.text_mismatch_category()
+                    break
+
         def is_expected(actual_result):
             return expectations.matches_an_expected_result(test_name, actual_result,
                                                            port_obj.get_option('pixel_tests') or result.reftest_type,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index 87c3b98..2510a234 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -582,7 +582,10 @@
         self.assertEqual(details.exit_code, 2)
         json_string = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json')
         self.assertTrue(json_string.find(
-            '"text-image-checksum.html":{"expected":"PASS","actual":"IMAGE+TEXT","is_unexpected":true') != -1)
+            '"text-image-checksum.html":{'
+            '"expected":"PASS",'
+            '"text_mismatch":"general text mismatch",'
+            '"actual":"IMAGE+TEXT","is_unexpected":true') != -1)
         self.assertTrue(json_string.find(
             '"missing_text.html":{"expected":"PASS","is_missing_text":true,"actual":"MISSING","is_unexpected":true') != -1)
         self.assertTrue(json_string.find('"num_regressions":2') != -1)
@@ -801,7 +804,10 @@
         json_string = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json')
         results = parse_full_results(json_string)
         self.assertEqual(results['tests']['failures']['unexpected']['text-image-checksum.html'],
-                         {'expected': 'PASS', 'actual': 'TEXT IMAGE+TEXT IMAGE+TEXT IMAGE+TEXT', 'is_unexpected': True})
+                         {'expected': 'PASS',
+                          'actual': 'TEXT IMAGE+TEXT IMAGE+TEXT IMAGE+TEXT',
+                          'is_unexpected': True,
+                          'text_mismatch': 'general text mismatch'})
         self.assertFalse(results['pixel_tests_enabled'])
         self.assertTrue(details.enabled_pixel_tests_in_retry)
 
@@ -969,22 +975,6 @@
         self.assertEqual(stdout.getvalue(), '')
         self.assertTrue('unsupported platform' in stderr.getvalue())
 
-    def test_build_check(self):
-        # By using a port_name for a different platform than the one
-        # we're running on, the build check should always fail because
-        # the binary should not be present.
-        if sys.platform == 'darwin':
-            port_name = 'linux-trusty'
-        else:
-            port_name = 'mac-mac10.11'
-        stdout = StringIO.StringIO()
-        stderr = StringIO.StringIO()
-        self.assertEqual(
-            run_webkit_tests.main(['--platform', port_name, 'fast/harness/results.html'], stdout, stderr),
-            exit_codes.UNEXPECTED_ERROR_EXIT_STATUS)
-        self.assertIn('Checking build ...', stderr.getvalue())
-        self.assertIn('Build check failed', stderr.getvalue())
-
     def test_verbose_in_child_processes(self):
         # When we actually run multiple processes, we may have to reconfigure logging in the
         # child process (e.g., on win32) and we need to make sure that works and we still
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
index abad796..77e6a2a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
@@ -43,7 +43,8 @@
         self.assertEqual(checker._handle_style_error,
                          _mock_handle_style_error)
 
-    def test_check(self):
+    # TODO(crbug.com/757067): Figure out why this is failing on LUCI mac/win.
+    def disable_test_check(self):
         """Test check() method."""
         errors = []
 
diff --git a/third_party/WebKit/public/blink_typemaps.gni b/third_party/WebKit/public/blink_typemaps.gni
index b9f7ec7..f5e470e 100644
--- a/third_party/WebKit/public/blink_typemaps.gni
+++ b/third_party/WebKit/public/blink_typemaps.gni
@@ -3,12 +3,12 @@
 # found in the LICENSE file.
 
 typemaps = [
-  "//cc/ipc/frame_sink_id.typemap",
   "//cc/ipc/local_surface_id.typemap",
   "//gpu/ipc/common/mailbox_holder_for_blink.typemap",
   "//gpu/ipc/common/sync_token.typemap",
   "//services/viz/public/cpp/compositing/begin_frame_args_for_blink.typemap",
   "//services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap",
+  "//services/viz/public/cpp/compositing/frame_sink_id.typemap",
   "//services/viz/public/cpp/compositing/returned_resource.typemap",
   "//services/viz/public/cpp/compositing/surface_id.typemap",
   "//services/viz/public/cpp/compositing/surface_info.typemap",
diff --git a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
index d3473b1..68f944ee 100644
--- a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
+++ b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
@@ -4,8 +4,8 @@
 
 module blink.mojom;
 
-import "cc/ipc/frame_sink_id.mojom";
 import "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom";
+import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_info.mojom";
 import "services/viz/public/interfaces/compositing/surface_sequence.mojom";
@@ -24,14 +24,14 @@
 interface OffscreenCanvasProvider {
   // Create an OffscreenCanvasSurface for |frame_sink_id|. |client| will observe
   // any changes to the SurfaceId associated with |frame_sink_id|.
-  CreateOffscreenCanvasSurface(cc.mojom.FrameSinkId parent_frame_sink_id,
-                               cc.mojom.FrameSinkId frame_sink_id,
+  CreateOffscreenCanvasSurface(viz.mojom.FrameSinkId parent_frame_sink_id,
+                               viz.mojom.FrameSinkId frame_sink_id,
                                OffscreenCanvasSurfaceClient client,
                                OffscreenCanvasSurface& surface);
 
   // Create an CompositorFrameSink for |frame_sink_id|. This must happen
   // after creating an OffsreenCanvasSurface for |frame_sink_id|.
-  CreateCompositorFrameSink(cc.mojom.FrameSinkId frame_sink_id,
+  CreateCompositorFrameSink(viz.mojom.FrameSinkId frame_sink_id,
                             viz.mojom.CompositorFrameSinkClient client,
                             viz.mojom.CompositorFrameSink& sink);
 };
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index 25b6f14a..c1e94647 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1678,6 +1678,7 @@
   kWebkitBoxLineClampManyChildren = 2143,
   kWebkitBoxLineClampDoesSomething = 2144,
   kFeaturePolicyAllowAttributeDeprecatedSyntax = 2145,
+  kSuppressHistoryEntryWithoutUserGesture = 2146,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/public/web/WebAXEnums.h b/third_party/WebKit/public/web/WebAXEnums.h
index 1ee2a9c9..43fa537 100644
--- a/third_party/WebKit/public/web/WebAXEnums.h
+++ b/third_party/WebKit/public/web/WebAXEnums.h
@@ -199,6 +199,13 @@
   kActivate,
   kCheck,
   kClick,
+
+  // A click will be performed on one of the object's ancestors.
+  // This happens when the object itself is not clickable, but one of its
+  // ancestors has click handlers attached which are able to capture the click
+  // as it bubbles up.
+  kClickAncestor,
+
   kJump,
   kOpen,
   kPress,
diff --git a/third_party/blink/tools/plan_blink_move.py b/third_party/blink/tools/plan_blink_move.py
new file mode 100755
index 0000000..d8a1aff
--- /dev/null
+++ b/third_party/blink/tools/plan_blink_move.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env vpython
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import re
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..',
+                             'third_party', 'WebKit', 'Tools', 'Scripts'))
+from blinkpy.common.name_style_converter import NameStyleConverter
+from webkitpy.common.system.filesystem import FileSystem
+
+
+def relative_dest(fs, filename):
+    """Returns a destination path string for given filename.
+
+    |filename| is a path relative to third_party/WebKit, and the resultant path
+    is relative to third_party/blink.
+    """
+    dest = None
+    if filename.startswith('public'):
+        dest = re.sub(r'^public', 'renderer' + fs.sep + 'public', filename)
+    elif filename.startswith('Source'):
+        dest = re.sub(r'^Source', 'renderer', filename)
+    elif filename.startswith('common'):
+        dest = filename
+    else:
+        raise ValueError('|filename| must start with "common", "public", or "Source": %s' % filename)
+    if filename.endswith('.h') or filename.endswith('.cpp') or \
+       filename.endswith('.mm') or filename.endswith('.idl'):
+        dirname, basename = fs.split(dest)
+        basename, ext = fs.splitext(basename)
+        if filename.endswith('.cpp'):
+            ext = '.cc'
+        if basename.lower() != basename:
+            basename = NameStyleConverter(basename).to_snake_case()
+        return fs.join(dirname, basename + ext)
+    return dest
+
+
+def start_with_list(name, prefixes):
+    if len(prefixes) == 0:
+        return True
+    for prefix in prefixes:
+        if name.startswith(prefix):
+            return True
+    return False
+
+
+def plan_blink_move(fs, prefixes):
+    """Returns (source, dest) path pairs.
+
+    The source paths are relative to third_party/WebKit,
+    and the dest paths are relative to third_party/blink.
+    The paths use os.sep as the path part separator.
+    """
+    blink_dir = fs.join(fs.dirname(__file__), '..')
+    webkit_dir = fs.join(blink_dir, '..', '..', 'third_party', 'WebKit')
+    source_files = fs.files_under(fs.join(webkit_dir, 'Source'))
+    source_files += fs.files_under(fs.join(webkit_dir, 'common'))
+    source_files += fs.files_under(fs.join(webkit_dir, 'public'))
+
+    # It's possible to check git.exists() here, but we don't do it due to slow
+    # performance. We should check it just before executing git command.
+
+    source_files = [f[len(webkit_dir) + 1:] for f in source_files]
+    return [(f, relative_dest(fs, f)) for f in source_files
+            if f.find('node_modules') == -1 and start_with_list(f, prefixes)]
+
+
+def main():
+    fs = FileSystem()
+    file_pairs = plan_blink_move(fs, sys.argv[1:])
+    print 'Show renaming plan. It contains files not in the repository.'
+    print '<Source path relative to third_party/WebKit> => <Destination path relative to third_party/blink>'
+    for pair in file_pairs:
+        print '%s\t=>\t%s' % pair
+
+
+if __name__ == '__main__':
+    main()
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index c307119..21ff744 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 01110c0a3b3536f344224728ac524b30599fecc5
+Revision: 20ed4146d37705a12a5b603a89c97f206f58d14c
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index f4136874..fdcec72c5 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -38,7 +38,7 @@
 
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
-      'ee67585e3115982282b86e210939ead1791e696d',
+      '068fe690218f03a02c1cd34c9a0eb4bf3c814a6a',
   'crashpad/third_party/zlib/zlib':
       Var('chromium_git') + '/chromium/src/third_party/zlib@' +
       '13dc246a58e4b72104d35f9b1809af95221ebda7',
diff --git a/third_party/crashpad/crashpad/build/gyp_crashpad_android.py b/third_party/crashpad/crashpad/build/gyp_crashpad_android.py
index a6ad1b4..4461425 100755
--- a/third_party/crashpad/crashpad/build/gyp_crashpad_android.py
+++ b/third_party/crashpad/crashpad/build/gyp_crashpad_android.py
@@ -46,8 +46,8 @@
   ARCH_TRIPLET_TO_ARCH = {
     'arm-linux-androideabi': 'arm',
     'aarch64-linux-android': 'arm64',
-    'i686-linux-android': 'x86',
-    'x86_64-linux-android': 'x86_64',
+    'i686-linux-android': 'ia32',
+    'x86_64-linux-android': 'x64',
     'mipsel-linux-android': 'mips',
     'mips64el-linux-android': 'mips64',
   }
diff --git a/third_party/crashpad/crashpad/client/simple_string_dictionary.h b/third_party/crashpad/crashpad/client/simple_string_dictionary.h
index ea142fcd..17c04e1 100644
--- a/third_party/crashpad/crashpad/client/simple_string_dictionary.h
+++ b/third_party/crashpad/crashpad/client/simple_string_dictionary.h
@@ -18,8 +18,11 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/strings/string_piece.h"
 #include "util/misc/implicit_cast.h"
 
 namespace crashpad {
@@ -51,10 +54,13 @@
   struct Entry {
     //! \brief The entry’s key.
     //!
-    //! If this is a 0-length `NUL`-terminated string, the entry is inactive.
+    //! This string is always `NUL`-terminated. If this is a 0-length
+    //! `NUL`-terminated string, the entry is inactive.
     char key[KeySize];
 
     //! \brief The entry’s value.
+    //!
+    //! This string is always `NUL`-terminated.
     char value[ValueSize];
 
     //! \brief Returns the validity of the entry.
@@ -121,13 +127,16 @@
 
   //! \brief Given \a key, returns its corresponding value.
   //!
-  //! \param[in] key The key to look up. This must not be `nullptr`.
+  //! \param[in] key The key to look up. This must not be `nullptr`, nor an
+  //!     empty string. It must not contain embedded `NUL`s.
   //!
   //! \return The corresponding value for \a key, or if \a key is not found,
   //!     `nullptr`.
-  const char* GetValueForKey(const char* key) const {
-    DCHECK(key);
-    if (!key) {
+  const char* GetValueForKey(base::StringPiece key) const {
+    DCHECK(key.data());
+    DCHECK(key.size());
+    DCHECK_EQ(key.find('\0', 0), base::StringPiece::npos);
+    if (!key.data() || !key.size()) {
       return nullptr;
     }
 
@@ -145,17 +154,20 @@
   //! If \a key is not yet in the map and the map is already full (containing
   //! \a NumEntries active entries), this operation silently fails.
   //!
-  //! \param[in] key The key to store. This must not be `nullptr`.
+  //! \param[in] key The key to store. This must not be `nullptr`, nor an empty
+  //!     string. It must not contain embedded `NUL`s.
   //! \param[in] value The value to store. If `nullptr`, \a key is removed from
-  //!     the map.
-  void SetKeyValue(const char* key, const char* value) {
-    if (!value) {
+  //!     the map. Must not contain embedded `NUL`s.
+  void SetKeyValue(base::StringPiece key, base::StringPiece value) {
+    if (!value.data()) {
       RemoveKey(key);
       return;
     }
 
-    DCHECK(key);
-    if (!key) {
+    DCHECK(key.data());
+    DCHECK(key.size());
+    DCHECK_EQ(key.find('\0', 0), base::StringPiece::npos);
+    if (!key.data() || !key.size()) {
       return;
     }
 
@@ -165,6 +177,9 @@
       return;
     }
 
+    // |value| must not contain embedded NULs.
+    DCHECK_EQ(value.find('\0', 0), base::StringPiece::npos);
+
     Entry* entry = GetEntryForKey(key);
 
     // If it does not yet exist, attempt to insert it.
@@ -172,10 +187,7 @@
       for (size_t i = 0; i < num_entries; ++i) {
         if (!entries_[i].is_active()) {
           entry = &entries_[i];
-
-          strncpy(entry->key, key, key_size);
-          entry->key[key_size - 1] = '\0';
-
+          SetFromStringPiece(key, entry->key, key_size);
           break;
         }
       }
@@ -190,25 +202,27 @@
     // Sanity check that the key only appears once.
     int count = 0;
     for (size_t i = 0; i < num_entries; ++i) {
-      if (strncmp(entries_[i].key, key, key_size) == 0) {
+      if (EntryKeyEquals(key, entries_[i])) {
         ++count;
       }
     }
     DCHECK_EQ(count, 1);
 #endif
 
-    strncpy(entry->value, value, value_size);
-    entry->value[value_size - 1] = '\0';
+    SetFromStringPiece(value, entry->value, value_size);
   }
 
   //! \brief Removes \a key from the map.
   //!
   //! If \a key is not found, this is a no-op.
   //!
-  //! \param[in] key The key of the entry to remove. This must not be `nullptr`.
-  void RemoveKey(const char* key) {
-    DCHECK(key);
-    if (!key) {
+  //! \param[in] key The key of the entry to remove. This must not be `nullptr`,
+  //!     nor an empty string. It must not contain embedded `NUL`s.
+  void RemoveKey(base::StringPiece key) {
+    DCHECK(key.data());
+    DCHECK(key.size());
+    DCHECK_EQ(key.find('\0', 0), base::StringPiece::npos);
+    if (!key.data() || !key.size()) {
       return;
     }
 
@@ -222,16 +236,37 @@
   }
 
  private:
-  const Entry* GetConstEntryForKey(const char* key) const {
+  static void SetFromStringPiece(base::StringPiece src,
+                                 char* dst,
+                                 size_t dst_size) {
+    size_t copy_len = std::min(dst_size - 1, src.size());
+    src.copy(dst, copy_len);
+    dst[copy_len] = '\0';
+  }
+
+  static bool EntryKeyEquals(base::StringPiece key, const Entry& entry) {
+    if (key.size() >= KeySize)
+      return false;
+
+    // Test for a NUL terminator and early out if it's absent.
+    if (entry.key[key.size()] != '\0')
+      return false;
+
+    // As there's a NUL terminator at the right position in the entries
+    // string, strncmp can do the rest.
+    return strncmp(key.data(), entry.key, key.size()) == 0;
+  }
+
+  const Entry* GetConstEntryForKey(base::StringPiece key) const {
     for (size_t i = 0; i < num_entries; ++i) {
-      if (strncmp(key, entries_[i].key, key_size) == 0) {
+      if (EntryKeyEquals(key, entries_[i])) {
         return &entries_[i];
       }
     }
     return nullptr;
   }
 
-  Entry* GetEntryForKey(const char* key) {
+  Entry* GetEntryForKey(base::StringPiece key) {
     return const_cast<Entry*>(GetConstEntryForKey(key));
   }
 
diff --git a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
new file mode 100644
index 0000000..f3ed99b
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
@@ -0,0 +1,397 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/linux/system_snapshot_linux.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+
+#include <algorithm>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "snapshot/cpu_context.h"
+#include "snapshot/posix/timezone.h"
+#include "util/file/file_io.h"
+#include "util/numeric/in_range_cast.h"
+#include "util/string/split_string.h"
+
+#if defined(OS_ANDROID)
+#include <sys/system_properties.h>
+#endif
+
+namespace crashpad {
+namespace internal {
+
+namespace {
+
+bool ReadCPUsOnline(uint32_t* first_cpu, uint8_t* cpu_count) {
+  std::string contents;
+  if (!LoggingReadEntireFile(base::FilePath("/sys/devices/system/cpu/online"),
+                             &contents)) {
+    return false;
+  }
+  if (contents.back() != '\n') {
+    LOG(ERROR) << "format error";
+    return false;
+  }
+  contents.pop_back();
+
+  unsigned int count = 0;
+  unsigned int first = 0;
+  bool have_first = false;
+  std::vector<std::string> ranges = SplitString(contents, ',');
+  for (const auto& range : ranges) {
+    std::string left, right;
+    if (SplitStringFirst(range, '-', &left, &right)) {
+      unsigned int start, end;
+      if (!StringToUint(base::StringPiece(left), &start) ||
+          !StringToUint(base::StringPiece(right), &end) || end <= start) {
+        LOG(ERROR) << "format error: " << range;
+        return false;
+      }
+      if (end <= start) {
+        LOG(ERROR) << "format error";
+        return false;
+      }
+      count += end - start + 1;
+      if (!have_first) {
+        first = start;
+        have_first = true;
+      }
+    } else {
+      unsigned int cpuno;
+      if (!StringToUint(base::StringPiece(range), &cpuno)) {
+        LOG(ERROR) << "format error";
+        return false;
+      }
+      if (!have_first) {
+        first = cpuno;
+        have_first = true;
+      }
+      ++count;
+    }
+  }
+  if (!have_first) {
+    LOG(ERROR) << "no cpus online";
+    return false;
+  }
+  *cpu_count = InRangeCast<uint8_t>(count, std::numeric_limits<uint8_t>::max());
+  *first_cpu = first;
+  return true;
+}
+
+bool ReadFreqFile(const std::string& filename, uint64_t* hz) {
+  std::string contents;
+  if (!LoggingReadEntireFile(base::FilePath(filename), &contents)) {
+    return false;
+  }
+  if (contents.back() != '\n') {
+    LOG(ERROR) << "format error";
+    return false;
+  }
+  contents.pop_back();
+
+  uint64_t khz;
+  if (!base::StringToUint64(base::StringPiece(contents), &khz)) {
+    LOG(ERROR) << "format error";
+    return false;
+  }
+
+  *hz = khz * 1000;
+  return true;
+}
+
+#if defined(OS_ANDROID)
+bool ReadProperty(const char* property, std::string* value) {
+  char value_buffer[PROP_VALUE_MAX];
+  int length = __system_property_get(property, value_buffer);
+  if (length <= 0) {
+    LOG(ERROR) << "Couldn't read property " << property;
+    return false;
+  }
+  *value = value_buffer;
+  return true;
+}
+#endif  // OS_ANDROID
+
+}  // namespace
+
+SystemSnapshotLinux::SystemSnapshotLinux()
+    : SystemSnapshot(),
+      os_version_full_(),
+      os_version_build_(),
+      process_reader_(nullptr),
+      snapshot_time_(nullptr),
+#if defined(ARCH_CPU_X86_FAMILY)
+      cpuid_(),
+#endif  // ARCH_CPU_X86_FAMILY
+      os_version_major_(-1),
+      os_version_minor_(-1),
+      os_version_bugfix_(-1),
+      target_cpu_(0),
+      cpu_count_(0),
+      initialized_() {
+}
+
+SystemSnapshotLinux::~SystemSnapshotLinux() {}
+
+void SystemSnapshotLinux::Initialize(ProcessReader* process_reader,
+                                     const timeval* snapshot_time) {
+  INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+  process_reader_ = process_reader;
+  snapshot_time_ = snapshot_time;
+
+#if defined(OS_ANDROID)
+  std::string build_string;
+  if (ReadProperty("ro.build.fingerprint", &build_string)) {
+    os_version_build_ = build_string;
+    os_version_full_ = build_string;
+  }
+#endif  // OS_ANDROID
+
+  utsname uts;
+  if (uname(&uts) != 0) {
+    PLOG(WARNING) << "uname";
+  } else {
+    if (!os_version_full_.empty()) {
+      os_version_full_.push_back(' ');
+    }
+    os_version_full_ += base::StringPrintf(
+        "%s %s %s %s", uts.sysname, uts.release, uts.version, uts.machine);
+  }
+  ReadKernelVersion(uts.release);
+
+  if (!os_version_build_.empty()) {
+    os_version_build_.push_back(' ');
+  }
+  os_version_build_ += uts.version;
+  os_version_build_.push_back(' ');
+  os_version_build_ += uts.machine;
+
+  if (!ReadCPUsOnline(&target_cpu_, &cpu_count_)) {
+    target_cpu_ = 0;
+    cpu_count_ = 0;
+  }
+
+  INITIALIZATION_STATE_SET_VALID(initialized_);
+}
+
+CPUArchitecture SystemSnapshotLinux::GetCPUArchitecture() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
+  return process_reader_->Is64Bit() ? kCPUArchitectureX86_64
+                                    : kCPUArchitectureX86;
+#else
+#error port to your architecture
+#endif
+}
+
+uint32_t SystemSnapshotLinux::CPURevision() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
+  return cpuid_.Revision();
+#else
+#error port to your architecture
+#endif
+}
+
+uint8_t SystemSnapshotLinux::CPUCount() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  return cpu_count_;
+}
+
+std::string SystemSnapshotLinux::CPUVendor() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
+  return cpuid_.Vendor();
+#else
+#error port to your architecture
+#endif
+}
+
+void SystemSnapshotLinux::CPUFrequency(uint64_t* current_hz,
+                                       uint64_t* max_hz) const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  *current_hz = 0;
+  *max_hz = 0;
+
+  ReadFreqFile(base::StringPrintf(
+                   "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq",
+                   target_cpu_),
+               current_hz);
+
+  ReadFreqFile(base::StringPrintf(
+                   "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq",
+                   target_cpu_),
+               max_hz);
+}
+
+uint32_t SystemSnapshotLinux::CPUX86Signature() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
+  return cpuid_.Signature();
+#else
+  NOTREACHED();
+  return 0;
+#endif
+}
+
+uint64_t SystemSnapshotLinux::CPUX86Features() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
+  return cpuid_.Features();
+#else
+  NOTREACHED();
+  return 0;
+#endif
+}
+
+uint64_t SystemSnapshotLinux::CPUX86ExtendedFeatures() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  return cpuid_.ExtendedFeatures();
+}
+
+uint32_t SystemSnapshotLinux::CPUX86Leaf7Features() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
+  return cpuid_.Leaf7Features();
+#else
+  NOTREACHED();
+  return 0;
+#endif
+}
+
+bool SystemSnapshotLinux::CPUX86SupportsDAZ() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
+  return cpuid_.SupportsDAZ();
+#else
+  NOTREACHED();
+  return false;
+#endif  // ARCH_CPU_X86_FMAILY
+}
+
+SystemSnapshot::OperatingSystem SystemSnapshotLinux::GetOperatingSystem()
+    const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(OS_ANDROID)
+  return kOperatingSystemAndroid;
+#else
+  return kOperatingSystemLinux;
+#endif  // OS_ANDROID
+}
+
+bool SystemSnapshotLinux::OSServer() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  return false;
+}
+
+void SystemSnapshotLinux::OSVersion(int* major,
+                                    int* minor,
+                                    int* bugfix,
+                                    std::string* build) const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  *major = os_version_major_;
+  *minor = os_version_minor_;
+  *bugfix = os_version_bugfix_;
+  build->assign(os_version_build_);
+}
+
+std::string SystemSnapshotLinux::OSVersionFull() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  return os_version_full_;
+}
+
+std::string SystemSnapshotLinux::MachineDescription() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(OS_ANDROID)
+  std::string description;
+  std::string prop;
+  if (ReadProperty("ro.product.model", &prop)) {
+    description += prop;
+  }
+  if (ReadProperty("ro.product.board", &prop)) {
+    if (!description.empty()) {
+      description.push_back(' ');
+    }
+    description += prop;
+  }
+  return description;
+#else
+  return std::string();
+#endif  // OS_ANDROID
+}
+
+bool SystemSnapshotLinux::NXEnabled() const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  return cpuid_.NXEnabled();
+}
+
+void SystemSnapshotLinux::TimeZone(DaylightSavingTimeStatus* dst_status,
+                                   int* standard_offset_seconds,
+                                   int* daylight_offset_seconds,
+                                   std::string* standard_name,
+                                   std::string* daylight_name) const {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  internal::TimeZone(*snapshot_time_,
+                     dst_status,
+                     standard_offset_seconds,
+                     daylight_offset_seconds,
+                     standard_name,
+                     daylight_name);
+}
+
+void SystemSnapshotLinux::ReadKernelVersion(const std::string& version_string) {
+  std::vector<std::string> versions = SplitString(version_string, '.');
+  if (versions.size() < 3) {
+    LOG(WARNING) << "format error";
+    return;
+  }
+
+  if (!StringToInt(base::StringPiece(versions[0]), &os_version_major_)) {
+    LOG(WARNING) << "no kernel version";
+    return;
+  }
+  DCHECK_GE(os_version_major_, 3);
+
+  if (!StringToInt(base::StringPiece(versions[1]), &os_version_minor_)) {
+    LOG(WARNING) << "no major revision";
+    return;
+  }
+  DCHECK_GE(os_version_minor_, 0);
+
+  size_t minor_rev_end = versions[2].find_first_not_of("0123456789");
+  if (minor_rev_end == std::string::npos) {
+    minor_rev_end = versions[2].size();
+  }
+  if (!StringToInt(base::StringPiece(versions[2].c_str(), minor_rev_end),
+                   &os_version_bugfix_)) {
+    LOG(WARNING) << "no minor revision";
+    return;
+  }
+  DCHECK_GE(os_version_bugfix_, 0);
+
+  if (!os_version_build_.empty()) {
+    os_version_build_.push_back(' ');
+  }
+  os_version_build_ += versions[2].substr(minor_rev_end);
+}
+
+}  // namespace internal
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.h b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.h
new file mode 100644
index 0000000..a991450
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.h
@@ -0,0 +1,112 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_SNAPSHOT_LINUX_SYSTEM_SNAPSHOT_LINUX_H_
+#define CRASHPAD_SNAPSHOT_LINUX_SYSTEM_SNAPSHOT_LINUX_H_
+
+#include <stdint.h>
+#include <time.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "snapshot/linux/process_reader.h"
+#include "snapshot/system_snapshot.h"
+#include "util/misc/initialization_state_dcheck.h"
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#include "snapshot/x86/cpuid_reader.h"
+#endif  // ARCH_CPU_X86_FAMILY
+
+namespace crashpad {
+namespace internal {
+
+//! \brief A SystemSnapshot of the running system, when the system runs Linux.
+class SystemSnapshotLinux final : public SystemSnapshot {
+ public:
+  SystemSnapshotLinux();
+  ~SystemSnapshotLinux() override;
+
+  //! \brief Initializes the object.
+  //!
+  //! \param[in] process_reader A reader for the process being snapshotted.
+  //!     \n\n
+  //!     It seems odd that a system snapshot implementation would need a
+  //!     ProcessReader, but some of the information reported about the system
+  //!     depends on the process it’s being reported for. For example, the
+  //!     architecture returned by GetCPUArchitecture() should be the
+  //!     architecture of the process, which may be different than the native
+  //!     architecture of the system: an x86_64 system can run both x86_64 and
+  //!     32-bit x86 processes.
+  //! \param[in] snapshot_time The time of the snapshot being taken.
+  //!     \n\n
+  //!     This parameter is necessary for TimeZone() to determine whether
+  //!     daylight saving time was in effect at the time the snapshot was taken.
+  //!     Otherwise, it would need to base its determination on the current
+  //!     time, which may be different than the snapshot time for snapshots
+  //!     generated around the daylight saving transition time.
+  void Initialize(ProcessReader* process_reader, const timeval* snapshot_time);
+
+  // SystemSnapshot:
+
+  CPUArchitecture GetCPUArchitecture() const override;
+  uint32_t CPURevision() const override;
+  uint8_t CPUCount() const override;
+  std::string CPUVendor() const override;
+  void CPUFrequency(uint64_t* current_hz, uint64_t* max_hz) const override;
+  uint32_t CPUX86Signature() const override;
+  uint64_t CPUX86Features() const override;
+  uint64_t CPUX86ExtendedFeatures() const override;
+  uint32_t CPUX86Leaf7Features() const override;
+  bool CPUX86SupportsDAZ() const override;
+  OperatingSystem GetOperatingSystem() const override;
+  bool OSServer() const override;
+  void OSVersion(int* major,
+                 int* minor,
+                 int* bugfix,
+                 std::string* build) const override;
+  std::string OSVersionFull() const override;
+  bool NXEnabled() const override;
+  std::string MachineDescription() const override;
+  void TimeZone(DaylightSavingTimeStatus* dst_status,
+                int* standard_offset_seconds,
+                int* daylight_offset_seconds,
+                std::string* standard_name,
+                std::string* daylight_name) const override;
+
+ private:
+  void ReadKernelVersion(const std::string& version_string);
+
+  std::string os_version_full_;
+  std::string os_version_build_;
+  ProcessReader* process_reader_;  // weak
+  const timeval* snapshot_time_;  // weak
+#if defined(ARCH_CPU_X86_FAMILY)
+  CpuidReader cpuid_;
+#endif  // ARCH_CPU_X86_FAMILY
+  int os_version_major_;
+  int os_version_minor_;
+  int os_version_bugfix_;
+  uint32_t target_cpu_;
+  uint8_t cpu_count_;
+  InitializationStateDcheck initialized_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemSnapshotLinux);
+};
+
+}  // namespace internal
+}  // namespace crashpad
+
+#endif  // CRASHPAD_SNAPSHOT_LINUX_SYSTEM_SNAPSHOT_LINUX_H_
diff --git a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux_test.cc
new file mode 100644
index 0000000..f55036e
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux_test.cc
@@ -0,0 +1,85 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/linux/system_snapshot_linux.h"
+
+#include <sys/time.h>
+
+#include <string>
+
+#include "build/build_config.h"
+#include "gtest/gtest.h"
+#include "snapshot/linux/process_reader.h"
+#include "test/errors.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+TEST(SystemSnapshotLinux, Basic) {
+  ProcessReader process_reader;
+  ASSERT_TRUE(process_reader.Initialize(getpid()));
+
+  timeval snapshot_time;
+  ASSERT_EQ(gettimeofday(&snapshot_time, nullptr), 0)
+      << ErrnoMessage("gettimeofday");
+
+  internal::SystemSnapshotLinux system;
+  system.Initialize(&process_reader, &snapshot_time);
+
+  EXPECT_GT(system.CPUCount(), 0u);
+
+  uint64_t current_hz, max_hz;
+  system.CPUFrequency(&current_hz, &max_hz);
+  EXPECT_GE(max_hz, current_hz);
+
+  int major, minor, bugfix;
+  std::string build;
+  system.OSVersion(&major, &minor, &bugfix, &build);
+  EXPECT_GE(major, 3);
+  EXPECT_GE(minor, 0);
+  EXPECT_GE(bugfix, 0);
+  EXPECT_FALSE(build.empty());
+
+  EXPECT_FALSE(system.OSVersionFull().empty());
+
+  // No expectations; just make sure these can be called successfully.
+  system.CPURevision();
+  system.NXEnabled();
+
+#if defined(OS_ANDROID)
+  EXPECT_FALSE(system.MachineDescription().empty());
+#else
+  system.MachineDescription();
+#endif  // OS_ANDROID
+
+#if defined(ARCH_CPU_X86_FAMILY)
+  system.CPUX86Signature();
+  system.CPUX86Features();
+  system.CPUX86ExtendedFeatures();
+  system.CPUX86Leaf7Features();
+
+  EXPECT_PRED1(
+      [](std::string vendor) {
+        return vendor == "GenuineIntel" || vendor == "AuthenticAMD";
+      },
+      system.CPUVendor());
+
+  EXPECT_TRUE(system.CPUX86SupportsDAZ());
+#endif  // ARCH_CPU_X86_FAMILY
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
index 2bafb274..140e7f4 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
@@ -18,7 +18,6 @@
 #include <sys/sysctl.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
-#include <time.h>
 
 #include <algorithm>
 
@@ -27,6 +26,7 @@
 #include "build/build_config.h"
 #include "snapshot/cpu_context.h"
 #include "snapshot/mac/process_reader.h"
+#include "snapshot/posix/timezone.h"
 #include "util/mac/mac_util.h"
 #include "util/numeric/in_range_cast.h"
 
@@ -348,64 +348,12 @@
                                  std::string* daylight_name) const {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
-  tm local;
-  PCHECK(localtime_r(&snapshot_time_->tv_sec, &local)) << "localtime_r";
-
-  *standard_name = tzname[0];
-
-  bool found_transition = false;
-  long probe_gmtoff = local.tm_gmtoff;
-  if (daylight) {
-    // Scan forward and backward, one month at a time, looking for an instance
-    // when the observance of daylight saving time is different than it is in
-    // |local|. It’s possible that no such instance will be found even with
-    // |daylight| set. This can happen in locations where daylight saving time
-    // was once observed or is expected to be observed in the future, but where
-    // no transitions to or from daylight saving time occurred or will occur
-    // within a year of the current date. Arizona, which last observed daylight
-    // saving time in 1967, is an example.
-    static constexpr int kMonthDeltas[] =
-        {0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6,
-         7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12};
-    for (size_t index = 0;
-         index < arraysize(kMonthDeltas) && !found_transition;
-         ++index) {
-      // Look at a day of each month at local noon. Set tm_isdst to -1 to avoid
-      // giving mktime() any hints about whether to consider daylight saving
-      // time in effect. mktime() accepts values of tm_mon that are outside of
-      // its normal range and behaves as expected: if tm_mon is -1, it
-      // references December of the preceding year, and if it is 12, it
-      // references January of the following year.
-      tm probe_tm = {};
-      probe_tm.tm_hour = 12;
-      probe_tm.tm_mday = std::min(local.tm_mday, 28);
-      probe_tm.tm_mon = local.tm_mon + kMonthDeltas[index];
-      probe_tm.tm_year = local.tm_year;
-      probe_tm.tm_isdst = -1;
-      if (mktime(&probe_tm) != -1 && probe_tm.tm_isdst != local.tm_isdst) {
-        found_transition = true;
-        probe_gmtoff = probe_tm.tm_gmtoff;
-      }
-    }
-  }
-
-  if (found_transition) {
-    *daylight_name = tzname[1];
-    if (!local.tm_isdst) {
-      *dst_status = kObservingStandardTime;
-      *standard_offset_seconds = local.tm_gmtoff;
-      *daylight_offset_seconds = probe_gmtoff;
-    } else {
-      *dst_status = kObservingDaylightSavingTime;
-      *standard_offset_seconds = probe_gmtoff;
-      *daylight_offset_seconds = local.tm_gmtoff;
-    }
-  } else {
-    *daylight_name = tzname[0];
-    *dst_status = kDoesNotObserveDaylightSavingTime;
-    *standard_offset_seconds = local.tm_gmtoff;
-    *daylight_offset_seconds = local.tm_gmtoff;
-  }
+  internal::TimeZone(*snapshot_time_,
+                     dst_status,
+                     standard_offset_seconds,
+                     daylight_offset_seconds,
+                     standard_name,
+                     daylight_name);
 }
 
 }  // namespace internal
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
index fb4166f..646021b 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
@@ -14,13 +14,10 @@
 
 #include "snapshot/mac/system_snapshot_mac.h"
 
-#include <stdlib.h>
 #include <sys/time.h>
-#include <time.h>
 
 #include <string>
 
-#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/mac/process_reader.h"
@@ -129,152 +126,6 @@
   EXPECT_FALSE(system_snapshot().MachineDescription().empty());
 }
 
-class ScopedSetTZ {
- public:
-  ScopedSetTZ(const std::string& tz) {
-    const char* old_tz = getenv(kTZ);
-    old_tz_set_ = old_tz;
-    if (old_tz_set_) {
-      old_tz_.assign(old_tz);
-    }
-
-    EXPECT_EQ(setenv(kTZ, tz.c_str(), 1), 0) << ErrnoMessage("setenv");
-    tzset();
-  }
-
-  ~ScopedSetTZ() {
-    if (old_tz_set_) {
-      EXPECT_EQ(setenv(kTZ, old_tz_.c_str(), 1), 0) << ErrnoMessage("setenv");
-    } else {
-      EXPECT_EQ(unsetenv(kTZ), 0) << ErrnoMessage("unsetenv");
-    }
-    tzset();
-  }
-
- private:
-  std::string old_tz_;
-  bool old_tz_set_;
-
-  static constexpr char kTZ[] = "TZ";
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedSetTZ);
-};
-
-constexpr char ScopedSetTZ::kTZ[];
-
-TEST_F(SystemSnapshotMacTest, TimeZone) {
-  SystemSnapshot::DaylightSavingTimeStatus dst_status;
-  int standard_offset_seconds;
-  int daylight_offset_seconds;
-  std::string standard_name;
-  std::string daylight_name;
-
-  system_snapshot().TimeZone(&dst_status,
-                             &standard_offset_seconds,
-                             &daylight_offset_seconds,
-                             &standard_name,
-                             &daylight_name);
-
-  // |standard_offset_seconds| gives seconds east of UTC, and |timezone| gives
-  // seconds west of UTC.
-  EXPECT_EQ(standard_offset_seconds, -timezone);
-
-  // In contemporary usage, most time zones have an integer hour offset from
-  // UTC, although several are at a half-hour offset, and two are at 15-minute
-  // offsets. Throughout history, other variations existed. See
-  // http://www.timeanddate.com/time/time-zones-interesting.html.
-  EXPECT_EQ(standard_offset_seconds % (15 * 60), 0)
-      << "standard_offset_seconds " << standard_offset_seconds;
-
-  if (dst_status == SystemSnapshot::kDoesNotObserveDaylightSavingTime) {
-    EXPECT_EQ(daylight_offset_seconds, standard_offset_seconds);
-    EXPECT_EQ(daylight_name, standard_name);
-  } else {
-    EXPECT_EQ(daylight_offset_seconds % (15 * 60), 0)
-        << "daylight_offset_seconds " << daylight_offset_seconds;
-
-    // In contemporary usage, dst_delta_seconds will almost always be one hour,
-    // except for Lord Howe Island, Australia, which uses a 30-minute
-    // delta. Throughout history, other variations existed. See
-    // http://www.timeanddate.com/time/dst/#brief.
-    int dst_delta_seconds = daylight_offset_seconds - standard_offset_seconds;
-    if (dst_delta_seconds != 60 * 60 && dst_delta_seconds != 30 * 60) {
-      FAIL() << "dst_delta_seconds " << dst_delta_seconds;
-    }
-
-    EXPECT_NE(standard_name, daylight_name);
-  }
-
-  // Test a variety of time zones. Some of these observe daylight saving time,
-  // some don’t. Some used to but no longer do. Some have uncommon UTC offsets.
-  // standard_name and daylight_name can be nullptr where no name exists to
-  // verify, as may happen when some versions of the timezone database carry
-  // invented names and others do not.
-  static constexpr struct {
-    const char* tz;
-    bool observes_dst;
-    float standard_offset_hours;
-    float daylight_offset_hours;
-    const char* standard_name;
-    const char* daylight_name;
-  } kTestTimeZones[] = {
-      {"America/Anchorage", true, -9, -8, "AKST", "AKDT"},
-      {"America/Chicago", true, -6, -5, "CST", "CDT"},
-      {"America/Denver", true, -7, -6, "MST", "MDT"},
-      {"America/Halifax", true, -4, -3, "AST", "ADT"},
-      {"America/Los_Angeles", true, -8, -7, "PST", "PDT"},
-      {"America/New_York", true, -5, -4, "EST", "EDT"},
-      {"America/Phoenix", false, -7, -7, "MST", "MST"},
-      {"Asia/Karachi", false, 5, 5, "PKT", "PKT"},
-      {"Asia/Kolkata", false, 5.5, 5.5, "IST", "IST"},
-      {"Asia/Shanghai", false, 8, 8, "CST", "CST"},
-      {"Asia/Tokyo", false, 9, 9, "JST", "JST"},
-      {"Australia/Adelaide", true, 9.5, 10.5, "ACST", "ACDT"},
-      {"Australia/Brisbane", false, 10, 10, "AEST", "AEST"},
-      {"Australia/Darwin", false, 9.5, 9.5, "ACST", "ACST"},
-      {"Australia/Eucla", false, 8.75, 8.75, nullptr, nullptr},
-      {"Australia/Lord_Howe", true, 10.5, 11, nullptr, nullptr},
-      {"Australia/Perth", false, 8, 8, "AWST", "AWST"},
-      {"Australia/Sydney", true, 10, 11, "AEST", "AEDT"},
-      {"Europe/Bucharest", true, 2, 3, "EET", "EEST"},
-      {"Europe/London", true, 0, 1, "GMT", "BST"},
-      {"Europe/Moscow", false, 3, 3, "MSK", "MSK"},
-      {"Europe/Paris", true, 1, 2, "CET", "CEST"},
-      {"Europe/Reykjavik", false, 0, 0, "UTC", "UTC"},
-      {"Pacific/Auckland", true, 12, 13, "NZST", "NZDT"},
-      {"Pacific/Honolulu", false, -10, -10, "HST", "HST"},
-      {"UTC", false, 0, 0, "UTC", "UTC"},
-  };
-
-  for (size_t index = 0; index < arraysize(kTestTimeZones); ++index) {
-    const auto& test_time_zone = kTestTimeZones[index];
-    const char* tz = test_time_zone.tz;
-    SCOPED_TRACE(base::StringPrintf("index %zu, tz %s", index, tz));
-
-    {
-      ScopedSetTZ set_tz(tz);
-      system_snapshot().TimeZone(&dst_status,
-                                 &standard_offset_seconds,
-                                 &daylight_offset_seconds,
-                                 &standard_name,
-                                 &daylight_name);
-    }
-
-    EXPECT_EQ(dst_status != SystemSnapshot::kDoesNotObserveDaylightSavingTime,
-              test_time_zone.observes_dst);
-    EXPECT_EQ(standard_offset_seconds,
-              test_time_zone.standard_offset_hours * 60 * 60);
-    EXPECT_EQ(daylight_offset_seconds,
-              test_time_zone.daylight_offset_hours * 60 * 60);
-    if (test_time_zone.standard_name) {
-      EXPECT_EQ(standard_name, test_time_zone.standard_name);
-    }
-    if (test_time_zone.daylight_name) {
-      EXPECT_EQ(daylight_name, test_time_zone.daylight_name);
-    }
-  }
-}
-
 }  // namespace
 }  // namespace test
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/posix/timezone.cc b/third_party/crashpad/crashpad/snapshot/posix/timezone.cc
new file mode 100644
index 0000000..47c6ecfa
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/posix/timezone.cc
@@ -0,0 +1,118 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/posix/timezone.h"
+
+#include <stddef.h>
+#include <time.h>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace crashpad {
+namespace internal {
+
+void TimeZone(const timeval& snapshot_time,
+              SystemSnapshot::DaylightSavingTimeStatus* dst_status,
+              int* standard_offset_seconds,
+              int* daylight_offset_seconds,
+              std::string* standard_name,
+              std::string* daylight_name) {
+  tzset();
+
+  tm local;
+  PCHECK(localtime_r(&snapshot_time.tv_sec, &local)) << "localtime_r";
+
+  *standard_name = tzname[0];
+
+  bool found_transition = false;
+  long probe_gmtoff = local.tm_gmtoff;
+#if defined(OS_ANDROID)
+  // Some versions of the timezone database on Android have incorrect
+  // information (e.g. Asia/Kolkata and Pacific/Honolulu). These timezones set
+  // daylight to a non-zero value and return incorrect, >= 0 values for tm_isdst
+  // in the probes below. If tzname[1] is set to a bogus value, assume the
+  // timezone does not actually use daylight saving time.
+  if (daylight && strncmp(tzname[1], "_TZif", 5) != 0) {
+#else
+  if (daylight) {
+#endif
+    // Scan forward and backward, one month at a time, looking for an instance
+    // when the observance of daylight saving time is different than it is in
+    // |local|. It’s possible that no such instance will be found even with
+    // |daylight| set. This can happen in locations where daylight saving time
+    // was once observed or is expected to be observed in the future, but where
+    // no transitions to or from daylight saving time occurred or will occur
+    // within a year of the current date. Arizona, which last observed daylight
+    // saving time in 1967, is an example.
+    static constexpr int kMonthDeltas[] =
+        {0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6,
+         7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12};
+    for (size_t index = 0;
+         index < arraysize(kMonthDeltas) && !found_transition;
+         ++index) {
+      // Look at a day of each month at local noon. Set tm_isdst to -1 to avoid
+      // giving mktime() any hints about whether to consider daylight saving
+      // time in effect. mktime() accepts values of tm_mon that are outside of
+      // its normal range and behaves as expected: if tm_mon is -1, it
+      // references December of the preceding year, and if it is 12, it
+      // references January of the following year.
+      tm probe_tm = {};
+      probe_tm.tm_hour = 12;
+      probe_tm.tm_mday = std::min(local.tm_mday, 28);
+      probe_tm.tm_mon = local.tm_mon + kMonthDeltas[index];
+      probe_tm.tm_year = local.tm_year;
+      probe_tm.tm_isdst = -1;
+      if (mktime(&probe_tm) == -1) {
+        PLOG(WARNING) << "mktime";
+        continue;
+      }
+      if (probe_tm.tm_isdst < 0 || local.tm_isdst < 0) {
+        LOG(WARNING) << "dst status not available";
+        continue;
+      }
+      if (probe_tm.tm_isdst != local.tm_isdst) {
+        found_transition = true;
+        probe_gmtoff = probe_tm.tm_gmtoff;
+      }
+    }
+  }
+
+  if (found_transition) {
+    *daylight_name = tzname[1];
+    if (!local.tm_isdst) {
+      *dst_status = SystemSnapshot::kObservingStandardTime;
+      *standard_offset_seconds = local.tm_gmtoff;
+      *daylight_offset_seconds = probe_gmtoff;
+    } else {
+      *dst_status = SystemSnapshot::kObservingDaylightSavingTime;
+      *standard_offset_seconds = probe_gmtoff;
+      *daylight_offset_seconds = local.tm_gmtoff;
+    }
+  } else {
+    *daylight_name = tzname[0];
+    *dst_status = SystemSnapshot::kDoesNotObserveDaylightSavingTime;
+#if defined(OS_ANDROID)
+    // timezone is more reliably set correctly on Android.
+    *standard_offset_seconds = -timezone;
+    *daylight_offset_seconds = -timezone;
+#else
+    *standard_offset_seconds = local.tm_gmtoff;
+    *daylight_offset_seconds = local.tm_gmtoff;
+#endif  // OS_ANDROID
+  }
+}
+
+}  // namespace internal
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/posix/timezone.h b/third_party/crashpad/crashpad/snapshot/posix/timezone.h
new file mode 100644
index 0000000..bd404a354
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/posix/timezone.h
@@ -0,0 +1,55 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_SNAPSHOT_POSIX_TIMEZONE_H_
+#define CRASHPAD_SNAPSHOT_POSIX_TIMEZONE_H_
+
+#include <sys/time.h>
+
+#include <string>
+
+#include "snapshot/system_snapshot.h"
+
+namespace crashpad {
+namespace internal {
+
+//! \brief Returns time zone information from the snapshot system, based on
+//!     its locale configuration and \a snapshot_time.
+//!
+//! \param[in] snapshot_time The time to use collect daylight saving time status
+//!     for, given in time since Epoch.
+//! \param[out] dst_status Whether the location observes daylight saving time,
+//!     and if so, whether it or standard time is currently being observed.
+//! \param[out] standard_offset_seconds The number of seconds that the
+//!     location’s time zone is east (ahead) of UTC during standard time.
+//! \param[out] daylight_offset_seconds The number of seconds that the
+//!     location’s time zone is east (ahead) of UTC during daylight saving.
+//!     time.
+//! \param[out] standard_name The name of the time zone while standard time is
+//!     being observed.
+//! \param[out] daylight_name The name of the time zone while daylight saving
+//!     time is being observed.
+//!
+//! \sa SystemSnapshot::TimeZone
+void TimeZone(const timeval& snapshot_time,
+              SystemSnapshot::DaylightSavingTimeStatus* dst_status,
+              int* standard_offset_seconds,
+              int* daylight_offset_seconds,
+              std::string* standard_name,
+              std::string* daylight_name);
+
+}  // namespace internal
+}  // namespace crashpad
+
+#endif  // CRASHPAD_SNAPSHOT_POSIX_TIMEZONE_H_
diff --git a/third_party/crashpad/crashpad/snapshot/posix/timezone_test.cc b/third_party/crashpad/crashpad/snapshot/posix/timezone_test.cc
new file mode 100644
index 0000000..01bdff50
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/posix/timezone_test.cc
@@ -0,0 +1,196 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/posix/timezone.h"
+
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "gtest/gtest.h"
+#include "test/errors.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+class ScopedSetTZ {
+ public:
+  ScopedSetTZ(const std::string& tz) {
+    const char* old_tz = getenv(kTZ);
+    old_tz_set_ = old_tz;
+    if (old_tz_set_) {
+      old_tz_.assign(old_tz);
+    }
+
+    EXPECT_EQ(setenv(kTZ, tz.c_str(), 1), 0) << ErrnoMessage("setenv");
+    tzset();
+  }
+
+  ~ScopedSetTZ() {
+    if (old_tz_set_) {
+      EXPECT_EQ(setenv(kTZ, old_tz_.c_str(), 1), 0) << ErrnoMessage("setenv");
+    } else {
+      EXPECT_EQ(unsetenv(kTZ), 0) << ErrnoMessage("unsetenv");
+    }
+    tzset();
+  }
+
+ private:
+  std::string old_tz_;
+  bool old_tz_set_;
+
+  static constexpr char kTZ[] = "TZ";
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSetTZ);
+};
+
+constexpr char ScopedSetTZ::kTZ[];
+
+TEST(TimeZone, Basic) {
+  SystemSnapshot::DaylightSavingTimeStatus dst_status;
+  int standard_offset_seconds;
+  int daylight_offset_seconds;
+  std::string standard_name;
+  std::string daylight_name;
+
+  timeval snapshot_time;
+  ASSERT_EQ(gettimeofday(&snapshot_time, nullptr), 0);
+
+  internal::TimeZone(snapshot_time,
+                     &dst_status,
+                     &standard_offset_seconds,
+                     &daylight_offset_seconds,
+                     &standard_name,
+                     &daylight_name);
+
+  // |standard_offset_seconds| gives seconds east of UTC, and |timezone| gives
+  // seconds west of UTC.
+  EXPECT_EQ(standard_offset_seconds, -timezone);
+
+  // In contemporary usage, most time zones have an integer hour offset from
+  // UTC, although several are at a half-hour offset, and two are at 15-minute
+  // offsets. Throughout history, other variations existed. See
+  // http://www.timeanddate.com/time/time-zones-interesting.html.
+  EXPECT_EQ(standard_offset_seconds % (15 * 60), 0)
+      << "standard_offset_seconds " << standard_offset_seconds;
+
+  if (dst_status == SystemSnapshot::kDoesNotObserveDaylightSavingTime) {
+    EXPECT_EQ(daylight_offset_seconds, standard_offset_seconds);
+    EXPECT_EQ(daylight_name, standard_name);
+  } else {
+    EXPECT_EQ(daylight_offset_seconds % (15 * 60), 0)
+        << "daylight_offset_seconds " << daylight_offset_seconds;
+
+    // In contemporary usage, dst_delta_seconds will almost always be one hour,
+    // except for Lord Howe Island, Australia, which uses a 30-minute
+    // delta. Throughout history, other variations existed. See
+    // http://www.timeanddate.com/time/dst/#brief.
+    int dst_delta_seconds = daylight_offset_seconds - standard_offset_seconds;
+    if (dst_delta_seconds != 60 * 60 && dst_delta_seconds != 30 * 60) {
+      FAIL() << "dst_delta_seconds " << dst_delta_seconds;
+    }
+
+    EXPECT_NE(standard_name, daylight_name);
+  }
+
+  // Test a variety of time zones. Some of these observe daylight saving time,
+  // some don’t. Some used to but no longer do. Some have uncommon UTC offsets.
+  // standard_name and daylight_name can be nullptr where no name exists to
+  // verify, as may happen when some versions of the timezone database carry
+  // invented names and others do not.
+  static constexpr struct {
+    const char* tz;
+    bool observes_dst;
+    float standard_offset_hours;
+    float daylight_offset_hours;
+    const char* standard_name;
+    const char* daylight_name;
+  } kTestTimeZones[] = {
+      {"America/Anchorage", true, -9, -8, "AKST", "AKDT"},
+      {"America/Chicago", true, -6, -5, "CST", "CDT"},
+      {"America/Denver", true, -7, -6, "MST", "MDT"},
+      {"America/Halifax", true, -4, -3, "AST", "ADT"},
+      {"America/Los_Angeles", true, -8, -7, "PST", "PDT"},
+      {"America/New_York", true, -5, -4, "EST", "EDT"},
+      {"America/Phoenix", false, -7, -7, "MST", "MST"},
+      {"Asia/Karachi", false, 5, 5, "PKT", "PKT"},
+      {"Asia/Kolkata", false, 5.5, 5.5, "IST", "IST"},
+      {"Asia/Shanghai", false, 8, 8, "CST", "CST"},
+      {"Asia/Tokyo", false, 9, 9, "JST", "JST"},
+
+      // Australian timezone names have an optional "A" prefix, which is
+      // present for glibc and macOS, but missing on Android.
+      {"Australia/Adelaide", true, 9.5, 10.5, nullptr, nullptr},
+      {"Australia/Brisbane", false, 10, 10, nullptr, nullptr},
+      {"Australia/Darwin", false, 9.5, 9.5, nullptr, nullptr},
+      {"Australia/Eucla", false, 8.75, 8.75, nullptr, nullptr},
+      {"Australia/Lord_Howe", true, 10.5, 11, nullptr, nullptr},
+      {"Australia/Perth", false, 8, 8, nullptr, nullptr},
+      {"Australia/Sydney", true, 10, 11, nullptr, nullptr},
+
+      {"Europe/Bucharest", true, 2, 3, "EET", "EEST"},
+      {"Europe/London", true, 0, 1, "GMT", "BST"},
+      {"Europe/Paris", true, 1, 2, "CET", "CEST"},
+      {"Europe/Reykjavik", false, 0, 0, nullptr, nullptr},
+      {"Pacific/Auckland", true, 12, 13, "NZST", "NZDT"},
+      {"Pacific/Honolulu", false, -10, -10, "HST", "HST"},
+      {"UTC", false, 0, 0, "UTC", "UTC"},
+  };
+
+  for (size_t index = 0; index < arraysize(kTestTimeZones); ++index) {
+    const auto& test_time_zone = kTestTimeZones[index];
+    const char* tz = test_time_zone.tz;
+    SCOPED_TRACE(base::StringPrintf("index %zu, tz %s", index, tz));
+
+    {
+      ScopedSetTZ set_tz(tz);
+      internal::TimeZone(snapshot_time,
+                         &dst_status,
+                         &standard_offset_seconds,
+                         &daylight_offset_seconds,
+                         &standard_name,
+                         &daylight_name);
+    }
+
+    EXPECT_PRED2(
+        [](SystemSnapshot::DaylightSavingTimeStatus dst, bool observes) {
+          return (dst != SystemSnapshot::kDoesNotObserveDaylightSavingTime) ==
+                 observes;
+        },
+        dst_status,
+        test_time_zone.observes_dst);
+
+    EXPECT_EQ(standard_offset_seconds,
+              test_time_zone.standard_offset_hours * 60 * 60);
+    EXPECT_EQ(daylight_offset_seconds,
+              test_time_zone.daylight_offset_hours * 60 * 60);
+    if (test_time_zone.standard_name) {
+      EXPECT_EQ(standard_name, test_time_zone.standard_name);
+    }
+    if (test_time_zone.daylight_name) {
+      EXPECT_EQ(daylight_name, test_time_zone.daylight_name);
+    }
+  }
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot.gyp b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
index 24ab7a7..1c63be2 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
@@ -57,6 +57,8 @@
         'linux/process_reader.cc',
         'linux/process_reader.h',
         'linux/signal_context.h',
+        'linux/system_snapshot_linux.cc',
+        'linux/system_snapshot_linux.h',
         'linux/thread_snapshot_linux.cc',
         'linux/thread_snapshot_linux.h',
         'mac/cpu_context_mac.cc',
@@ -107,6 +109,8 @@
         'minidump/process_snapshot_minidump.cc',
         'minidump/process_snapshot_minidump.h',
         'module_snapshot.h',
+        'posix/timezone.cc',
+        'posix/timezone.h',
         'process_snapshot.h',
         'system_snapshot.h',
         'thread_snapshot.h',
@@ -140,6 +144,8 @@
         'win/system_snapshot_win.h',
         'win/thread_snapshot_win.cc',
         'win/thread_snapshot_win.h',
+        'x86/cpuid_reader.cc',
+        'x86/cpuid_reader.h',
       ],
       'conditions': [
         ['OS=="win"', {
@@ -155,6 +161,11 @@
             'capture_memory.h',
           ],
         }],
+        ['target_arch!="ia32" and target_arch!="x64"', {
+          'sources/': [
+            ['exclude', '^x86/'],
+          ],
+        }],
       ],
       'target_conditions': [
         ['OS=="android"', {
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
index d81c4b5..80a66f4 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
@@ -74,6 +74,7 @@
         'linux/elf_image_reader_test.cc',
         'linux/exception_snapshot_linux_test.cc',
         'linux/process_reader_test.cc',
+        'linux/system_snapshot_linux_test.cc',
         'mac/cpu_context_mac_test.cc',
         'mac/mach_o_image_annotations_reader_test.cc',
         'mac/mach_o_image_reader_test.cc',
@@ -82,6 +83,7 @@
         'mac/process_types_test.cc',
         'mac/system_snapshot_mac_test.cc',
         'minidump/process_snapshot_minidump_test.cc',
+        'posix/timezone_test.cc',
         'win/cpu_context_win_test.cc',
         'win/exception_snapshot_win_test.cc',
         'win/extra_memory_ranges_test.cc',
diff --git a/third_party/crashpad/crashpad/snapshot/system_snapshot.h b/third_party/crashpad/crashpad/snapshot/system_snapshot.h
index 549f0b6..6da3d37 100644
--- a/third_party/crashpad/crashpad/snapshot/system_snapshot.h
+++ b/third_party/crashpad/crashpad/snapshot/system_snapshot.h
@@ -41,6 +41,12 @@
 
     //! \brief Windows.
     kOperatingSystemWindows,
+
+    //! \brief Linux.
+    kOperatingSystemLinux,
+
+    //! \brief Android.
+    kOperatingSystemAndroid,
   };
 
   //! \brief A system’s daylight saving time status.
diff --git a/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.cc b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.cc
new file mode 100644
index 0000000..ccedf92
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.cc
@@ -0,0 +1,132 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/x86/cpuid_reader.h"
+
+#include "build/build_config.h"
+#include "snapshot/cpu_context.h"
+
+#if defined(OS_WIN)
+#include <immintrin.h>
+#include <intrin.h>
+#endif  // OS_WIN
+
+namespace crashpad {
+namespace internal {
+
+CpuidReader::CpuidReader()
+    : features_(0),
+      extended_features_(0),
+      vendor_(),
+      max_leaf_(0),
+      signature_(0) {
+  uint32_t cpuinfo[4];
+  Cpuid(cpuinfo, 0);
+  max_leaf_ = cpuinfo[0];
+  vendor_.append(reinterpret_cast<char*>(&cpuinfo[1]), 4);
+  vendor_.append(reinterpret_cast<char*>(&cpuinfo[3]), 4);
+  vendor_.append(reinterpret_cast<char*>(&cpuinfo[2]), 4);
+
+  Cpuid(cpuinfo, 1);
+  signature_ = cpuinfo[0];
+  features_ = (static_cast<uint64_t>(cpuinfo[2]) << 32) |
+              static_cast<uint64_t>(cpuinfo[3]);
+
+  Cpuid(cpuinfo, 0x80000001);
+  extended_features_ = (static_cast<uint64_t>(cpuinfo[2]) << 32) |
+                       static_cast<uint64_t>(cpuinfo[3]);
+}
+
+CpuidReader::~CpuidReader() {}
+
+uint32_t CpuidReader::Revision() const {
+  uint8_t stepping = signature_ & 0xf;
+  uint8_t model = (signature_ & 0xf0) >> 4;
+  uint8_t family = (signature_ & 0xf00) >> 8;
+  uint8_t extended_model = static_cast<uint8_t>((signature_ & 0xf0000) >> 16);
+  uint16_t extended_family = (signature_ & 0xff00000) >> 20;
+
+  // For families before 15, extended_family are simply reserved bits.
+  if (family < 15)
+    extended_family = 0;
+  // extended_model is only used for families 6 and 15.
+  if (family != 6 && family != 15)
+    extended_model = 0;
+
+  uint16_t adjusted_family = family + extended_family;
+  uint8_t adjusted_model = model + (extended_model << 4);
+  return (adjusted_family << 16) | (adjusted_model << 8) | stepping;
+}
+
+uint32_t CpuidReader::Leaf7Features() const {
+  if (max_leaf_ < 7) {
+    return 0;
+  }
+  uint32_t cpuinfo[4];
+  Cpuid(cpuinfo, 7);
+  return cpuinfo[1];
+}
+
+bool CpuidReader::SupportsDAZ() const {
+  // The correct way to check for denormals-as-zeros (DAZ) support is to examine
+  // mxcsr mask, which can be done with fxsave. See Intel Software Developer’s
+  // Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 “Checking for the
+  // DAZ Flag in the MXCSR Register”. Note that since this function tests for
+  // DAZ support in the CPU, it checks the mxcsr mask. Testing mxcsr would
+  // indicate whether DAZ is actually enabled, which is a per-thread context
+  // concern.
+
+  // Test for fxsave support.
+  if (!(features_ & (UINT64_C(1) << 24))) {
+    return false;
+  }
+
+#if defined(ARCH_CPU_X86)
+  using Fxsave = CPUContextX86::Fxsave;
+#elif defined(ARCH_CPU_X86_64)
+  using Fxsave = CPUContextX86_64::Fxsave;
+#endif
+
+#if defined(OS_WIN)
+  __declspec(align(16)) Fxsave fxsave = {};
+#else
+  Fxsave fxsave __attribute__((aligned(16))) = {};
+#endif
+
+  static_assert(sizeof(fxsave) == 512, "fxsave size");
+  static_assert(offsetof(decltype(fxsave), mxcsr_mask) == 28,
+                "mxcsr_mask offset");
+
+#if defined(OS_WIN)
+  _fxsave(&fxsave);
+#else
+  asm("fxsave %0" : "=m"(fxsave));
+#endif
+
+  // Test the DAZ bit.
+  return (fxsave.mxcsr_mask & (1 << 6)) != 0;
+}
+
+void CpuidReader::Cpuid(uint32_t cpuinfo[4], uint32_t leaf) const {
+#if defined(OS_WIN)
+  __cpuid(reinterpret_cast<int*>(cpuinfo), leaf);
+#else
+  asm("cpuid"
+      : "=a"(cpuinfo[0]), "=b"(cpuinfo[1]), "=c"(cpuinfo[2]), "=d"(cpuinfo[3])
+      : "a"(leaf), "b"(0), "c"(0), "d"(0));
+#endif  // OS_WIN
+}
+
+}  // namespace internal
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.h b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.h
new file mode 100644
index 0000000..0fd02cf
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.h
@@ -0,0 +1,63 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+
+#include <string>
+
+namespace crashpad {
+namespace internal {
+
+//! \brief Reads x86-family CPU information by calling `cpuid`.
+class CpuidReader {
+ public:
+  CpuidReader();
+  ~CpuidReader();
+
+  //! \see SystemSnapshot::CPURevision
+  uint32_t Revision() const;
+
+  //! \see SystemSnapshot::CPUVendor
+  std::string Vendor() const { return vendor_; }
+
+  //! \see SystemSnapshot::CPUX86Signature
+  uint32_t Signature() const { return signature_; }
+
+  //! \see SystemSnapshot::CPUX86Features
+  uint64_t Features() const { return features_; }
+
+  //! \see SystemSnapshot::CPUX86ExtendedFeatures
+  uint64_t ExtendedFeatures() const { return extended_features_; }
+
+  //! \see SystemSnapshot::CPUX86Leaf7Features
+  uint32_t Leaf7Features() const;
+
+  //! \see SystemSnapshot::NXEnabled
+  bool NXEnabled() const { return (ExtendedFeatures() & (1 << 20)) != 0; }
+
+  //! \see SystemSnapshot::CPUX86SupportsDAZ
+  bool SupportsDAZ() const;
+
+ private:
+  void Cpuid(uint32_t cpuinfo[4], uint32_t leaf) const;
+
+  uint64_t features_;
+  uint64_t extended_features_;
+  std::string vendor_;
+  uint32_t max_leaf_;
+  uint32_t signature_;
+};
+
+}  // namespace internal
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/misc/clock.h b/third_party/crashpad/crashpad/util/misc/clock.h
index a07e12a6..ed88cdc 100644
--- a/third_party/crashpad/crashpad/util/misc/clock.h
+++ b/third_party/crashpad/crashpad/util/misc/clock.h
@@ -34,19 +34,15 @@
 //! \return The value of the system’s monotonic clock, in nanoseconds.
 uint64_t ClockMonotonicNanoseconds();
 
-#if !defined(OS_WIN)  // Not implemented on Windows yet.
-
 //! \brief Sleeps for the specified duration.
 //!
 //! \param[in] nanoseconds The number of nanoseconds to sleep. The actual sleep
 //!     may be slightly longer due to latencies and timer resolution.
 //!
-//! This function is resilient against the underlying `nanosleep()` system call
-//! being interrupted by a signal.
+//! On POSIX, this function is resilient against the underlying `nanosleep()`
+//! system call being interrupted by a signal.
 void SleepNanoseconds(uint64_t nanoseconds);
 
-#endif
-
 }  // namespace crashpad
 
 #endif  // CRASHPAD_UTIL_MISC_CLOCK_H_
diff --git a/third_party/crashpad/crashpad/util/misc/clock_win.cc b/third_party/crashpad/crashpad/util/misc/clock_win.cc
index 18d0754..1079c423 100644
--- a/third_party/crashpad/crashpad/util/misc/clock_win.cc
+++ b/third_party/crashpad/crashpad/util/misc/clock_win.cc
@@ -45,4 +45,12 @@
          ((leftover_ticks * kNanosecondsPerSecond) / frequency);
 }
 
+void SleepNanoseconds(uint64_t nanoseconds) {
+  // This is both inaccurate (will be way too long for short sleeps) and
+  // incorrect (can sleep for less than requested). But it's what's available
+  // without implementing a busy loop.
+  constexpr uint64_t kNanosecondsPerMillisecond = static_cast<uint64_t>(1E6);
+  Sleep(static_cast<DWORD>(nanoseconds / kNanosecondsPerMillisecond));
+}
+
 }  // namespace crashpad
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/controller.js b/third_party/google_input_tools/src/chrome/os/inputview/controller.js
index 3c52b07..72cb4a4 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/controller.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/controller.js
@@ -2247,6 +2247,12 @@
   var widthPercent;
   var candidateViewHeight;
   var isLandScape = screen.width > screen.height;
+
+  if (this.container_.getElement() == null) {
+    // Loading settings is not completed yet. Ignore this event.
+    return;
+  }
+
   if (isLandScape) {
     goog.dom.classlist.addRemove(this.container_.getElement(),
         Css.PORTRAIT, Css.LANDSCAPE);
diff --git a/third_party/openvr/README.chromium b/third_party/openvr/README.chromium
index 936f6cb..029fc8a 100644
--- a/third_party/openvr/README.chromium
+++ b/third_party/openvr/README.chromium
@@ -5,7 +5,7 @@
 Date: 2 Feb 2017
 Revision: 7fa6470f2972970859f2395f1390f6d87d4b0fc3
 License: MIT
-License File: src\LICENSE
+License File: src/LICENSE
 Security Critical: yes
 
 Description:
diff --git a/third_party/typ/README.chromium b/third_party/typ/README.chromium
index c8af3c19..0b3264e 100644
--- a/third_party/typ/README.chromium
+++ b/third_party/typ/README.chromium
@@ -1,7 +1,7 @@
 Name: typ
 URL: https://github.com/dpranke/typ.git
-Version: 0.9.12
-Revision: 2b5a4fcf7c103323f9c6cd8d8127d740e78c0fe8
+Version: 0.10.0
+Revision: 1e254b3ef4d14dee6109d8c3a58ab64d1500e3c2
 Security Critical: no
 License: Apache 2.0
 License File: NOT_SHIPPED
diff --git a/third_party/typ/typ/arg_parser.py b/third_party/typ/typ/arg_parser.py
index 31d575d..707adab0 100644
--- a/third_party/typ/typ/arg_parser.py
+++ b/third_party/typ/typ/arg_parser.py
@@ -85,7 +85,7 @@
                               default=[],
                               help=('Directories to include when running and '
                                     'reporting coverage (defaults to '
-                                    '--top-level-dir plus --path)'))
+                                    '--top-level-dirs plus --path)'))
             self.add_argument('--coverage-omit', action='append',
                               default=[],
                               help=('Globs to omit when reporting coverage '
@@ -171,7 +171,9 @@
             self.add_argument('-P', '--path', action='append', default=[],
                               help=('Adds dir to sys.path (can specify '
                                     'multiple times).'))
-            self.add_argument('--top-level-dir', default=None,
+            self.add_argument('--top-level-dir', action='store', default=None,
+                              help=argparse.SUPPRESS)
+            self.add_argument('--top-level-dirs', action='append', default=[],
                               help=('Sets the top directory of project '
                                     '(used when running subdirs).'))
 
diff --git a/third_party/typ/typ/runner.py b/third_party/typ/typ/runner.py
index 01e414c..62d92c7f 100644
--- a/third_party/typ/typ/runner.py
+++ b/third_party/typ/typ/runner.py
@@ -111,6 +111,7 @@
         self.stats = None
         self.teardown_fn = None
         self.top_level_dir = None
+        self.top_level_dirs = []
         self.win_multiprocessing = WinMultiprocessing.spawn
         self.final_responses = []
 
@@ -159,7 +160,7 @@
             return self._spawn(test_set)
 
         ret = self._set_up_runner()
-        if ret:  # pragma: no cover
+        if ret:
             return ret, None, None
 
         find_start = h.time()
@@ -289,24 +290,39 @@
         self.printer = Printer(
             self.print_, args.overwrite, args.terminal_width)
 
-        self.top_level_dir = args.top_level_dir
-        if not self.top_level_dir:
-            if args.tests and h.isdir(args.tests[0]):
-                # TODO: figure out what to do if multiple files are
-                # specified and they don't all have the same correct
-                # top level dir.
-                d = h.realpath(h.dirname(args.tests[0]))
-                if h.exists(d, '__init__.py'):
-                    top_dir = d
+        if self.args.top_level_dirs and self.args.top_level_dir:
+            self.print_(
+                'Cannot specify both --top-level-dir and --top-level-dirs',
+                stream=h.stderr)
+            return 1
+
+        self.top_level_dirs = args.top_level_dirs
+        if not self.top_level_dirs and args.top_level_dir:
+            self.top_level_dirs = [args.top_level_dir]
+
+        if not self.top_level_dirs:
+            for test in [t for t in args.tests if h.exists(t)]:
+                if h.isdir(test):
+                    top_dir = test
                 else:
-                    top_dir = args.tests[0]
-            else:
-                top_dir = h.getcwd()
+                    top_dir = h.dirname(test)
+                while h.exists(top_dir, '__init__.py'):
+                    top_dir = h.dirname(top_dir)
+                top_dir = h.realpath(top_dir)
+                if not top_dir in self.top_level_dirs:
+                    self.top_level_dirs.append(top_dir)
+        if not self.top_level_dirs:
+            top_dir = h.getcwd()
             while h.exists(top_dir, '__init__.py'):
                 top_dir = h.dirname(top_dir)
-            self.top_level_dir = h.realpath(top_dir)
+            top_dir = h.realpath(top_dir)
+            self.top_level_dirs.append(top_dir)
 
-        h.add_to_path(self.top_level_dir)
+        if not self.top_level_dir and self.top_level_dirs:
+            self.top_level_dir = self.top_level_dirs[0]
+
+        for path in self.top_level_dirs:
+            h.add_to_path(path)
 
         for path in args.path:
             h.add_to_path(path)
@@ -315,11 +331,11 @@
             try:
                 import coverage
             except ImportError:
-                h.print_("Error: coverage is not installed")
                 return 1
+
             source = self.args.coverage_source
             if not source:
-                source = [self.top_level_dir] + self.args.path
+                source = self.top_level_dirs + self.args.path
             self.coverage_source = source
             self.cov = coverage.coverage(source=self.coverage_source,
                                          data_suffix=True)
@@ -342,7 +358,7 @@
             for name in names:
                 try:
                     self._add_tests_to_set(test_set, args.suffixes,
-                                           self.top_level_dir, classifier,
+                                           self.top_level_dirs, classifier,
                                            name)
                 except (AttributeError, ImportError, SyntaxError) as e:
                     ex_str = traceback.format_exc()
@@ -385,33 +401,47 @@
                 s = self.host.read_text_file(args.file_list)
             names = [line.strip() for line in s.splitlines()]
         else:
-            names = [self.top_level_dir]
+            names = self.top_level_dirs
         return names
 
-    def _add_tests_to_set(self, test_set, suffixes, top_level_dir, classifier,
+    def _add_tests_to_set(self, test_set, suffixes, top_level_dirs, classifier,
                           name):
         h = self.host
         loader = self.loader
         add_tests = _test_adder(test_set, classifier)
 
-        if h.isfile(name):
-            rpath = h.relpath(name, top_level_dir)
-            if rpath.endswith('.py'):
-                rpath = rpath[:-3]
-            module = rpath.replace(h.sep, '.')
-            add_tests(loader.loadTestsFromName(module))
-        elif h.isdir(name):
-            for suffix in suffixes:
-                add_tests(loader.discover(name, suffix, top_level_dir))
-        else:
-            possible_dir = name.replace('.', h.sep)
-            if h.isdir(top_level_dir, possible_dir):
+        found = set()
+        for d in top_level_dirs:
+            if h.isfile(name):
+                rpath = h.relpath(name, d)
+                if rpath.startswith('..'):
+                    continue
+                if rpath.endswith('.py'):
+                    rpath = rpath[:-3]
+                module = rpath.replace(h.sep, '.')
+                if module not in found:
+                    found.add(module)
+                    add_tests(loader.loadTestsFromName(module))
+            elif h.isdir(name):
+                rpath = h.relpath(name, d)
+                if rpath.startswith('..'):
+                    continue
                 for suffix in suffixes:
-                    path = h.join(top_level_dir, possible_dir)
-                    suite = loader.discover(path, suffix, top_level_dir)
-                    add_tests(suite)
+                    if not name in found:
+                        found.add(name + '/' + suffix)
+                        add_tests(loader.discover(name, suffix, d))
             else:
-                add_tests(loader.loadTestsFromName(name))
+                possible_dir = name.replace('.', h.sep)
+                if h.isdir(d, possible_dir):
+                    for suffix in suffixes:
+                        path = h.join(d, possible_dir)
+                        if not path in found:
+                            found.add(path + '/' + suffix)
+                            suite = loader.discover(path, suffix, d)
+                            add_tests(suite)
+                elif not name in found:
+                    found.add(name)
+                    add_tests(loader.loadTestsFromName(name))
 
         # pylint: disable=no-member
         if hasattr(loader, 'errors') and loader.errors:  # pragma: python3
@@ -755,6 +785,7 @@
         self.teardown_fn = parent.teardown_fn
         self.context_after_setup = None
         self.top_level_dir = parent.top_level_dir
+        self.top_level_dirs = parent.top_level_dirs
         self.loaded_suites = {}
         self.cov = None
 
diff --git a/third_party/typ/typ/tests/main_test.py b/third_party/typ/typ/tests/main_test.py
index f17aabc..2d90b16 100644
--- a/third_party/typ/typ/tests/main_test.py
+++ b/third_party/typ/typ/tests/main_test.py
@@ -354,6 +354,60 @@
                    files=files, cwd='bar', ret=0, err='',
                    out='pass_test.PassingTest.test_pass\n')
 
+    def test_multiple_top_level_dirs(self):
+        files = {
+            'foo/bar/__init__.py': '',
+            'foo/bar/pass_test.py': PASS_TEST_PY,
+            'baz/quux/__init__.py': '',
+            'baz/quux/second_test.py': PASS_TEST_PY,
+        }
+        self.check(['-l', 'foo/bar', 'baz/quux'], files=files,
+                   ret=0, err='',
+                   out=(
+                       'bar.pass_test.PassingTest.test_pass\n'
+                       'quux.second_test.PassingTest.test_pass\n'
+                       ))
+        self.check(['-l', 'foo/bar/pass_test.py', 'baz/quux'], files=files,
+                   ret=0, err='',
+                   out=(
+                       'bar.pass_test.PassingTest.test_pass\n'
+                       'quux.second_test.PassingTest.test_pass\n'
+                       ))
+        self.check(['-l', '--top-level-dirs', 'foo', '--top-level-dirs', 'baz'],
+                   files=files,
+                   ret=0, err='',
+                   out=(
+                       'bar.pass_test.PassingTest.test_pass\n'
+                       'quux.second_test.PassingTest.test_pass\n'
+                       ))
+
+    def test_single_top_level_dir(self):
+        files = {
+            'foo/bar/__init__.py': '',
+            'foo/bar/pass_test.py': PASS_TEST_PY,
+            'baz/quux/__init__.py': '',
+            'baz/quux/second_test.py': PASS_TEST_PY,
+        }
+        self.check(['-l', '--top-level-dir', 'foo'],
+                   files=files,
+                   ret=0, err='',
+                   out=(
+                       'bar.pass_test.PassingTest.test_pass\n'
+                       ))
+
+    def test_can_not_have_both_top_level_flags(self):
+        files = {
+            'foo/bar/__init__.py': '',
+            'foo/bar/pass_test.py': PASS_TEST_PY,
+            'baz/quux/__init__.py': '',
+            'baz/quux/second_test.py': PASS_TEST_PY,
+        }
+        self.check(
+            ['-l', '--top-level-dir', 'foo', '--top-level-dirs', 'bar'],
+            files=files,
+            ret=1, out='',
+            err='Cannot specify both --top-level-dir and --top-level-dirs\n')
+
     def test_help(self):
         self.check(['--help'], ret=0, rout='.*', err='')
 
diff --git a/third_party/typ/typ/version.py b/third_party/typ/typ/version.py
index 9fc38441d..437f236 100644
--- a/third_party/typ/typ/version.py
+++ b/third_party/typ/typ/version.py
@@ -12,4 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-VERSION = '0.9.12'
+VERSION = '0.10.0'
diff --git a/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.cc b/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.cc
index a51fc1e..72ce656f 100644
--- a/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.cc
+++ b/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.cc
@@ -114,12 +114,6 @@
   return lazy_tls_ptr.Pointer()->Get();
 }
 
-// static
-bool TaskQueue::IsCurrent(const char* queue_name) {
-  TaskQueue* current = Current();
-  return current && current->thread_->thread_name().compare(queue_name) == 0;
-}
-
 void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) {
   thread_->task_runner()->PostTask(FROM_HERE,
                                    base::Bind(&RunTask, base::Passed(&task)));
diff --git a/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.h b/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.h
index 46be1420..b3657a2c 100644
--- a/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.h
+++ b/third_party/webrtc_overrides/webrtc/rtc_base/task_queue.h
@@ -159,7 +159,6 @@
   static TaskQueue* Current();
 
   // Used for DCHECKing the current queue.
-  static bool IsCurrent(const char* queue_name);
   bool IsCurrent() const;
 
   // TODO(tommi): For better debuggability, implement RTC_FROM_HERE.
@@ -172,13 +171,24 @@
   void PostTaskAndReply(std::unique_ptr<QueuedTask> task,
                         std::unique_ptr<QueuedTask> reply);
 
+  // Schedules a task to execute a specified number of milliseconds from when
+  // the call is made. The precision should be considered as "best effort"
+  // and in some cases, such as on Windows when all high precision timers have
+  // been used up, can be off by as much as 15 millseconds (although 8 would be
+  // more likely). This can be mitigated by limiting the use of delayed tasks.
   void PostDelayedTask(std::unique_ptr<QueuedTask> task, uint32_t milliseconds);
 
-  template <class Closure>
+  // std::enable_if is used here to make sure that calls to PostTask() with
+  // std::unique_ptr<SomeClassDerivedFromQueuedTask> would not end up being
+  // caught by this template.
+  template <class Closure,
+            typename std::enable_if<
+                std::is_copy_constructible<Closure>::value>::type* = nullptr>
   void PostTask(const Closure& closure) {
     PostTask(std::unique_ptr<QueuedTask>(new ClosureTask<Closure>(closure)));
   }
 
+  // See documentation above for performance expectations.
   template <class Closure>
   void PostDelayedTask(const Closure& closure, uint32_t milliseconds) {
     PostDelayedTask(
diff --git a/third_party/zlib/OWNERS b/third_party/zlib/OWNERS
index 3dd8bfb..07d8bff 100644
--- a/third_party/zlib/OWNERS
+++ b/third_party/zlib/OWNERS
@@ -1,4 +1,5 @@
 agl@chromium.org
+cavalcantii@chromium.org
 cblume@chromium.org
 gavinp@chromium.org
 mtklein@chromium.org
diff --git a/tools/battor_agent/battor_connection_impl.cc b/tools/battor_agent/battor_connection_impl.cc
index aa71ffc..cb79476 100644
--- a/tools/battor_agent/battor_connection_impl.cc
+++ b/tools/battor_agent/battor_connection_impl.cc
@@ -11,7 +11,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
 #include "device/serial/buffer.h"
 #include "device/serial/serial_io_handler.h"
@@ -117,7 +117,7 @@
 
   if (!success) {
     Close();
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&Listener::OnConnectionOpened,
                               base::Unretained(listener_), false));
     return;
@@ -294,7 +294,7 @@
   LogSerial(StringPrintf("(message) Read finished with success: %d.", success));
 
   pending_read_buffer_ = nullptr;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&Listener::OnMessageRead, base::Unretained(listener_), success,
                  type, base::Passed(std::move(bytes))));
@@ -326,7 +326,7 @@
 void BattOrConnectionImpl::SetTimeout(base::TimeDelta timeout) {
   timeout_callback_.Reset(
       base::Bind(&BattOrConnectionImpl::CancelReadMessage, AsWeakPtr()));
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, timeout_callback_.callback(), timeout);
 }
 
@@ -341,7 +341,7 @@
         "(flush) Read failed due to serial read failure with error code: %d.",
         static_cast<int>(error)));
     pending_read_buffer_ = nullptr;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&Listener::OnConnectionOpened,
                               base::Unretained(listener_), false));
     return;
@@ -357,7 +357,7 @@
         base::TimeDelta::FromMilliseconds(kFlushQuietPeriodThresholdMs)) {
       LogSerial("(flush) Quiet period has finished.");
       pending_read_buffer_ = nullptr;
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
+      base::SequencedTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(&Listener::OnConnectionOpened,
                                 base::Unretained(listener_), true));
       return;
@@ -367,7 +367,7 @@
     // read again after a delay.
     LogSerial(StringPrintf("(flush) Reading more bytes after %u ms delay.",
                            kFlushQuietPeriodThresholdMs));
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&BattOrConnectionImpl::BeginReadBytesForFlush,
                        AsWeakPtr()),
@@ -436,7 +436,7 @@
                                        device::mojom::SerialSendError error) {
   bool success = (error == device::mojom::SerialSendError::NONE) &&
                  (pending_write_length_ == static_cast<size_t>(bytes_sent));
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&Listener::OnBytesSent, base::Unretained(listener_), success));
 }
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py
index 16748aae..2914b65 100644
--- a/tools/binary_size/libsupersize/console.py
+++ b/tools/binary_size/libsupersize/console.py
@@ -14,6 +14,7 @@
 import readline
 import subprocess
 import sys
+import types
 
 import archive
 import canned_queries
@@ -76,6 +77,7 @@
         'ShowExamples': self._ShowExamplesFunc,
         'canned_queries': canned_queries.CannedQueries(size_infos),
         'printed': self._printed_variables,
+        'models': models,
     }
     self._lazy_paths = lazy_paths
     self._size_infos = size_infos
@@ -102,8 +104,8 @@
       ret.symbols = ret.symbols.Sorted()
     return ret
 
-  def _PrintFunc(self, obj=None, verbose=False, recursive=False, use_pager=None,
-                 to_file=None):
+  def _PrintFunc(self, obj=None, verbose=False, summarize=True, recursive=False,
+                 use_pager=None, to_file=None):
     """Prints out the given Symbol / SymbolGroup / SizeInfo.
 
     For convenience, |obj| will be appended to the global "printed" list.
@@ -112,6 +114,7 @@
       obj: The object to be printed. Defaults to size_infos[-1]. Also accepts an
           index into the |printed| array for showing previous results.
       verbose: Show more detailed output.
+      summarize: If False, show symbols only (no headers / summaries).
       recursive: Print children of nested SymbolGroups.
       use_pager: Pipe output through `less`. Ignored when |obj| is a Symbol.
           default is to automatically pipe when output is long.
@@ -123,7 +126,8 @@
       if not isinstance(obj, models.SymbolGroup) or len(obj) > 0:
         self._printed_variables.append(obj)
     obj = obj if obj is not None else self._size_infos[-1]
-    lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive)
+    lines = describe.GenerateLines(
+        obj, verbose=verbose, recursive=recursive, summarize=summarize)
     _WriteToStream(lines, use_pager=use_pager, to_file=to_file)
 
   def _ElfPathAndToolPrefixForSymbol(self, size_info, elf_path):
@@ -327,6 +331,8 @@
         '  printed: List of objects passed to Print().',
     ]
     for key, value in self._variables.iteritems():
+      if isinstance(value, types.ModuleType):
+        continue
       if key.startswith('size_info'):
         lines.append('  {}: Loaded from {}'.format(key, value.size_path))
     lines.append('*' * 80)
diff --git a/tools/binary_size/libsupersize/describe.py b/tools/binary_size/libsupersize/describe.py
index 494ea96..414fcbfc6 100644
--- a/tools/binary_size/libsupersize/describe.py
+++ b/tools/binary_size/libsupersize/describe.py
@@ -48,9 +48,10 @@
 
 
 class Describer(object):
-  def __init__(self, verbose=False, recursive=False):
+  def __init__(self, verbose=False, recursive=False, summarize=True):
     self.verbose = verbose
     self.recursive = recursive
+    self.summarize = summarize
 
   def _DescribeSectionSizes(self, section_sizes):
     def include_in_totals(name):
@@ -189,40 +190,54 @@
           yield l
 
   def _DescribeSymbolGroup(self, group):
-    total_size = group.pss
-    section_sizes = collections.defaultdict(float)
-    for s in group.IterLeafSymbols():
-      section_sizes[s.section_name] += s.pss
+    if self.summarize:
+      total_size = group.pss
+      section_sizes = collections.defaultdict(float)
+      for s in group.IterLeafSymbols():
+        section_sizes[s.section_name] += s.pss
 
     # Apply this filter after calcualating size since an alias being removed
     # causes some symbols to be UNCHANGED, yet have pss != 0.
     if group.IsDelta() and not self.verbose:
       group = group.WhereDiffStatusIs(models.DIFF_STATUS_UNCHANGED).Inverted()
 
-    unique_paths = set()
-    for s in group.IterLeafSymbols():
-      # Ignore paths like foo/{shared}/2
-      if '{' not in s.object_path:
-        unique_paths.add(s.object_path)
+    if self.summarize:
+      unique_paths = set()
+      for s in group.IterLeafSymbols():
+        # Ignore paths like foo/{shared}/2
+        if '{' not in s.object_path:
+          unique_paths.add(s.object_path)
 
-    if group.IsDelta():
-      unique_part = 'aliases not grouped for diffs'
+      if group.IsDelta():
+        unique_part = 'aliases not grouped for diffs'
+      else:
+        unique_part = '{:,} unique'.format(group.CountUniqueSymbols())
+
+      relevant_sections = [
+          s for s in models.SECTION_TO_SECTION_NAME.itervalues()
+          if s in section_sizes]
+      if models.SECTION_NAME_MULTIPLE in relevant_sections:
+        relevant_sections.remove(models.SECTION_NAME_MULTIPLE)
+
+      size_summary = ' '.join(
+          '{}={:<10}'.format(k, _PrettySize(int(section_sizes[k])))
+          for k in relevant_sections)
+      size_summary += ' total={:<10}'.format(_PrettySize(int(total_size)))
+
+      section_legend = ', '.join(
+          '{}={}'.format(models.SECTION_NAME_TO_SECTION[k], k)
+          for k in relevant_sections if k in models.SECTION_NAME_TO_SECTION)
+
+      summary_desc = [
+          'Showing {:,} symbols ({}) with total pss: {} bytes'.format(
+              len(group), unique_part, int(total_size)),
+          size_summary,
+          'Number of unique paths: {}'.format(len(unique_paths)),
+          '',
+          'Section Legend: {}'.format(section_legend),
+      ]
     else:
-      unique_part = '{:,} unique'.format(group.CountUniqueSymbols())
-
-    relevant_sections = [s for s in models.SECTION_TO_SECTION_NAME.itervalues()
-                         if s in section_sizes]
-    if models.SECTION_NAME_MULTIPLE in relevant_sections:
-      relevant_sections.remove(models.SECTION_NAME_MULTIPLE)
-
-    size_summary = ' '.join(
-        '{}={:<10}'.format(k, _PrettySize(int(section_sizes[k])))
-        for k in relevant_sections)
-    size_summary += ' total={:<10}'.format(_PrettySize(int(total_size)))
-
-    section_legend = ', '.join(
-        '{}={}'.format(models.SECTION_NAME_TO_SECTION[k], k)
-        for k in relevant_sections if k in models.SECTION_NAME_TO_SECTION)
+      summary_desc = ()
 
     if self.verbose:
       titles = 'Index | Running Total | Section@Address | ...'
@@ -232,18 +247,10 @@
     else:
       titles = ('Index | Running Total | Section@Address | PSS | Path')
 
-    header_desc = [
-        'Showing {:,} symbols ({}) with total pss: {} bytes'.format(
-            len(group), unique_part, int(total_size)),
-        size_summary,
-        'Number of unique paths: {}'.format(len(unique_paths)),
-        '',
-        'Section Legend: {}'.format(section_legend),
-        titles,
-        '-' * 60
-    ]
+    header_desc = (titles, '-' * 60)
+
     children_desc = self._DescribeSymbolGroupChildren(group)
-    return itertools.chain(header_desc, children_desc)
+    return itertools.chain(summary_desc, header_desc, children_desc)
 
   def _DescribeDiffObjectPaths(self, delta_group):
     paths_by_status = [set(), set(), set(), set()]
@@ -281,28 +288,32 @@
         yield '  ' + p
 
   def _DescribeDeltaSymbolGroup(self, delta_group):
-    header_template = ('{} symbols added (+), {} changed (~), {} removed (-), '
-                       '{} unchanged ({})')
-    unchanged_msg = '=' if self.verbose else 'not shown'
-    counts = delta_group.CountsByDiffStatus()
-    num_unique_before_symbols, num_unique_after_symbols = (
-        delta_group.CountUniqueSymbols())
-    diff_summary_desc = [
-        header_template.format(
-            counts[models.DIFF_STATUS_ADDED],
-            counts[models.DIFF_STATUS_CHANGED],
-            counts[models.DIFF_STATUS_REMOVED],
-            counts[models.DIFF_STATUS_UNCHANGED],
-            unchanged_msg),
-        'Number of unique symbols {} -> {} ({:+})'.format(
-            num_unique_before_symbols, num_unique_after_symbols,
-            num_unique_after_symbols - num_unique_before_symbols),
-        ]
-    path_delta_desc = self._DescribeDiffObjectPaths(delta_group)
+    if self.summarize:
+      header_template = ('{} symbols added (+), {} changed (~), '
+                         '{} removed (-), {} unchanged ({})')
+      unchanged_msg = '=' if self.verbose else 'not shown'
+      counts = delta_group.CountsByDiffStatus()
+      num_unique_before_symbols, num_unique_after_symbols = (
+          delta_group.CountUniqueSymbols())
+      diff_summary_desc = [
+          header_template.format(
+              counts[models.DIFF_STATUS_ADDED],
+              counts[models.DIFF_STATUS_CHANGED],
+              counts[models.DIFF_STATUS_REMOVED],
+              counts[models.DIFF_STATUS_UNCHANGED],
+              unchanged_msg),
+          'Number of unique symbols {} -> {} ({:+})'.format(
+              num_unique_before_symbols, num_unique_after_symbols,
+              num_unique_after_symbols - num_unique_before_symbols),
+          ]
+      path_delta_desc = itertools.chain(
+          self._DescribeDiffObjectPaths(delta_group), ('',))
+    else:
+      diff_summary_desc = ()
+      path_delta_desc = ()
 
     group_desc = self._DescribeSymbolGroup(delta_group)
-    return itertools.chain(diff_summary_desc, path_delta_desc, ('',),
-                           group_desc)
+    return itertools.chain(diff_summary_desc, path_delta_desc, group_desc)
 
   def _DescribeDeltaSizeInfo(self, diff):
     common_metadata = {k: v for k, v in diff.before_metadata.iteritems()
@@ -415,9 +426,10 @@
   return sorted('%s=%s' % t for t in display_dict.iteritems())
 
 
-def GenerateLines(obj, verbose=False, recursive=False):
+def GenerateLines(obj, verbose=False, recursive=False, summarize=True):
   """Returns an iterable of lines (without \n) that describes |obj|."""
-  return Describer(verbose=verbose, recursive=recursive).GenerateLines(obj)
+  d = Describer(verbose=verbose, recursive=recursive, summarize=summarize)
+  return d.GenerateLines(obj)
 
 
 def WriteLines(lines, func):
diff --git a/tools/binary_size/libsupersize/main.py b/tools/binary_size/libsupersize/main.py
index 3fe14da..a289ec2 100755
--- a/tools/binary_size/libsupersize/main.py
+++ b/tools/binary_size/libsupersize/main.py
@@ -48,7 +48,18 @@
     args.output_directory = None
     args.tool_prefix = None
     args.inputs = [args.before, args.after]
-    args.query = ('Print(Diff(), verbose=%s)' % bool(args.all))
+    args.query = '\n'.join([
+        'd = Diff()',
+        'sis = canned_queries.StaticInitializers(d.symbols)',
+        'count = sis.CountsByDiffStatus()[models.DIFF_STATUS_ADDED]',
+        'count += sis.CountsByDiffStatus()[models.DIFF_STATUS_REMOVED]',
+        'if count > 0:',
+        '  print "Static Initializers Diff:"',
+        '  Print(sis, summarize=False)',
+        '  print',
+        '  print "Full diff:"',
+        'Print(d, verbose=%s)' % bool(args.all),
+    ])
     console.Run(args, parser)
 
 
@@ -64,7 +75,8 @@
       'Starts an interactive Python console for analyzing .size files.')
   actions['diff'] = (
       _DiffAction(),
-      'Shorthand for console --query "Print(Diff())"')
+      'Shorthand for console --query "Print(Diff())" (plus highlights static '
+      'initializers in diff)')
 
   for name, tup in actions.iteritems():
     sub_parser = sub_parsers.add_parser(name, help=tup[1])
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 1cafa04..a83bbfa 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -96,7 +96,6 @@
       'Linux ChromiumOS Builder': 'chromeos_with_codecs_release_bot',
       'Linux ChromiumOS Builder (dbg)': 'chromeos_with_codecs_debug_bot',
       'Linux ChromiumOS Full': 'chromeos_with_codecs_release_bot',
-      'Linux ChromiumOS Ozone Builder': 'chromeos_with_codecs_release_bot',
     },
 
     'chromium.fyi': {
@@ -187,6 +186,9 @@
       'GomaCanaryiOS': 'ios',
       'ios-simulator': 'ios',
       'Headless Linux (dbg)': 'headless_linux_debug_bot',
+      'Jumbo Linux x64': 'jumbo_release_bot',
+      'Jumbo Mac': 'jumbo_release_bot',
+      'Jumbo Win x64': 'jumbo_release_bot',
       'MD Top Chrome ChromeOS material-hybrid': 'chromeos_with_codecs_debug_bot',
       'MD Top Chrome ChromeOS non-material': 'chromeos_with_codecs_debug_bot',
       'MD Top Chrome Win material': 'debug_bot_minimal_symbols',
@@ -259,6 +261,7 @@
       'Android Release (Nexus 9)': 'android_release_trybot_arm64',
       'Android Release (NVIDIA Shield TV)': 'android_release_trybot_arm64',
       'GPU Linux Builder': 'gpu_fyi_tests_release_trybot',
+      'GPU Linux Ozone Builder': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot',
       'GPU Linux Builder (dbg)': 'gpu_fyi_tests_debug_trybot',
       'GPU Linux dEQP Builder': 'deqp_release_trybot',
       'GPU Mac Builder': 'gpu_fyi_tests_release_trybot',
@@ -271,9 +274,6 @@
       'GPU Win x64 Builder': 'gpu_fyi_tests_release_trybot',
       'GPU Win x64 Builder (dbg)': 'gpu_fyi_tests_debug_trybot',
       'GPU Win x64 dEQP Builder': 'deqp_release_no_clang_trybot',
-      'Linux ChromiumOS Builder': 'gpu_fyi_tests_chromeos_cros_release_trybot',
-      # This is, confusingly, apparently not actually building ChromiumOS.
-      'Linux ChromiumOS Ozone Builder': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot',
       'Linux GPU TSAN Release': 'gpu_fyi_tests_release_trybot_tsan',
       'Mac GPU ASAN Release': 'gpu_fyi_tests_release_trybot_asan',
     },
@@ -1368,6 +1368,10 @@
     # build files.
     'ios': [ 'error'],
 
+    'jumbo_release_bot': [
+      'jumbo', 'release_bot'
+    ],
+
     'linux_chromium_analysis': [
       'analysis'
     ],
@@ -1845,6 +1849,10 @@
       'gn_args': 'emma_coverage=true emma_filter="org.chromium.*"',
     },
 
+    'jumbo': {
+      'gn_args': 'use_jumbo_build=false',
+    },
+
     'libfuzzer': { 'gn_args': 'use_libfuzzer=true' },
 
     'lsan': {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 062b384..1840b22 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -5289,6 +5289,12 @@
   </description>
 </action>
 
+<action name="InProductHelp.NotifyEvent.IPH_Bookmark">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>The user triggered an event in in-product help.</description>
+</action>
+
 <action name="InProductHelp.NotifyEvent.IPH_DataSaverDetail">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5361,6 +5367,12 @@
   <description>The user triggered a used event in in-product help.</description>
 </action>
 
+<action name="InProductHelp.NotifyUsedEvent.IPH_Bookmark">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>The user triggered a used event in in-product help.</description>
+</action>
+
 <action name="InProductHelp.NotifyUsedEvent.IPH_DataSaverDetail">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5430,6 +5442,15 @@
   </description>
 </action>
 
+<action name="InProductHelp.ShouldTriggerHelpUI.IPH_Bookmark">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>
+    The feature engagement tracker tried to determine whether in-product help
+    should be shown to the user.
+  </description>
+</action>
+
 <action name="InProductHelp.ShouldTriggerHelpUI.IPH_DataSaverDetail">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5530,6 +5551,15 @@
 </action>
 
 <action
+    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_Bookmark">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>
+    A user action that could have triggered In-Product Help did not.
+  </description>
+</action>
+
+<action
     name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DataSaverDetail">
   <owner>nyquist@chromium.org</owner>
   <owner>xingliu@chromium.org</owner>
@@ -5625,6 +5655,12 @@
   <description>A user action triggered In-Product Help.</description>
 </action>
 
+<action name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_Bookmark">
+  <owner>nyquist@chromium.org</owner>
+  <owner>xingliu@chromium.org</owner>
+  <description>A user action triggered In-Product Help.</description>
+</action>
+
 <action
     name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DataSaverDetail">
   <owner>nyquist@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index e6bd872..12fd86439 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2484,14 +2484,14 @@
 </enum>
 
 <enum name="BadMessageReasonChrome">
-<!-- Generated from chrome/browser/bad_message.h -->
+<!-- Generated from chrome/browser/bad_message.h.-->
 
   <int value="0" label="WRLHH_LOGGING_STOPPED_BAD_STATE"/>
   <int value="1" label="PPH_EXTRA_PREVIEW_MESSAGE"/>
 </enum>
 
 <enum name="BadMessageReasonContent">
-<!-- Generated from content/browser/bad_message.h -->
+<!-- Generated from content/browser/bad_message.h.-->
 
   <int value="0" label="NC_IN_PAGE_NAVIGATION"/>
   <int value="1" label="RFH_CAN_COMMIT_URL_BLOCKED"/>
@@ -2673,10 +2673,11 @@
   <int value="175" label="SWDH_PROVIDER_CREATED_ILLEGAL_TYPE_CONTROLLER"/>
   <int value="176" label="SWDH_PROVIDER_CREATED_DUPLICATE_ID"/>
   <int value="177" label="SWDH_PROVIDER_CREATED_BAD_ID"/>
+  <int value="178" label="RFH_KEEP_ALIVE_HANDLE_REQUESTED_INCORRECTLY"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions">
-<!-- Generated from extensions/browser/bad_message.h -->
+<!-- Generated from extensions/browser/bad_message.h.-->
 
   <int value="0" label="EOG_BAD_ORIGIN"/>
   <int value="1" label="EVG_BAD_ORIGIN"/>
@@ -2692,7 +2693,7 @@
 </enum>
 
 <enum name="BadMessageReasonGuestView">
-<!-- Generated from components/guest_view/browser/bad_message.h -->
+<!-- Generated from components/guest_view/browser/bad_message.h.-->
 
   <int value="0" label="GVM_EMBEDDER_FORBIDDEN_ACCESS_TO_GUEST"/>
   <int value="1" label="GVM_INVALID_GUESTVIEW_TYPE"/>
@@ -2700,7 +2701,7 @@
 </enum>
 
 <enum name="BadMessageReasonNaCl">
-<!-- Generated from components/nacl/browser/bad_message.h -->
+<!-- Generated from components/nacl/browser/bad_message.h.-->
 
   <int value="0" label="NFH_OPEN_EXECUTABLE_BAD_ROUTING_ID"/>
   <int value="1" label="NHMF_LAUNCH_CONTINUATION_BAD_ROUTING_ID"/>
@@ -2708,7 +2709,7 @@
 </enum>
 
 <enum name="BadMessageReasonPasswordManager">
-<!-- Generated from components/password_manager/content/browser/bad_message.h -->
+<!-- Generated from components/password_manager/content/browser/bad_message.h.-->
 
   <int value="1" label="CPMD_BAD_ORIGIN_FORMS_PARSED"/>
   <int value="2" label="CPMD_BAD_ORIGIN_FORMS_RENDERED"/>
@@ -16273,6 +16274,7 @@
   <int value="2143" label="WebkitBoxLineClampManyChildren"/>
   <int value="2144" label="WebkitBoxLineClampDoesSomething"/>
   <int value="2145" label="FeaturePolicyAllowAttributeDeprecatedSyntax"/>
+  <int value="2146" label="SuppressHistoryEntryWithoutUserGesture"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -19277,7 +19279,7 @@
              AMD"/>
 </enum>
 
-<enum name="GpuImageDecodeState">
+<enum name="GpuImageUsageState">
   <int value="0" label="Wasted, once"/>
   <int value="1" label="Used, once"/>
   <int value="2" label="Wasted, relocked"/>
@@ -23017,6 +23019,8 @@
   <int value="-2043128632" label="enable-tab-switcher-in-document-mode"/>
   <int value="-2040471724" label="CrOSComponent:disabled"/>
   <int value="-2040115518" label="load-media-router-component-extension"/>
+  <int value="-2039343702"
+      label="KeepAliveRendererForKeepaliveRequests:enabled"/>
   <int value="-2036149591" label="FaviconsFromWebManifest:disabled"/>
   <int value="-2035126988" label="enabled-new-style-notification"/>
   <int value="-2033225430" label="NTPMostLikelyFaviconsFromServer:disabled"/>
@@ -23916,6 +23920,8 @@
   <int value="711424932" label="enable-cloud-print-xps"/>
   <int value="715617684" label="OriginTrials:disabled"/>
   <int value="716080990" label="restrict-iframe-permissions"/>
+  <int value="719267310"
+      label="KeepAliveRendererForKeepaliveRequests:disabled"/>
   <int value="724208771" label="TabsInCBD:enabled"/>
   <int value="730024226" label="enable-out-of-process-pdf"/>
   <int value="730750097" label="PermissionsBlacklist:disabled"/>
@@ -35116,6 +35122,9 @@
   <int value="7" label="Authentication failed with force signin">
     Signed out because credentials are invalid and force-sign-in is enabled.
   </int>
+  <int value="8" label="User turned off sync from DICE UI.">
+    User turned off sync from the Desktop Identity Consistency internals UI.
+  </int>
 </enum>
 
 <enum name="SigninSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b276cafe..8d026b9 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -7415,6 +7415,10 @@
 
 <histogram name="BrowserDialogs.ExternalProtocol.RememberCheckbox"
     enum="BooleanChecked">
+  <obsolete>
+    Deprecated 09/2017. This histogram has been replaced with
+    ExternalProtocol.HandleState.
+  </obsolete>
   <owner>dominickn@chromium.org</owner>
   <summary>
     Whether or not the user checked the option in the external protocol dialog
@@ -20966,6 +20970,44 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.DeclarativeNetRequest.IndexAndPersistRulesTime"
+    units="ms">
+  <owner>karandeepb@chromium.org</owner>
+  <summary>
+    Time taken to index and persist to disk, the deserialized json rules
+    provided by an extension manifest for the Declarative Net Request API. This
+    includes the time recorded in
+    Extensions.DeclarativeNetRequest.IndexRulesTime together with the time taken
+    to persist the ruleset to disk. This is emitted whenever an extension's json
+    ruleset is successfully indexed and persisted. This may happen when a packed
+    extension is installed, an unpacked extension is loaded, an extension's
+    ruleset is re-indexed due to corruption, etc.
+  </summary>
+</histogram>
+
+<histogram name="Extensions.DeclarativeNetRequest.IndexRulesTime" units="ms">
+  <owner>karandeepb@chromium.org</owner>
+  <summary>
+    Time taken to index the deserialized json rules provided by an extension
+    manifest for the Declarative Net Request API. This is emitted whenever an
+    extension's json ruleset is successfully indexed. This may happen when a
+    packed extension is installed, an unpacked extension is loaded, an
+    extension's ruleset is re-indexed due to corruption, etc.
+  </summary>
+</histogram>
+
+<histogram name="Extensions.DeclarativeNetRequest.ManifestRulesCount"
+    units="rules">
+  <owner>karandeepb@chromium.org</owner>
+  <summary>
+    The number of indexed declarative rules provided by an extension manifest
+    for the Declarative Net Request API. This is emitted whenever an extension's
+    json ruleset is indexed. This may happen when a packed extension is
+    installed, an unpacked extension is loaded, an extension's ruleset is re-
+    indexed, due to corruption, etc.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.DeclarativeRulesStorageInitialization" units="ms">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>Time spent until rules storage delegate gets ready.</summary>
@@ -39030,6 +39072,18 @@
   </summary>
 </histogram>
 
+<histogram name="Net.DiskCache.Size" units="MB">
+  <owner>erikchen@chromium.org</owner>
+  <summary>
+    The sum of the size of all files in the HTTP cache directory.
+
+    This is recorded on startup, and then every 24 hours afterwards. However, it
+    is only recorded for 0.1% of profiles, to reduce overhead for most users.
+    This is meant to be a temporary metric to help debug a potential HTTP cache
+    leak. We do not yet know which milestone we expect it to be removed in.
+  </summary>
+</histogram>
+
 <histogram name="Net.DNS_Resolution_And_TCP_Connection_Latency">
   <obsolete>
     Deprecated- see Net.DNS_Resolution_And_TCP_Connection_Latency2
@@ -41562,6 +41616,9 @@
 </histogram>
 
 <histogram name="Net.QuicServerInfo.DiskCacheWaitForDataReadyTime" units="ms">
+  <obsolete>
+    Deprecated as of 4/19/2017.
+  </obsolete>
   <owner>rch@chromium.org</owner>
   <summary>
     Time spent waiting to load QUIC server information from disk cache.
@@ -50672,6 +50729,22 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.Prefetching.DownloadedFileSize" units="KiB">
+  <owner>carlosk@chromium.org</owner>
+  <summary>
+    Actual size of archive file successfully downloaded by offline page
+    prefetching.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.Prefetching.DownloadExpectedFileSize" units="KiB">
+  <owner>carlosk@chromium.org</owner>
+  <summary>
+    Expected size of archive file that started being downloaded by offline page
+    prefetching.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.Prefetching.FinishedItemErrorCode"
     enum="OfflinePrefetchItemErrorCode">
   <owner>carlosk@chromium.org</owner>
@@ -61032,6 +61105,9 @@
 </histogram>
 
 <histogram name="Prerender.AbandonTimeUntilUsed" units="ms">
+  <obsolete>
+    Deprecated 2017-09 as prerenders can no longer be 'used' (=='swapped-in').
+  </obsolete>
   <owner>davidben@chromium.org</owner>
   <owner>pasko@chromium.org</owner>
   <summary>
@@ -61303,6 +61379,9 @@
 </histogram>
 
 <histogram name="Prerender.NetworkBytesUsed" units="bytes">
+  <obsolete>
+    Deprecated 2017-09 as prerenders can no longer be 'used' (=='swapped-in').
+  </obsolete>
   <owner>hajimehoshi@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
@@ -61319,7 +61398,9 @@
   <owner>kouhei@chromium.org</owner>
   <summary>
     Number of bytes transferred on the network for URLRequests (not including
-    HTTP/TLS/TCP/IP overhead) for a prerender that was not used.
+    HTTP/TLS/TCP/IP overhead) for a prerender that was not used. All
+    nostate-prefetch bytes are currently counted as wasted because it is hard to
+    track byte use in HTTP cache.
   </summary>
 </histogram>
 
@@ -61381,6 +61462,9 @@
 </histogram>
 
 <histogram name="Prerender.OmniboxNavigationsUsedPrerenderCount">
+  <obsolete>
+    Deprecated 2017-09 as prerenders can no longer be 'used' (=='swapped-in').
+  </obsolete>
   <owner>pasko@chromium.org</owner>
   <summary>
     The number of navigations that use a prerender initiated from the Omnibox.
@@ -61391,6 +61475,9 @@
 </histogram>
 
 <histogram name="Prerender.OmniboxPrerenderCount">
+  <obsolete>
+    Deprecated 2017-09.
+  </obsolete>
   <owner>pasko@chromium.org</owner>
   <summary>
     The number of prerenders initiated from the Omnibox. This is incremented
@@ -61726,6 +61813,9 @@
 </histogram>
 
 <histogram name="Prerender.PercentLoadDoneAtSwapin">
+  <obsolete>
+    Deprecated 2017-09 as prerenders can no longer be 'used' (=='swapped-in').
+  </obsolete>
   <owner>pasko@chromium.org</owner>
   <summary>
     For prerenders that are swapped in, the percentage of the time from load
@@ -61801,7 +61891,8 @@
 <histogram name="Prerender.PrerendersPerSessionCount">
   <owner>pasko@chromium.org</owner>
   <summary>
-    The number of sessions that have at least X successful prerenders.
+    The number of sessions that have at least X successful prerenders. Recorded
+    only on iOS since 2017-09.
   </summary>
 </histogram>
 
@@ -61950,11 +62041,17 @@
 </histogram>
 
 <histogram name="Prerender.TimeBetweenPrerenderRequests" units="ms">
+  <obsolete>
+    Deprecated 2017-09.
+  </obsolete>
   <owner>pasko@chromium.org</owner>
   <summary>Time between subsequent prerender requests.</summary>
 </histogram>
 
 <histogram name="Prerender.TimeSinceLastRecentVisit" units="ms">
+  <obsolete>
+    Deprecated 2017-09.
+  </obsolete>
   <owner>pasko@chromium.org</owner>
   <summary>
     The time elapsed between the most recent visit to a URL and when an
@@ -61985,6 +62082,9 @@
 </histogram>
 
 <histogram name="Prerender.TimeUntilUsed2" units="ms">
+  <obsolete>
+    Deprecated 2017-09 as prerenders can no longer be 'used' (=='swapped-in').
+  </obsolete>
   <owner>pasko@chromium.org</owner>
   <summary>
     Time from when a prerendered page is started to when it is first used due to
@@ -64447,7 +64547,7 @@
   </summary>
 </histogram>
 
-<histogram name="Renderer4.GpuImageDecodeState" enum="GpuImageDecodeState">
+<histogram name="Renderer4.GpuImageDecodeState" enum="GpuImageUsageState">
   <owner>vmpstr@chromium.org</owner>
   <summary>
     Gpu image decode usage statistics. Images are decoded and locked prior to
@@ -64465,8 +64565,29 @@
   </summary>
 </histogram>
 
+<histogram name="Renderer4.GpuImageUploadState" enum="GpuImageUsageState">
+  <owner>ericrk@chromium.org</owner>
+  <summary>
+    Gpu image upload usage statistics. Images are uploaded and locked prior to
+    use; this indicates how that upload is used during tile management.
+  </summary>
+</histogram>
+
+<histogram name="Renderer4.GpuImageUploadState.FirstLockWasted"
+    enum="BooleanWasted">
+  <owner>ericrk@chromium.org</owner>
+  <summary>
+    Indication whether the first lock of an image upload was wasted (image was
+    not used). Images are uploaded and locked prior to raster; this indicates
+    whether the upload was used or not during the first lock.
+  </summary>
+</histogram>
+
 <histogram name="Renderer4.GpuImageUploadState.FirstRefWasted"
     enum="BooleanWasted">
+  <obsolete>
+    Deprecated as of 06/2017.  No longer generated.
+  </obsolete>
   <owner>vmpstr@chromium.org</owner>
   <summary>
     Indication whether the first ref of a GPU image upload was wasted (not used
@@ -64476,6 +64597,9 @@
 </histogram>
 
 <histogram name="Renderer4.GpuImageUploadState.Used" enum="BooleanUsage">
+  <obsolete>
+    Deprecated as of 06/2017.  No longer generated.
+  </obsolete>
   <owner>vmpstr@chromium.org</owner>
   <summary>
     Indication whether the GPU image upload was used in raster. Images are
@@ -83398,6 +83522,14 @@
   </summary>
 </histogram>
 
+<histogram name="ThirdPartyModules.TimeDateStampObtained" enum="BooleanSuccess">
+  <owner>pmonette@chromium.org</owner>
+  <summary>
+    Indicates whether the TimeDateStamp for a loaded module was successfully
+    obtained.
+  </summary>
+</histogram>
+
 <histogram name="ThirdPartyModules.Uninstallable" enum="BooleanUninstallable">
   <owner>pmonette@chromium.org</owner>
   <summary>
@@ -87757,6 +87889,17 @@
   </summary>
 </histogram>
 
+<histogram name="WebApk.Install.ChromeUnimportantStorage.Fail" units="MB">
+  <owner>hanxi@chromium.org</owner>
+  <owner>ranj@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    Records the Chrome unimportant storage size when installing a WebAPK from
+    Google Play fails, with a range between 0 and 1000, round to the nearest
+    10MB.
+  </summary>
+</histogram>
+
 <histogram name="WebApk.Install.GooglePlayBindDuration" units="ms">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
@@ -95918,6 +96061,7 @@
 <histogram_suffixes name="IPHFeatures" separator=".">
   <affected-histogram name="InProductHelp.NotifyEventReadyState"/>
   <affected-histogram name="InProductHelp.ShouldTriggerHelpUI"/>
+  <suffix name="IPH_Bookmark" label="In product help bookmark."/>
   <suffix name="IPH_DataSaverPreview"
       label="In product help data saver preview."/>
   <suffix name="IPH_DataSaverDetail"
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 141af510..411fcb96 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -829,6 +829,13 @@
       The |ui::PageTransition| for the main frame navigation of this page load.
     </summary>
   </metric>
+  <metric name="Net.DownstreamKbpsEstimate.OnNavigationStart">
+    <owner>tbansal@chromium.org</owner>
+    <summary>
+      The downstream throughput (in kilobits per second) for this page load, at
+      the time the navigation for this page load was initiated.
+    </summary>
+  </metric>
   <metric name="Net.EffectiveConnectionType.OnNavigationStart">
     <obsolete>
       Deprecated 7/2017 in favor of
diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py
index e44d041..95a3950 100644
--- a/tools/perf/benchmarks/speedometer.py
+++ b/tools/perf/benchmarks/speedometer.py
@@ -18,7 +18,6 @@
 
 import os
 
-from core import path_util
 from core import perf_benchmark
 
 from telemetry import benchmark
@@ -30,10 +29,6 @@
 from metrics import keychain_metric
 
 
-_SPEEDOMETER_DIR = os.path.join(path_util.GetChromiumSrcDir(),
-    'third_party', 'WebKit', 'PerformanceTests', 'Speedometer')
-
-
 class SpeedometerMeasurement(legacy_page_test.LegacyPageTest):
   enabled_suites = [
       'VanillaJS-TodoMVC',
@@ -42,7 +37,7 @@
       'jQuery-TodoMVC',
       'AngularJS-TodoMVC',
       'React-TodoMVC',
-      'Flight-TodoMVC'
+      'FlightJS-TodoMVC'
   ]
 
   def __init__(self):
@@ -103,14 +98,18 @@
     return 'speedometer'
 
   def CreateStorySet(self, options):
-    ps = story.StorySet(base_dir=_SPEEDOMETER_DIR,
-        serving_dirs=[_SPEEDOMETER_DIR])
+    ps = story.StorySet(
+        base_dir=os.path.dirname(os.path.abspath(__file__)),
+        archive_data_file='../page_sets/data/speedometer.json',
+        cloud_storage_bucket=story.PUBLIC_BUCKET)
     ps.AddStory(page_module.Page(
-        'file://index.html', ps, ps.base_dir, name='Speedometer'))
+        'http://browserbench.org/Speedometer/', ps, ps.base_dir,
+        make_javascript_deterministic=False,
+        name='http://browserbench.org/Speedometer/'))
     return ps
 
   def GetExpectations(self):
     class StoryExpectations(story.expectations.StoryExpectations):
       def SetExpectations(self):
-        pass # Speedometer1.0 not disabled.
+        pass # http://browserbench.org/Speedometer/ not disabled.
     return StoryExpectations()
diff --git a/tools/perf/contrib/vr_benchmarks/vr_benchmarks/vr_memory.py b/tools/perf/contrib/vr_benchmarks/vr_benchmarks/vr_memory.py
deleted file mode 100644
index 11c0309a..0000000
--- a/tools/perf/contrib/vr_benchmarks/vr_benchmarks/vr_memory.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-from benchmarks import memory
-from core import perf_benchmark
-from telemetry import benchmark
-from contrib.vr_benchmarks.vr_page_sets import webvr_sample_pages
-
-
-@benchmark.Owner(emails=['bsheedy@chromium.org', 'leilei@chromium.org'])
-class WebVrMemorySamplePages(perf_benchmark.PerfBenchmark):
-  """Measures WebVR memory on an official sample page with settings tweaked."""
-
-  @classmethod
-  def AddBenchmarkCommandLineArgs(cls, parser):
-    parser.add_option('--shared-prefs-file',
-                      help='The path relative to the Chromium source root '
-                           'to a file containing a JSON list of shared '
-                           'preference files to edit and how to do so. '
-                           'See examples in //chrome/android/'
-                           'shared_preference_files/test/')
-
-  def CreateCoreTimelineBasedMeasurementOptions(self):
-    return memory.CreateCoreTimelineBasedMemoryMeasurementOptions()
-
-  def CreateStorySet(self, options):
-    return webvr_sample_pages.WebVrSamplePageSet()
-
-  def SetExtraBrowserOptions(self, options):
-    memory.SetExtraBrowserOptionsForMemoryMeasurement(options)
-    options.AppendExtraBrowserArgs(['--enable-webvr',])
-
-  @classmethod
-  def Name(cls):
-    return 'vr_memory.webvr_sample_pages'
-
-  @classmethod
-  def ValueCanBeAddedPredicate(cls, value, is_first_result):
-    return memory.DefaultValueCanBeAddedPredicateForMemoryMeasurement(value)
diff --git a/tools/perf/contrib/vr_benchmarks/vr_benchmarks/webvr.py b/tools/perf/contrib/vr_benchmarks/vr_benchmarks/webvr.py
new file mode 100644
index 0000000..adfd14e5
--- /dev/null
+++ b/tools/perf/contrib/vr_benchmarks/vr_benchmarks/webvr.py
@@ -0,0 +1,54 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from benchmarks import memory
+from core import perf_benchmark
+from telemetry import benchmark
+from telemetry.timeline import chrome_trace_category_filter
+from telemetry.timeline import chrome_trace_config
+from telemetry.web_perf import timeline_based_measurement
+from contrib.vr_benchmarks.vr_page_sets import webvr_sample_pages
+
+
+@benchmark.Owner(emails=['bsheedy@chromium.org', 'leilei@chromium.org'])
+class XrWebVrStatic(perf_benchmark.PerfBenchmark):
+  """Measures WebVR performance with sample pages."""
+
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, parser):
+    parser.add_option('--shared-prefs-file',
+                      help='The path relative to the Chromium source root '
+                           'to a file containing a JSON list of shared '
+                           'preference files to edit and how to do so. '
+                           'See examples in //chrome/android/'
+                           'shared_preference_files/test/')
+
+  def CreateCoreTimelineBasedMeasurementOptions(self):
+    memory_categories = ['blink.console', 'disabled-by-default-memory-infra']
+    gpu_categories = ['gpu']
+    category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
+        ','.join(['-*'] + memory_categories + gpu_categories))
+    options = timeline_based_measurement.Options(category_filter)
+    options.config.enable_android_graphics_memtrack = True
+    options.config.enable_platform_display_trace = True
+
+    options.SetTimelineBasedMetrics(['memoryMetric', 'webvrMetric'])
+    options.config.chrome_trace_config.SetMemoryDumpConfig(
+        chrome_trace_config.MemoryDumpConfig())
+    return options
+
+  def CreateStorySet(self, options):
+    return webvr_sample_pages.WebVrSamplePageSet()
+
+  def SetExtraBrowserOptions(self, options):
+    memory.SetExtraBrowserOptionsForMemoryMeasurement(options)
+    options.AppendExtraBrowserArgs(['--enable-webvr',])
+
+  @classmethod
+  def Name(cls):
+    return 'xr.webvr.static'
+
+  @classmethod
+  def ValueCanBeAddedPredicate(cls, value, is_first_result):
+    return memory.DefaultValueCanBeAddedPredicateForMemoryMeasurement(value)
diff --git a/tools/perf/page_sets/data/speedometer.json b/tools/perf/page_sets/data/speedometer.json
new file mode 100644
index 0000000..c6912cf3c
--- /dev/null
+++ b/tools/perf/page_sets/data/speedometer.json
@@ -0,0 +1,9 @@
+{
+    "archives": {
+        "http://browserbench.org/Speedometer/": {
+            "DEFAULT": "speedometer_000.wprgo"
+        }
+    },
+    "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
+    "platform_specific": true
+}
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/speedometer_000.wprgo.sha1 b/tools/perf/page_sets/data/speedometer_000.wprgo.sha1
new file mode 100644
index 0000000..13e4893
--- /dev/null
+++ b/tools/perf/page_sets/data/speedometer_000.wprgo.sha1
@@ -0,0 +1 @@
+962642b357699cdf4aca5c51ea37f9a3faec339d
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/README.md b/tools/perf/page_sets/static_top_25/README.md
new file mode 100644
index 0000000..765bca4
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/README.md
@@ -0,0 +1,41 @@
+This directory contains static html snapshots of top trafficked web
+sites. The URL list is:
+
+https://www.google.com/search?q=barack+obama
+https://mail.google.com/mail/ (logged in)
+https://www.google.com/calendar/ (logged in)
+https://www.google.com/search?q=cats&tbm=isch (logged in)
+https://docs.google.com/document/d/1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view (logged in)
+https://plus.google.com/110031535020051778989/posts (logged in)
+http://www.youtube.com (logged in)
+http://googlewebmastercentral.blogspot.com/
+http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/
+https://www.facebook.com/barackobama
+http://www.linkedin.com/in/linustorvalds
+http://en.wikipedia.org/wiki/Wikipedia
+https://twitter.com/katyperry
+http://pinterest.com
+http://espn.go.com
+http://www.weather.com/weather/right-now/Mountain+View+CA+94043
+http://games.yahoo.com
+http://news.yahoo.com
+http://www.cnn.com
+http://www.amazon.com
+http://www.ebay.com
+http://booking.com
+http://answers.yahoo.com
+http://sports.yahoo.com/
+http://techcrunch.com
+
+Where "logged in" is noted, we use the "googletest" credentials.
+
+Typical command to snapshot a static page:
+
+% ./third_party/catapult/telemetry/bin/snap_page --browser=system \
+    --url='https://www.cnn.com' --snapshot-path=cnn.html
+
+For a logged in page where one must log in before snapshotting, use
+the "--interactive" flag:
+
+% ./third_party/catapult/telemetry/bin/snap_page --browser=system \
+    --url='https://www.youtube.com' --snapshot-path=youtube.html --interactive
diff --git a/tools/perf/page_sets/static_top_25/amazon.html.sha1 b/tools/perf/page_sets/static_top_25/amazon.html.sha1
new file mode 100644
index 0000000..9d59ec9b
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/amazon.html.sha1
@@ -0,0 +1 @@
+1f6cd63e131eb05297368c99b2eddf52eb2ac06c
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/blogger.html.sha1 b/tools/perf/page_sets/static_top_25/blogger.html.sha1
new file mode 100644
index 0000000..35c1a50
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/blogger.html.sha1
@@ -0,0 +1 @@
+c2f8a8fdbf1136c4d9db7441f61a6b84c2a04ee5
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/booking.html.sha1 b/tools/perf/page_sets/static_top_25/booking.html.sha1
new file mode 100644
index 0000000..e2ebbc6c
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/booking.html.sha1
@@ -0,0 +1 @@
+43c29ac02819a7912b913529fd4c5609193a92e2
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/cnn.html.sha1 b/tools/perf/page_sets/static_top_25/cnn.html.sha1
new file mode 100644
index 0000000..d25e389
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/cnn.html.sha1
@@ -0,0 +1 @@
+14d02366717a65fa15480a7dfaae3c326c19f7b2
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/ebay.html.sha1 b/tools/perf/page_sets/static_top_25/ebay.html.sha1
new file mode 100644
index 0000000..6df8bbd
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/ebay.html.sha1
@@ -0,0 +1 @@
+e3be589e841ecc734b50fbcc6d4b84abaa5595b2
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/espn.html.sha1 b/tools/perf/page_sets/static_top_25/espn.html.sha1
new file mode 100644
index 0000000..f3d321e
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/espn.html.sha1
@@ -0,0 +1 @@
+edc07f6230a3a929cd11bb4c8040a4e6eb3641df
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/facebook.html.sha1 b/tools/perf/page_sets/static_top_25/facebook.html.sha1
new file mode 100644
index 0000000..c605acb
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/facebook.html.sha1
@@ -0,0 +1 @@
+30312217b846c9966516bb24b2152ddd07715fb7
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/gmail.html.sha1 b/tools/perf/page_sets/static_top_25/gmail.html.sha1
new file mode 100644
index 0000000..1089148a
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/gmail.html.sha1
@@ -0,0 +1 @@
+69b69015744c9df7ad637defed244d2667bb6793
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/google.html.sha1 b/tools/perf/page_sets/static_top_25/google.html.sha1
new file mode 100644
index 0000000..8b484ac1
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/google.html.sha1
@@ -0,0 +1 @@
+298f5f8c4b1cea174a4e6277de9a1a766481ce87
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/googlecalendar.html.sha1 b/tools/perf/page_sets/static_top_25/googlecalendar.html.sha1
new file mode 100644
index 0000000..deec326d
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/googlecalendar.html.sha1
@@ -0,0 +1 @@
+5d25c7d4cb2b67674e9ed3dec76bce8c66af6933
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/googledocs.html.sha1 b/tools/perf/page_sets/static_top_25/googledocs.html.sha1
new file mode 100644
index 0000000..a64adab3
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/googledocs.html.sha1
@@ -0,0 +1 @@
+6773f5b595e30b3a0b55b6ef4f530595537feb00
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/googleimagesearch.html.sha1 b/tools/perf/page_sets/static_top_25/googleimagesearch.html.sha1
new file mode 100644
index 0000000..cb21fac
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/googleimagesearch.html.sha1
@@ -0,0 +1 @@
+d54b560e6847ee6950efd826db8dda07d7d505ef
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/googleplus.html.sha1 b/tools/perf/page_sets/static_top_25/googleplus.html.sha1
new file mode 100644
index 0000000..28b4371
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/googleplus.html.sha1
@@ -0,0 +1 @@
+e8cac04d2c352477be488cf551de2d29b58117cf
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/linkedin.html.sha1 b/tools/perf/page_sets/static_top_25/linkedin.html.sha1
new file mode 100644
index 0000000..64ebb7cd
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/linkedin.html.sha1
@@ -0,0 +1 @@
+4c8ad3b9ab226e899d1b876541f423c310664bd8
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/pinterest.html.sha1 b/tools/perf/page_sets/static_top_25/pinterest.html.sha1
new file mode 100644
index 0000000..718e07f4
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/pinterest.html.sha1
@@ -0,0 +1 @@
+e5aaf7a65c8e59f0ccb4c31e69c2f42a03a17b42
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/techcrunch.html.sha1 b/tools/perf/page_sets/static_top_25/techcrunch.html.sha1
new file mode 100644
index 0000000..45cb588
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/techcrunch.html.sha1
@@ -0,0 +1 @@
+f33ba5e5125e1bcf43b18bdcb7be8c3d7202f660
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/twitter.html.sha1 b/tools/perf/page_sets/static_top_25/twitter.html.sha1
new file mode 100644
index 0000000..befe78c
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/twitter.html.sha1
@@ -0,0 +1 @@
+12530420d1ad623242d1f95b6f8719815b9de409
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/weather.html.sha1 b/tools/perf/page_sets/static_top_25/weather.html.sha1
new file mode 100644
index 0000000..7e840d83
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/weather.html.sha1
@@ -0,0 +1 @@
+0ce64c55798dbbb313eb4ab65a2d657edc80ef15
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/wikipedia.html.sha1 b/tools/perf/page_sets/static_top_25/wikipedia.html.sha1
new file mode 100644
index 0000000..cb1c4fa
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/wikipedia.html.sha1
@@ -0,0 +1 @@
+303d4798a1df4bb476e55787a74d688ec30a7f4f
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/wordpress.html.sha1 b/tools/perf/page_sets/static_top_25/wordpress.html.sha1
new file mode 100644
index 0000000..5f18a25
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/wordpress.html.sha1
@@ -0,0 +1 @@
+eb4a0b448824929ee6e84a3d5ba2d8d03450af0a
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/yahooanswers.html.sha1 b/tools/perf/page_sets/static_top_25/yahooanswers.html.sha1
new file mode 100644
index 0000000..39fdd95
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/yahooanswers.html.sha1
@@ -0,0 +1 @@
+acdf9fa9ed9e958590c08d3411b2ac32117ccc4a
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/yahoogames.html.sha1 b/tools/perf/page_sets/static_top_25/yahoogames.html.sha1
new file mode 100644
index 0000000..930a7ac
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/yahoogames.html.sha1
@@ -0,0 +1 @@
+8d6b8a9673468a35dea320de36bc9b6e4cdc7116
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/yahoonews.html.sha1 b/tools/perf/page_sets/static_top_25/yahoonews.html.sha1
new file mode 100644
index 0000000..52da153
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/yahoonews.html.sha1
@@ -0,0 +1 @@
+9bf26870f7cb0a859347f3d46248d5bd92ac045f
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/yahoosports.html.sha1 b/tools/perf/page_sets/static_top_25/yahoosports.html.sha1
new file mode 100644
index 0000000..79e7d01c
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/yahoosports.html.sha1
@@ -0,0 +1 @@
+b9ca4ef35990010023b4812ceb12e0d47e6013de
\ No newline at end of file
diff --git a/tools/perf/page_sets/static_top_25/youtube.html.sha1 b/tools/perf/page_sets/static_top_25/youtube.html.sha1
new file mode 100644
index 0000000..f3205f3
--- /dev/null
+++ b/tools/perf/page_sets/static_top_25/youtube.html.sha1
@@ -0,0 +1 @@
+d8f69b54741ba0e8f84428fbd024f8e3a1968840
\ No newline at end of file
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py
index f7e2edd..14932dcd 100644
--- a/tools/perf/page_sets/system_health/expectations.py
+++ b/tools/perf/page_sets/system_health/expectations.py
@@ -93,8 +93,6 @@
     self.DisableStory('long_running:tools:gmail-background',
                       [expectations.ANDROID_WEBVIEW],
                       'Webview does not have tabs')
-    self.DisableStory('browse:social:facebook_infinite_scroll',
-                      [expectations.ALL_ANDROID], 'crbug.com/760319')
     self.DisableStory('browse:shopping:avito',
                       [expectations.ANDROID_NEXUS6], 'crbug.com/736497')
     self.DisableStory('browse:social:pinterest_infinite_scroll',
@@ -117,8 +115,6 @@
                       [expectations.ALL_ANDROID], 'crbug.com/726301')
     self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID],
                       'crbug.com/728081')
-    self.DisableStory('browse:social:facebook_infinite_scroll',
-                      [expectations.ALL_ANDROID], 'crbug.com/760319')
     self.DisableStory(
         'load:tools:drive',
         [expectations.ANDROID_NEXUS5X, expectations.ANDROID_WEBVIEW],
@@ -176,8 +172,6 @@
                       'Webview does not have NTP')
     self.DisableStory('browse:social:pinterest_infinite_scroll',
                       [expectations.ANDROID_WEBVIEW], 'crbug.com/728528')
-    self.DisableStory('browse:social:facebook_infinite_scroll',
-                      [expectations.ALL_ANDROID], 'crbug.com/760319')
 
 
 class SystemHealthWebviewStartupExpectations(expectations.StoryExpectations):
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 2492065..8d5cf9e3 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -311,6 +311,13 @@
     activate,
     check,
     click,
+
+    // A click will be performed on one of the node's ancestors.
+    // This happens when the node itself is not clickable, but one of its
+    // ancestors has click handlers attached which are able to capture the click
+    // as it bubbles up.
+    click_ancestor,
+
     jump,
     open,
     press,
diff --git a/ui/accessibility/ax_text_utils.cc b/ui/accessibility/ax_text_utils.cc
index 67ca764..fd045776 100644
--- a/ui/accessibility/ax_text_utils.cc
+++ b/ui/accessibility/ax_text_utils.cc
@@ -126,6 +126,8 @@
       return l10n_util::GetStringUTF16(IDS_AX_CHECK_ACTION_VERB);
     case AX_DEFAULT_ACTION_VERB_CLICK:
       return l10n_util::GetStringUTF16(IDS_AX_CLICK_ACTION_VERB);
+    case AX_DEFAULT_ACTION_VERB_CLICK_ANCESTOR:
+      return l10n_util::GetStringUTF16(IDS_AX_CLICK_ANCESTOR_ACTION_VERB);
     case AX_DEFAULT_ACTION_VERB_JUMP:
       return l10n_util::GetStringUTF16(IDS_AX_JUMP_ACTION_VERB);
     case AX_DEFAULT_ACTION_VERB_OPEN:
@@ -153,6 +155,8 @@
       return base::UTF8ToUTF16("check");
     case ui::AX_DEFAULT_ACTION_VERB_CLICK:
       return base::UTF8ToUTF16("click");
+    case ui::AX_DEFAULT_ACTION_VERB_CLICK_ANCESTOR:
+      return base::UTF8ToUTF16("click-ancestor");
     case ui::AX_DEFAULT_ACTION_VERB_JUMP:
       return base::UTF8ToUTF16("jump");
     case ui::AX_DEFAULT_ACTION_VERB_OPEN:
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index abdf04b..391e27d 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -463,4 +463,51 @@
   return 1;
 }
 
+bool AXPlatformNodeBase::IsLeaf() {
+  if (GetChildCount() == 0)
+    return true;
+
+  // These types of objects may have children that we use as internal
+  // implementation details, but we want to expose them as leaves to platform
+  // accessibility APIs because screen readers might be confused if they find
+  // any children.
+  // Note that if a combo box, search box or text field are not native, they
+  // might present a menu of choices using aria-owns which should not be hidden
+  // from tree.
+  if (IsNativeTextControl() || IsTextOnlyObject())
+    return true;
+
+  // Roles whose children are only presentational according to the ARIA and
+  // HTML5 Specs should be hidden from screen readers.
+  // (Note that whilst ARIA buttons can have only presentational children, HTML5
+  // buttons are allowed to have content.)
+  switch (GetData().role) {
+    case ui::AX_ROLE_IMAGE:
+    case ui::AX_ROLE_METER:
+    case ui::AX_ROLE_SCROLL_BAR:
+    case ui::AX_ROLE_SLIDER:
+    case ui::AX_ROLE_SPLITTER:
+    case ui::AX_ROLE_PROGRESS_INDICATOR:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool AXPlatformNodeBase::IsChildOfLeaf() {
+  AXPlatformNodeBase* ancestor = FromNativeViewAccessible(GetParent());
+
+  while (ancestor) {
+    if (ancestor->IsLeaf())
+      return true;
+    ancestor = FromNativeViewAccessible(ancestor->GetParent());
+  }
+
+  return false;
+}
+
+base::string16 AXPlatformNodeBase::GetText() {
+  return GetInnerText();
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 1481ed97..5f2cf620 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -113,6 +113,22 @@
   // this cell spans. If not a cell, returns 0.
   int GetTableRowSpan() const;
 
+  // Returns true if an ancestor of this node (not including itself) is a
+  // leaf node, meaning that this node is not actually exposed to the
+  // platform.
+  bool IsChildOfLeaf();
+
+  // Returns true if this is a leaf node on this platform, meaning any
+  // children should not be exposed to this platform's native accessibility
+  // layer. Each platform subclass should implement this itself.
+  // The definition of a leaf may vary depending on the platform,
+  // but a leaf node should never have children that are focusable or
+  // that might send notifications.
+  bool IsLeaf();
+
+  // TODO(dougt) Maybe promote this to AXPlatformNode at some point.
+  virtual base::string16 GetText();
+
   //
   // Delegate.  This is a weak reference which owns |this|.
   //
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 57db017..d2edbd88 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -610,10 +610,15 @@
         return index - 1;
     }
   }
-
   return -1;
 }
 
+base::string16 AXPlatformNodeWin::GetText() {
+  if (IsChildOfLeaf())
+    return AXPlatformNodeBase::GetText();
+  return hypertext_;
+}
+
 //
 // IAccessible implementation.
 //
@@ -1323,7 +1328,7 @@
   *similar_items_in_group = GetIntAttribute(ui::AX_ATTR_SET_SIZE);
   *position_in_group = GetIntAttribute(ui::AX_ATTR_POS_IN_SET);
 
-  if (*group_level == *similar_items_in_group == *position_in_group == 0)
+  if (!*group_level && !*similar_items_in_group && !*position_in_group)
     return S_FALSE;
   return S_OK;
 }
@@ -1350,14 +1355,69 @@
 }
 
 STDMETHODIMP AXPlatformNodeWin::scrollTo(enum IA2ScrollType scroll_type) {
-  return E_NOTIMPL;
+  COM_OBJECT_VALIDATE();
+  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IA2_SCROLL_TO);
+
+  gfx::Rect r = delegate_->GetScreenBoundsRect();
+  switch (scroll_type) {
+    case IA2_SCROLL_TYPE_TOP_LEFT:
+      r = gfx::Rect(r.x(), r.y(), 0, 0);
+      break;
+    case IA2_SCROLL_TYPE_BOTTOM_RIGHT:
+      r = gfx::Rect(r.right(), r.bottom(), 0, 0);
+      break;
+    case IA2_SCROLL_TYPE_TOP_EDGE:
+      r = gfx::Rect(r.x(), r.y(), r.width(), 0);
+      break;
+    case IA2_SCROLL_TYPE_BOTTOM_EDGE:
+      r = gfx::Rect(r.x(), r.bottom(), r.width(), 0);
+      break;
+    case IA2_SCROLL_TYPE_LEFT_EDGE:
+      r = gfx::Rect(r.x(), r.y(), 0, r.height());
+      break;
+    case IA2_SCROLL_TYPE_RIGHT_EDGE:
+      r = gfx::Rect(r.right(), r.y(), 0, r.height());
+      break;
+    case IA2_SCROLL_TYPE_ANYWHERE:
+    default:
+      break;
+  }
+
+  ui::AXActionData action_data;
+  action_data.target_node_id = GetData().id;
+  action_data.action = ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE;
+  action_data.target_rect = r;
+  delegate_->AccessibilityPerformAction(action_data);
+  return S_OK;
 }
 
 STDMETHODIMP AXPlatformNodeWin::scrollToPoint(
     enum IA2CoordinateType coordinate_type,
     LONG x,
     LONG y) {
-  return E_NOTIMPL;
+  COM_OBJECT_VALIDATE();
+
+  WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_SCROLL_TO_POINT);
+
+  gfx::Point scroll_to(x, y);
+
+  if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
+    scroll_to -= delegate_->GetScreenBoundsRect().OffsetFromOrigin();
+  } else if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
+    if (GetParent()) {
+      AXPlatformNodeBase* base = FromNativeViewAccessible(GetParent());
+      scroll_to += base->delegate_->GetScreenBoundsRect().OffsetFromOrigin();
+    }
+  } else {
+    return E_INVALIDARG;
+  }
+
+  ui::AXActionData action_data;
+  action_data.target_node_id = GetData().id;
+  action_data.action = ui::AX_ACTION_SCROLL_TO_POINT;
+  action_data.target_point = scroll_to;
+  delegate_->AccessibilityPerformAction(action_data);
+  return S_OK;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_nExtendedStates(LONG* n_extended_states) {
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index ecf7e80..87bf0d0 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -286,6 +286,7 @@
   // AXPlatformNodeBase overrides.
   void Destroy() override;
   int GetIndexInParent() override;
+  base::string16 GetText() override;
 
   //
   // IAccessible methods.
@@ -650,6 +651,22 @@
   // AXPlatformNodeBase overrides.
   void Dispose() override;
 
+  // Maps an embedded character offset in |hypertext_| to an index in
+  // |hyperlinks_|.
+  std::map<int32_t, int32_t> old_hyperlink_offset_to_index_;
+  std::map<int32_t, int32_t> hyperlink_offset_to_index_;
+
+  // The unique id of a AXPlatformNodes for each hyperlink.
+  // TODO(nektar): Replace object IDs with child indices if we decide that
+  // we are not implementing IA2 hyperlinks for anything other than IA2
+  // Hypertext.
+  std::vector<int32_t> old_hyperlinks_;
+  std::vector<int32_t> hyperlinks_;
+
+  // Hypertext.
+  base::string16 old_hypertext_;
+  base::string16 hypertext_;
+
  private:
   int32_t unique_id_;
 
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 8fcf2ee..438e8dc 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -972,6 +972,101 @@
   }
 }
 
+TEST_F(AXPlatformNodeWinTest, TestIAccessible2ScrollToPoint) {
+  AXNodeData root;
+  root.id = 1;
+  root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+  root.location = gfx::RectF(0, 0, 2000, 2000);
+
+  AXNodeData child1;
+  child1.id = 2;
+  child1.role = AX_ROLE_STATIC_TEXT;
+  child1.location = gfx::RectF(10, 10, 10, 10);
+  root.child_ids.push_back(2);
+
+  Init(root, child1);
+
+  ScopedComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
+  ScopedComPtr<IDispatch> result;
+  EXPECT_EQ(S_OK, root_iaccessible->get_accChild(ScopedVariant(1),
+                                                 result.GetAddressOf()));
+  ScopedComPtr<IAccessible2> ax_child1;
+  EXPECT_EQ(S_OK, result.CopyTo(ax_child1.GetAddressOf()));
+  result.Reset();
+
+  LONG x_left, y_top, width, height;
+  EXPECT_EQ(S_OK,
+            ax_child1->accLocation(&x_left, &y_top, &width, &height, SELF));
+  EXPECT_EQ(10, x_left);
+  EXPECT_EQ(10, y_top);
+  EXPECT_EQ(10, width);
+  EXPECT_EQ(10, height);
+
+  ScopedComPtr<IAccessible2> root_iaccessible2 =
+      ToIAccessible2(root_iaccessible);
+  EXPECT_EQ(S_OK, root_iaccessible2->scrollToPoint(
+                      IA2_COORDTYPE_SCREEN_RELATIVE, 600, 650));
+
+  EXPECT_EQ(S_OK,
+            ax_child1->accLocation(&x_left, &y_top, &width, &height, SELF));
+  EXPECT_EQ(610, x_left);
+  EXPECT_EQ(610, y_top);
+  EXPECT_EQ(10, width);
+  EXPECT_EQ(10, height);
+
+  EXPECT_EQ(S_OK, root_iaccessible2->scrollToPoint(
+                      IA2_COORDTYPE_PARENT_RELATIVE, 0, 0));
+
+  EXPECT_EQ(S_OK,
+            ax_child1->accLocation(&x_left, &y_top, &width, &height, SELF));
+  EXPECT_EQ(10, x_left);
+  EXPECT_EQ(10, y_top);
+  EXPECT_EQ(10, width);
+  EXPECT_EQ(10, height);
+}
+
+TEST_F(AXPlatformNodeWinTest, TestIAccessible2ScrollTo) {
+  AXNodeData root;
+  root.id = 1;
+  root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+  root.location = gfx::RectF(0, 0, 2000, 2000);
+
+  AXNodeData child1;
+  child1.id = 2;
+  child1.role = AX_ROLE_STATIC_TEXT;
+  child1.location = gfx::RectF(10, 10, 10, 10);
+  root.child_ids.push_back(2);
+
+  Init(root, child1);
+
+  ScopedComPtr<IAccessible> root_iaccessible(GetRootIAccessible());
+  ScopedComPtr<IDispatch> result;
+  EXPECT_EQ(S_OK, root_iaccessible->get_accChild(ScopedVariant(1),
+                                                 result.GetAddressOf()));
+  ScopedComPtr<IAccessible2> ax_child1;
+  EXPECT_EQ(S_OK, result.CopyTo(ax_child1.GetAddressOf()));
+  result.Reset();
+
+  LONG x_left, y_top, width, height;
+  EXPECT_EQ(S_OK,
+            ax_child1->accLocation(&x_left, &y_top, &width, &height, SELF));
+  EXPECT_EQ(10, x_left);
+  EXPECT_EQ(10, y_top);
+  EXPECT_EQ(10, width);
+  EXPECT_EQ(10, height);
+
+  ScopedComPtr<IAccessible2> root_iaccessible2 =
+      ToIAccessible2(root_iaccessible);
+  EXPECT_EQ(S_OK, ax_child1->scrollTo(IA2_SCROLL_TYPE_ANYWHERE));
+
+  EXPECT_EQ(S_OK,
+            ax_child1->accLocation(&x_left, &y_top, &width, &height, SELF));
+  EXPECT_EQ(20, x_left);
+  EXPECT_EQ(20, y_top);
+  EXPECT_EQ(10, width);
+  EXPECT_EQ(10, height);
+}
+
 TEST_F(AXPlatformNodeWinTest, TestIAccessibleTableGetChildIndex) {
   Init(Build3X3Table());
 
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index 0ec21d1..d60d44c 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -175,7 +175,12 @@
   return gfx::kNullAcceleratedWidget;
 }
 
-bool TestAXNodeWrapper::AccessibilityPerformAction(const AXActionData& data) {
+bool TestAXNodeWrapper::AccessibilityPerformAction(
+    const ui::AXActionData& data) {
+  if (data.action == ui::AX_ACTION_SCROLL_TO_POINT)
+    g_offset = gfx::Vector2d(data.target_point.x(), data.target_point.x());
+  else if (data.action == ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE)
+    g_offset = gfx::Vector2d(data.target_rect.x(), data.target_rect.x());
   return true;
 }
 
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index cbf034c..2b13b35 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -61,6 +61,7 @@
     "//components/viz/common",
     "//components/viz/host",
     "//components/viz/service",
+    "//services/viz/public/interfaces",
     "//skia",
     "//third_party/WebKit/public:blink_headers",
     "//ui/base",
diff --git a/ui/app_list/presenter/app_list.cc b/ui/app_list/presenter/app_list.cc
index be14bb0..0f4a6ef 100644
--- a/ui/app_list/presenter/app_list.cc
+++ b/ui/app_list/presenter/app_list.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "base/metrics/histogram_macros.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/presenter/app_list_delegate.h"
 
 namespace app_list {
@@ -22,9 +24,12 @@
   return presenter_.get();
 }
 
-void AppList::Show(int64_t display_id) {
-  if (presenter_)
+void AppList::Show(int64_t display_id, AppListShowSource show_source) {
+  if (presenter_) {
+    UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
+                              show_source, app_list::kMaxAppListToggleMethod);
     presenter_->Show(display_id);
+  }
 }
 
 void AppList::UpdateYPositionAndOpacity(int y_position_in_screen,
@@ -45,9 +50,14 @@
     presenter_->Dismiss();
 }
 
-void AppList::ToggleAppList(int64_t display_id) {
-  if (presenter_)
+void AppList::ToggleAppList(int64_t display_id, AppListShowSource show_source) {
+  if (presenter_) {
+    if (!IsVisible()) {
+      UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
+                                show_source, app_list::kMaxAppListToggleMethod);
+    }
     presenter_->ToggleAppList(display_id);
+  }
 }
 
 void AppList::StartVoiceInteractionSession() {
diff --git a/ui/app_list/presenter/app_list.h b/ui/app_list/presenter/app_list.h
index 311442c4..11bfc3e 100644
--- a/ui/app_list/presenter/app_list.h
+++ b/ui/app_list/presenter/app_list.h
@@ -6,6 +6,7 @@
 #define UI_APP_LIST_PRESENTER_APP_LIST_H_
 
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/presenter/app_list_presenter.mojom.h"
 #include "ui/app_list/presenter/app_list_presenter_export.h"
 
@@ -26,12 +27,12 @@
   mojom::AppListPresenter* GetAppListPresenter();
 
   // Helper functions to call the underlying functionality on the presenter.
-  void Show(int64_t display_id);
+  void Show(int64_t display_id, AppListShowSource show_source);
   void UpdateYPositionAndOpacity(int y_position_in_screen,
                                  float background_opacity);
   void EndDragFromShelf(mojom::AppListState app_list_state);
   void Dismiss();
-  void ToggleAppList(int64_t display_id);
+  void ToggleAppList(int64_t display_id, AppListShowSource show_source);
   void StartVoiceInteractionSession();
   void ToggleVoiceInteractionSession();
 
diff --git a/ui/app_list/presenter/app_list_presenter_impl.cc b/ui/app_list/presenter/app_list_presenter_impl.cc
index 91afc03..7664b54 100644
--- a/ui/app_list/presenter/app_list_presenter_impl.cc
+++ b/ui/app_list/presenter/app_list_presenter_impl.cc
@@ -54,8 +54,11 @@
 }
 
 void AppListPresenterImpl::Show(int64_t display_id) {
-  if (is_visible_)
+  if (is_visible_) {
+    if (display_id != GetDisplayId())
+      Dismiss();
     return;
+  }
 
   is_visible_ = true;
   if (app_list_) {
@@ -131,6 +134,9 @@
 
 void AppListPresenterImpl::UpdateYPositionAndOpacity(int y_position_in_screen,
                                                      float background_opacity) {
+  if (!is_visible_)
+    return;
+
   if (view_)
     view_->UpdateYPositionAndOpacity(y_position_in_screen, background_opacity);
 }
diff --git a/ui/app_list/views/suggestions_container_view.cc b/ui/app_list/views/suggestions_container_view.cc
index c86ac21..4a47fa4 100644
--- a/ui/app_list/views/suggestions_container_view.cc
+++ b/ui/app_list/views/suggestions_container_view.cc
@@ -92,6 +92,11 @@
       item = display_results[i];
     search_result_tile_views_[i]->SetSearchResult(item);
     search_result_tile_views_[i]->SetEnabled(true);
+
+    // Notify text change after accessible name is updated and the tile view
+    // is re-enabled, so that ChromeVox will announce the updated text.
+    search_result_tile_views_[i]->NotifyAccessibilityEvent(
+        ui::AX_EVENT_TEXT_CHANGED, true);
   }
 
   parent()->Layout();
diff --git a/ui/aura/mus/window_tree_client_unittest.cc b/ui/aura/mus/window_tree_client_unittest.cc
index 9fb47c7..50a97118 100644
--- a/ui/aura/mus/window_tree_client_unittest.cc
+++ b/ui/aura/mus/window_tree_client_unittest.cc
@@ -1085,11 +1085,12 @@
   // child1 has a custom targeter set which would always return itself as the
   // target window therefore event should go to child1.
   const gfx::Point event_location(50, 60);
+  const gfx::Point root_location;
   uint32_t event_id = 1;
   window_delegate1->set_event_id(event_id);
   window_delegate2->set_event_id(event_id);
   std::unique_ptr<ui::Event> ui_event(
-      new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location, gfx::Point(),
+      new ui::MouseEvent(ui::ET_MOUSE_MOVED, event_location, root_location,
                          ui::EventTimeForNow(), ui::EF_NONE, 0));
   window_tree_client()->OnWindowInputEvent(
       event_id, server_id(child1.get()), window_tree_host->display_id(),
@@ -1103,7 +1104,9 @@
   window_delegate1->reset();
   window_delegate2->reset();
 
-  // The same event should go to child2 if child2 is the capture window.
+  // Set capture to |child2|. Capture takes precedence, and because the event is
+  // converted local coordinates are converted from the original target to root
+  // and then to capture target.
   std::unique_ptr<client::DefaultCaptureClient> capture_client(
       base::MakeUnique<client::DefaultCaptureClient>());
   client::SetCaptureClient(top_level, capture_client.get());
@@ -1120,7 +1123,10 @@
             window_tree()->GetEventResult(event_id));
   EXPECT_EQ(0, window_delegate1->move_count());
   EXPECT_EQ(1, window_delegate2->move_count());
-  EXPECT_EQ(gfx::Point(30, 30), window_delegate2->last_event_location());
+  gfx::Point location_in_child2(event_location);
+  Window::ConvertPointToTarget(child1.get(), top_level, &location_in_child2);
+  Window::ConvertPointToTarget(top_level, child2.get(), &location_in_child2);
+  EXPECT_EQ(location_in_child2, window_delegate2->last_event_location());
   child2.reset();
   child1.reset();
   window_tree_host.reset();
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc
index 9b3aa8fe..f1e7b29 100644
--- a/ui/aura/window_event_dispatcher.cc
+++ b/ui/aura/window_event_dispatcher.cc
@@ -443,6 +443,45 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // WindowEventDispatcher, ui::EventProcessor implementation:
+
+ui::EventTarget* WindowEventDispatcher::GetInitialEventTarget(
+    ui::Event* event) {
+  if (Env::GetInstance()->mode() == Env::Mode::LOCAL ||
+      !event->IsLocatedEvent() || !event->target()) {
+    return nullptr;
+  }
+
+  ui::LocatedEvent* located_event = event->AsLocatedEvent();
+
+  Window* priority_target = static_cast<Window*>(
+      event_targeter_->GetPriorityTargetInRootWindow(window(), *located_event));
+  if (!priority_target)
+    return nullptr;
+
+  Window* original_target = static_cast<Window*>(event->target());
+
+  // The event has a target but we need to dispatch it using the normal path.
+  // Reset the target and location so the normal flow is used.
+  const gfx::PointF original_location = located_event->location_f();
+  ui::Event::DispatcherApi(event).set_target(nullptr);
+  located_event->set_location_f(located_event->root_location_f());
+  if (event_targeter_->ProcessEventIfTargetsDifferentRootWindow(
+          window(), static_cast<Window*>(priority_target), event)) {
+    // Make sure the event was marked handled so that EventProcessor doesn't
+    // attempt to process the event as well.
+    event->SetHandled();
+    return nullptr;
+  }
+  located_event->set_location_f(original_location);
+  if (original_target != priority_target) {
+    // Don't convert from the root as it may be offset by the bounds of the
+    // root's host.
+    located_event->ConvertLocationToTarget(original_target, window());
+    located_event->ConvertLocationToTarget(window(), priority_target);
+  }
+  return priority_target;
+}
+
 ui::EventTarget* WindowEventDispatcher::GetRootForEvent(ui::Event* event) {
   if (Env::GetInstance()->mode() == Env::Mode::LOCAL)
     return window();
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h
index 9bd63a7..e3ee61c 100644
--- a/ui/aura/window_event_dispatcher.h
+++ b/ui/aura/window_event_dispatcher.h
@@ -184,6 +184,7 @@
   void ReleaseNativeCapture() override;
 
   // Overridden from ui::EventProcessor:
+  ui::EventTarget* GetInitialEventTarget(ui::Event* event) override;
   ui::EventTarget* GetRootForEvent(ui::Event* event) override;
   void OnEventProcessingStarted(ui::Event* event) override;
   void OnEventProcessingFinished(ui::Event* event) override;
diff --git a/ui/aura/window_event_dispatcher_unittest.cc b/ui/aura/window_event_dispatcher_unittest.cc
index 2f5e9f1..69240f88 100644
--- a/ui/aura/window_event_dispatcher_unittest.cc
+++ b/ui/aura/window_event_dispatcher_unittest.cc
@@ -32,6 +32,7 @@
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/aura/test/test_windows.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_targeter.h"
 #include "ui/aura/window_tracker.h"
 #include "ui/base/hit_test.h"
 #include "ui/display/screen.h"
@@ -61,9 +62,11 @@
   ~NonClientDelegate() override {}
 
   int non_client_count() const { return non_client_count_; }
-  gfx::Point non_client_location() const { return non_client_location_; }
+  const gfx::Point& non_client_location() const { return non_client_location_; }
   int mouse_event_count() const { return mouse_event_count_; }
-  gfx::Point mouse_event_location() const { return mouse_event_location_; }
+  const gfx::Point& mouse_event_location() const {
+    return mouse_event_location_;
+  }
   int mouse_event_flags() const { return mouse_event_flags_; }
 
   int GetNonClientComponent(const gfx::Point& location) const override {
@@ -484,7 +487,7 @@
 
 namespace {
 
-// FilterFilter that tracks the types of events it's seen.
+// ui::EventHandler that tracks the types of events it's seen.
 class EventFilterRecorder : public ui::EventHandler {
  public:
   typedef std::vector<ui::EventType> Events;
@@ -2909,6 +2912,62 @@
 
 namespace {
 
+class ExplicitWindowTargeter : public WindowTargeter {
+ public:
+  explicit ExplicitWindowTargeter(Window* target) : target_(target) {}
+  ~ExplicitWindowTargeter() override = default;
+
+  // WindowTargeter:
+  ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
+                                      ui::Event* event) override {
+    return target_;
+  }
+  ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target,
+                                      ui::Event* event) override {
+    return nullptr;
+  }
+
+ private:
+  Window* target_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExplicitWindowTargeter);
+};
+
+}  // namespace
+
+TEST_F(WindowEventDispatcherMusTest, TargetCaptureWindow) {
+  NonClientDelegate w1_delegate;
+  NonClientDelegate w2_delegate;
+  std::unique_ptr<Window> w1(
+      CreateNormalWindow(-1, root_window(), &w1_delegate));
+  std::unique_ptr<Window> w2(
+      CreateNormalWindow(-1, root_window(), &w2_delegate));
+  const gfx::Point w2_origin(10, 11);
+  w2->SetBounds(gfx::Rect(w2_origin, gfx::Size(100, 100)));
+  NonClientDelegate w2_child_delegate;
+  std::unique_ptr<Window> w2_child(
+      CreateNormalWindow(-1, w2.get(), &w2_child_delegate));
+  ExplicitWindowTargeter* w2_targeter =
+      new ExplicitWindowTargeter(w2_child.get());
+  w2->SetEventTargeter(base::WrapUnique(w2_targeter));
+  w2->SetCapture();
+  ASSERT_TRUE(w2->HasCapture());
+  const gfx::Point root_location(100, 200);
+  const gfx::Point mouse_location(15, 25);
+  ui::MouseEvent mouse(ui::ET_MOUSE_PRESSED, mouse_location, root_location,
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                       ui::EF_LEFT_MOUSE_BUTTON);
+  ui::Event::DispatcherApi(&mouse).set_target(w1.get());
+  DispatchEventUsingWindowDispatcher(&mouse);
+  EXPECT_EQ(0, w1_delegate.mouse_event_count());
+  EXPECT_EQ(1, w2_delegate.mouse_event_count());
+  EXPECT_EQ(0, w2_child_delegate.mouse_event_count());
+  EXPECT_EQ(mouse_location - w2_origin.OffsetFromOrigin(),
+            w2_delegate.mouse_event_location());
+}
+
+namespace {
+
 class LocationRecordingEventHandler : public ui::EventHandler {
  public:
   LocationRecordingEventHandler() = default;
@@ -2941,12 +3000,12 @@
   std::unique_ptr<Window> window(
       test::CreateTestWindowWithBounds(gfx::Rect(0, 0, 10, 20), root_window()));
   std::unique_ptr<Window> child_window(
-      test::CreateTestWindowWithBounds(gfx::Rect(5, 6, 10, 20), window.get()));
+      CreateNormalWindow(-1, window.get(), nullptr));
 
   test::EnvTestHelper().SetAlwaysUseLastMouseLocation(false);
 
   LocationRecordingEventHandler event_handler;
-  root_window()->AddPreTargetHandler(&event_handler);
+  child_window->AddPreTargetHandler(&event_handler);
 
   const gfx::Point mouse_location(1, 2);
   gfx::Point root_location(mouse_location);
diff --git a/ui/aura/window_targeter.cc b/ui/aura/window_targeter.cc
index 8be8e14..e04383a 100644
--- a/ui/aura/window_targeter.cc
+++ b/ui/aura/window_targeter.cc
@@ -47,8 +47,9 @@
   return nullptr;
 }
 
-Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
-                                               const ui::LocatedEvent& event) {
+Window* WindowTargeter::GetPriorityTargetInRootWindow(
+    Window* root_window,
+    const ui::LocatedEvent& event) {
   DCHECK_EQ(root_window, root_window->GetRootWindow());
 
   // Mouse events should be dispatched to the window that processed the
@@ -71,8 +72,27 @@
         ui::GestureRecognizer::Get()->GetTouchLockedTarget(touch);
     if (consumer)
       return static_cast<Window*>(consumer);
-    consumer = ui::GestureRecognizer::Get()->GetTargetForLocation(
-        event.location_f(), touch.source_device_id());
+  }
+
+  return nullptr;
+}
+
+Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
+                                               const ui::LocatedEvent& event) {
+  DCHECK_EQ(root_window, root_window->GetRootWindow());
+
+  Window* priority_target = GetPriorityTargetInRootWindow(root_window, event);
+  if (priority_target)
+    return priority_target;
+
+  if (event.IsTouchEvent()) {
+    // Query the gesture-recognizer to find targets for touch events.
+    const ui::TouchEvent& touch = *event.AsTouchEvent();
+    // GetTouchLockedTarget() is handled in GetPriorityTargetInRootWindow().
+    DCHECK(!ui::GestureRecognizer::Get()->GetTouchLockedTarget(touch));
+    ui::GestureConsumer* consumer =
+        ui::GestureRecognizer::Get()->GetTargetForLocation(
+            event.location_f(), touch.source_device_id());
     if (consumer)
       return static_cast<Window*>(consumer);
 
@@ -84,34 +104,44 @@
   return nullptr;
 }
 
+bool WindowTargeter::ProcessEventIfTargetsDifferentRootWindow(
+    Window* root_window,
+    Window* target,
+    ui::Event* event) {
+  if (root_window->Contains(target))
+    return false;
+
+  // |window| is the root window, but |target| is not a descendent of
+  // |window|. So do not allow dispatching from here. Instead, dispatch the
+  // event through the WindowEventDispatcher that owns |target|.
+  Window* new_root = target->GetRootWindow();
+  DCHECK(new_root);
+  if (event->IsLocatedEvent()) {
+    // The event has been transformed to be in |target|'s coordinate system.
+    // But dispatching the event through the EventProcessor requires the event
+    // to be in the host's coordinate system. So, convert the event to be in
+    // the root's coordinate space, and then to the host's coordinate space by
+    // applying the host's transform.
+    ui::LocatedEvent* located_event = event->AsLocatedEvent();
+    located_event->ConvertLocationToTarget(target, new_root);
+    WindowTreeHost* window_tree_host = new_root->GetHost();
+    located_event->UpdateForRootTransform(
+        window_tree_host->GetRootTransform(),
+        window_tree_host->GetRootTransformForLocalEventCoordinates());
+  }
+  ignore_result(new_root->GetHost()->event_sink()->OnEventFromSource(event));
+  return true;
+}
+
 ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
                                                     ui::Event* event) {
   Window* window = static_cast<Window*>(root);
   Window* target = event->IsKeyEvent()
                        ? FindTargetForKeyEvent(window, *event->AsKeyEvent())
                        : FindTargetForNonKeyEvent(window, event);
-  if (target && !window->parent() && !window->Contains(target)) {
-    // |window| is the root window, but |target| is not a descendent of
-    // |window|. So do not allow dispatching from here. Instead, dispatch the
-    // event through the WindowEventDispatcher that owns |target|.
-    Window* new_root = target->GetRootWindow();
-    DCHECK(new_root);
-    if (event->IsLocatedEvent()) {
-      // The event has been transformed to be in |target|'s coordinate system.
-      // But dispatching the event through the EventProcessor requires the event
-      // to be in the host's coordinate system. So, convert the event to be in
-      // the root's coordinate space, and then to the host's coordinate space by
-      // applying the host's transform.
-      ui::LocatedEvent* located_event = static_cast<ui::LocatedEvent*>(event);
-      located_event->ConvertLocationToTarget(target, new_root);
-      WindowTreeHost* window_tree_host = new_root->GetHost();
-      located_event->UpdateForRootTransform(
-          window_tree_host->GetRootTransform(),
-          window_tree_host->GetRootTransformForLocalEventCoordinates());
-    }
-    ignore_result(new_root->GetHost()->event_sink()->OnEventFromSource(event));
-
-    target = nullptr;
+  if (target && !window->parent() &&
+      ProcessEventIfTargetsDifferentRootWindow(window, target, event)) {
+    return nullptr;
   }
   return target;
 }
diff --git a/ui/aura/window_targeter.h b/ui/aura/window_targeter.h
index cb07c10..1aea7f82 100644
--- a/ui/aura/window_targeter.h
+++ b/ui/aura/window_targeter.h
@@ -60,9 +60,21 @@
   virtual std::unique_ptr<HitTestRects> GetExtraHitTestShapeRects(
       Window* target) const;
 
+  // If there is a target that takes priority over normal WindowTargeter (such
+  // as a capture window) this returns it.
+  Window* GetPriorityTargetInRootWindow(Window* root_window,
+                                        const ui::LocatedEvent& event);
+
   Window* FindTargetInRootWindow(Window* root_window,
                                  const ui::LocatedEvent& event);
 
+  // If |target| is not a child of |root_window|, then converts |event| to
+  // be relative to |root_window| and dispatches the event to |root_window|.
+  // Returns false if the |target| is a child of |root_window|.
+  bool ProcessEventIfTargetsDifferentRootWindow(Window* root_window,
+                                                Window* target,
+                                                ui::Event* event);
+
   // ui::EventTargeter:
   ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
                                       ui::Event* event) override;
diff --git a/ui/base/test/ui_controls_internal_win.cc b/ui/base/test/ui_controls_internal_win.cc
index 2648a05..d2c43d4f 100644
--- a/ui/base/test/ui_controls_internal_win.cc
+++ b/ui/base/test/ui_controls_internal_win.cc
@@ -139,6 +139,32 @@
 
 // Private functions ----------------------------------------------------------
 
+UINT MapVirtualKeyToScanCode(UINT code) {
+  UINT ret_code = MapVirtualKey(code, MAPVK_VK_TO_VSC);
+  // We have to manually mark the following virtual
+  // keys as extended or else their scancodes depend
+  // on NumLock state.
+  // For ex. VK_DOWN will be mapped onto either DOWN or NumPad2
+  // depending on NumLock state which can lead to tests failures.
+  switch (code) {
+    case VK_INSERT:
+    case VK_DELETE:
+    case VK_HOME:
+    case VK_END:
+    case VK_NEXT:
+    case VK_PRIOR:
+    case VK_LEFT:
+    case VK_RIGHT:
+    case VK_UP:
+    case VK_DOWN:
+    case VK_NUMLOCK:
+      ret_code |= KF_EXTENDED;
+    default:
+      break;
+  }
+  return ret_code;
+}
+
 // Whether scan code should be used for |key|.
 // When sending keyboard events by SendInput() function, Windows does not
 // "smartly" add scan code if virtual key-code is used. So these key events
@@ -149,7 +175,7 @@
 // default keyboard layout. So fall back to use virtual key code for these keys.
 bool ShouldSendThroughScanCode(ui::KeyboardCode key) {
   const DWORD native_code = ui::WindowsKeyCodeForKeyboardCode(key);
-  const DWORD scan_code = MapVirtualKey(native_code, MAPVK_VK_TO_VSC);
+  const DWORD scan_code = MapVirtualKeyToScanCode(native_code);
   return native_code == MapVirtualKey(scan_code, MAPVK_VSC_TO_VK);
 }
 
@@ -160,7 +186,7 @@
   input->type = INPUT_KEYBOARD;
   input->ki.wVk = ui::WindowsKeyCodeForKeyboardCode(key);
   if (ShouldSendThroughScanCode(key)) {
-    input->ki.wScan = MapVirtualKey(input->ki.wVk, MAPVK_VK_TO_VSC);
+    input->ki.wScan = MapVirtualKeyToScanCode(input->ki.wVk);
     // When KEYEVENTF_SCANCODE is used, ki.wVk is ignored, so we do not need to
     // clear it.
     input->ki.dwFlags = KEYEVENTF_SCANCODE;
diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc
index d88f791..f7d5a1b8 100644
--- a/ui/chromeos/touch_exploration_controller.cc
+++ b/ui/chromeos/touch_exploration_controller.cc
@@ -708,6 +708,7 @@
   if (lift_activation_bounds_.Contains(anchor_location.x(),
                                        anchor_location.y()) &&
       lift_activation_bounds_.Contains(location)) {
+    delegate_->PlayTouchTypeEarcon();
     SendSimulatedTap();
   }
 }
diff --git a/ui/chromeos/touch_exploration_controller.h b/ui/chromeos/touch_exploration_controller.h
index 7ce3aa29..2decd40 100644
--- a/ui/chromeos/touch_exploration_controller.h
+++ b/ui/chromeos/touch_exploration_controller.h
@@ -58,6 +58,10 @@
   // played.
   virtual void PlayEnterScreenEarcon() = 0;
 
+  // This function should be called when the touch type earcon should
+  // be played.
+  virtual void PlayTouchTypeEarcon() = 0;
+
   // Called when the user performed an accessibility gesture while in touch
   // accessibility mode, that should be forwarded to ChromeVox.
   virtual void HandleAccessibilityGesture(ui::AXGesture gesture) = 0;
diff --git a/ui/chromeos/touch_exploration_controller_unittest.cc b/ui/chromeos/touch_exploration_controller_unittest.cc
index 778fdab..f8dc250 100644
--- a/ui/chromeos/touch_exploration_controller_unittest.cc
+++ b/ui/chromeos/touch_exploration_controller_unittest.cc
@@ -85,6 +85,7 @@
   void PlayPassthroughEarcon() override { ++num_times_passthrough_played_; }
   void PlayExitScreenEarcon() override { ++num_times_exit_screen_played_; }
   void PlayEnterScreenEarcon() override { ++num_times_enter_screen_played_; }
+  void PlayTouchTypeEarcon() override { ++num_times_touch_type_sound_played_; }
   void HandleAccessibilityGesture(ui::AXGesture gesture) override {
     last_gesture_ = gesture;
   }
@@ -94,6 +95,9 @@
   size_t NumPassthroughSounds() const { return num_times_passthrough_played_; }
   size_t NumExitScreenSounds() const { return num_times_exit_screen_played_; }
   size_t NumEnterScreenSounds() const { return num_times_enter_screen_played_; }
+  size_t NumTouchTypeSounds() const {
+    return num_times_touch_type_sound_played_;
+  }
   ui::AXGesture GetLastGesture() const { return last_gesture_; }
 
   void ResetCountersToZero() {
@@ -101,6 +105,7 @@
     num_times_passthrough_played_ = 0;
     num_times_exit_screen_played_ = 0;
     num_times_enter_screen_played_ = 0;
+    num_times_touch_type_sound_played_ = 0;
   }
 
  private:
@@ -109,6 +114,7 @@
   size_t num_times_passthrough_played_ = 0;
   size_t num_times_exit_screen_played_ = 0;
   size_t num_times_enter_screen_played_ = 0;
+  size_t num_times_touch_type_sound_played_ = 0;
   ui::AXGesture last_gesture_ = ui::AX_GESTURE_NONE;
 };
 
@@ -2070,6 +2076,7 @@
   gfx::Point tap_location = lift_activation.CenterPoint();
   EnterTouchExplorationModeAtLocation(tap_location);
   ClearCapturedEvents();
+  ASSERT_EQ(0U, delegate_.NumTouchTypeSounds());
 
   // A touch release should trigger a tap.
   ui::TouchEvent touch_explore_release(
@@ -2083,7 +2090,9 @@
   EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
   EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
   EXPECT_EQ(ui::ET_MOUSE_MOVED, captured_events[2]->type());
+  ASSERT_EQ(1U, delegate_.NumTouchTypeSounds());
   ClearCapturedEvents();
+  delegate_.ResetCountersToZero();
 
   // Touch explore inside the activation bounds, but lift outside.
   gfx::Point out_tap_location(tap_location.x(), lift_activation.bottom() + 20);
@@ -2099,6 +2108,7 @@
   const EventList& out_captured_events = GetCapturedEvents();
   ASSERT_EQ(1U, out_captured_events.size());
   EXPECT_EQ(ui::ET_MOUSE_MOVED, out_captured_events[0]->type());
+  ASSERT_EQ(0U, delegate_.NumTouchTypeSounds());
 }
 
 // Ensure that any touch release events received after
diff --git a/ui/events/event.h b/ui/events/event.h
index 6b5ccbd..61861900 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -378,7 +378,7 @@
     gfx::Point offset = gfx::ToFlooredPoint(location_);
     T::ConvertPointToTarget(source, target, &offset);
     gfx::Vector2d diff = gfx::ToFlooredPoint(location_) - offset;
-    location_= location_ - diff;
+    location_ = location_ - diff;
   }
 
  protected:
diff --git a/ui/events/event_processor.cc b/ui/events/event_processor.cc
index f80cb91..316dcdd 100644
--- a/ui/events/event_processor.cc
+++ b/ui/events/event_processor.cc
@@ -22,45 +22,54 @@
     event_to_dispatch = event_copy.get();
   }
 
-  OnEventProcessingStarted(event_to_dispatch);
-  EventTarget* target = nullptr;
-  EventTargeter* targeter = nullptr;
-  if (!event_to_dispatch->handled()) {
-    EventTarget* root = GetRootForEvent(event_to_dispatch);
-    DCHECK(root);
-    targeter = root->GetEventTargeter();
-    if (targeter) {
-      target = targeter->FindTargetForEvent(root, event_to_dispatch);
-    } else {
-      targeter = GetDefaultEventTargeter();
-      if (event_to_dispatch->target())
-        target = root;
-      else
-        target = targeter->FindTargetForEvent(root, event_to_dispatch);
-    }
-    DCHECK(targeter);
-  }
-
   EventDispatchDetails details;
-  while (target) {
-    details = DispatchEvent(target, event_to_dispatch);
+  OnEventProcessingStarted(event_to_dispatch);
+  // GetInitialEventTarget() may handle the event.
+  EventTarget* initial_target = event_to_dispatch->handled()
+                                    ? nullptr
+                                    : GetInitialEventTarget(event_to_dispatch);
+  if (!event_to_dispatch->handled()) {
+    EventTarget* target = initial_target;
+    EventTargeter* targeter = nullptr;
 
-    if (!dispatch_original_event) {
-      if (event_to_dispatch->stopped_propagation())
-        event->StopPropagation();
-      else if (event_to_dispatch->handled())
-        event->SetHandled();
+    if (!target) {
+      EventTarget* root = GetRootForEvent(event_to_dispatch);
+      DCHECK(root);
+      targeter = root->GetEventTargeter();
+      if (targeter) {
+        target = targeter->FindTargetForEvent(root, event_to_dispatch);
+      } else {
+        targeter = GetDefaultEventTargeter();
+        if (event_to_dispatch->target())
+          target = root;
+        else
+          target = targeter->FindTargetForEvent(root, event_to_dispatch);
+      }
+      DCHECK(targeter);
     }
 
-    if (details.dispatcher_destroyed)
-      return details;
+    while (target) {
+      details = DispatchEvent(target, event_to_dispatch);
 
-    if (details.target_destroyed || event->handled())
-      break;
+      if (!dispatch_original_event) {
+        if (event_to_dispatch->stopped_propagation())
+          event->StopPropagation();
+        else if (event_to_dispatch->handled())
+          event->SetHandled();
+      }
 
-    target = targeter->FindNextBestTarget(target, event_to_dispatch);
+      if (details.dispatcher_destroyed)
+        return details;
+
+      if (details.target_destroyed || event->handled() ||
+          target == initial_target) {
+        break;
+      }
+
+      DCHECK(targeter);
+      target = targeter->FindNextBestTarget(target, event_to_dispatch);
+    }
   }
-
   OnEventProcessingFinished(event);
   return details;
 }
diff --git a/ui/events/event_processor.h b/ui/events/event_processor.h
index 7be5f2d..cdb834b 100644
--- a/ui/events/event_processor.h
+++ b/ui/events/event_processor.h
@@ -23,6 +23,11 @@
   // EventSink overrides:
   EventDispatchDetails OnEventFromSource(Event* event) override;
 
+  // Returns the initial target for the event. A value of null means use the
+  // root and default targeter to find the target. This pass may process the
+  // event.
+  virtual EventTarget* GetInitialEventTarget(Event* event) = 0;
+
   // Returns the EventTarget with the right EventTargeter that we should use for
   // dispatching this |event|.
   virtual EventTarget* GetRootForEvent(Event* event) = 0;
diff --git a/ui/events/test/test_event_processor.cc b/ui/events/test/test_event_processor.cc
index dd83c4c..748d47c9a2 100644
--- a/ui/events/test/test_event_processor.cc
+++ b/ui/events/test/test_event_processor.cc
@@ -37,6 +37,10 @@
   return true;
 }
 
+EventTarget* TestEventProcessor::GetInitialEventTarget(Event* event) {
+  return nullptr;
+}
+
 EventTarget* TestEventProcessor::GetRootForEvent(Event* event) {
   return root_.get();
 }
diff --git a/ui/events/test/test_event_processor.h b/ui/events/test/test_event_processor.h
index 1e484a45..8ff9e5a 100644
--- a/ui/events/test/test_event_processor.h
+++ b/ui/events/test/test_event_processor.h
@@ -36,6 +36,7 @@
 
   // EventProcessor:
   bool CanDispatchToTarget(EventTarget* target) override;
+  EventTarget* GetInitialEventTarget(Event* event) override;
   EventTarget* GetRootForEvent(Event* event) override;
   EventTargeter* GetDefaultEventTargeter() override;
   EventDispatchDetails OnEventFromSource(Event* event) override;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
index 9c117ce..11c3d4d 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
@@ -235,13 +235,6 @@
  * @this {cr.ui.ListSelectionController}
  */
 filelist.handleTap = function(e, index, eventType) {
-  var isTap = eventType == FileTapHandler.TapEvent.TAP ||
-      eventType == FileTapHandler.TapEvent.LONG_TAP ||
-      eventType == FileTapHandler.TapEvent.TWO_FINGER_TAP;
-  if (isTap && index == -1) {
-    return false;
-  }
-
   var sm = /** @type {!FileListSelectionModel|!FileListSingleSelectionModel} */
       (this.selectionModel);
   if (eventType == FileTapHandler.TapEvent.TWO_FINGER_TAP) {
@@ -250,23 +243,34 @@
     // If the target is a non-selected file, cancel current selection and open
     // context menu for the single file.
     // Otherwise (when the target is the background), for the current folder.
-    var indexSelected = sm.getIndexSelected(index);
-    if (!indexSelected) {
-      // Prepare to open context menu of the new item by selecting only it.
-      if (sm.getCheckSelectMode()) {
-        // Unselect all items once to ensure that the check-select mode is
-        // terminated.
-        sm.unselectAll();
+    if (index == -1) {
+      // Two-finger tap outside the list should be handled here because it does
+      // not produce mousedown/click events.
+      sm.unselectAll();
+    } else {
+      var indexSelected = sm.getIndexSelected(index);
+      if (!indexSelected) {
+        // Prepare to open context menu of the new item by selecting only it.
+        if (sm.getCheckSelectMode()) {
+          // Unselect all items once to ensure that the check-select mode is
+          // terminated.
+          sm.unselectAll();
+        }
+        sm.beginChange();
+        sm.selectedIndex = index;
+        sm.endChange();
       }
-      sm.beginChange();
-      sm.selectedIndex = index;
-      sm.endChange();
     }
 
     // Context menu will be opened for the selected files by the following
     // 'contextmenu' event.
     return false;
   }
+  if (index == -1) {
+    return false;
+  }
+  var isTap = eventType == FileTapHandler.TapEvent.TAP ||
+      eventType == FileTapHandler.TapEvent.LONG_TAP;
   if (eventType == FileTapHandler.TapEvent.TAP &&
       e.target.classList.contains('detail-checkmark')) {
     // Single tap on the checkbox in the list view mode should toggle select,
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index 1eee0004..e2d9f2e 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -51,10 +51,8 @@
 #include "ui/gfx/render_text_mac.h"
 #endif
 
-using base::ASCIIToUTF16;
 using base::UTF8ToUTF16;
 using base::WideToUTF16;
-using base::WideToUTF8;
 
 namespace gfx {
 namespace test {
@@ -153,13 +151,13 @@
 };
 
 // Various weak, LTR, RTL, and Bidi string cases with three characters each.
-const wchar_t kWeak[] =      L" . ";
-const wchar_t kLtr[] =       L"abc";
-const wchar_t kRtl[] =       L"\x5d0\x5d1\x5d2";
-const wchar_t kLtrRtl[] =    L"a" L"\x5d0\x5d1";
-const wchar_t kLtrRtlLtr[] = L"a" L"\x5d1" L"b";
-const wchar_t kRtlLtr[] =    L"\x5d0\x5d1" L"a";
-const wchar_t kRtlLtrRtl[] = L"\x5d0" L"a" L"\x5d1";
+const char kWeak[] = " . ";
+const char kLtr[] = "abc";
+const char kRtl[] = "\u05d0\u05d1\u05d2";
+const char kLtrRtl[] = "a\u05d0\u05d1";
+const char kLtrRtlLtr[] = "a\u05d1b";
+const char kRtlLtr[] = "\u05d0\u05d1a";
+const char kRtlLtrRtl[] = "\u05d0a\u05d1";
 
 // Bitmasks based on gfx::TextStyle.
 enum {
@@ -375,7 +373,7 @@
 // rectangular buffer against a specific color value.
 class TestRectangleBuffer {
  public:
-  TestRectangleBuffer(const wchar_t* string,
+  TestRectangleBuffer(const char* string,
                       const SkColor* buffer,
                       uint32_t stride,
                       uint32_t row_count)
@@ -405,7 +403,7 @@
   }
 
  private:
-  const wchar_t* string_;
+  const char* string_;
   const SkColor* buffer_;
   int stride_;
   int row_count_;
@@ -471,7 +469,7 @@
   // with an arrow indicating the direction of the run. Single-character runs
   // just show the character position.
   //
-  // For example, the the logical bidirectional string "abc+\x05d0\x05d1\x05d2"
+  // For example, the the logical bidirectional string "abc+\u05d0\u05d1\u05d2"
   // (visual string: "abc+אבג") yields "[0->2][3][6<-4]".
   std::string GetRunListStructureString() const {
     const internal::TextRunList* run_list = GetHarfBuzzRunList();
@@ -619,13 +617,13 @@
   // Check the default styles applied to new instances and adjusted text.
   RenderText* render_text = GetRenderText();
   EXPECT_TRUE(render_text->text().empty());
-  const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
+  const char* const cases[] = {kWeak, kLtr, "Hello", kRtl, "", ""};
   for (size_t i = 0; i < arraysize(cases); ++i) {
     EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(SK_ColorBLACK));
     EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(NORMAL_BASELINE));
     for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
       EXPECT_TRUE(test_api()->styles()[style].EqualsValueForTesting(false));
-    render_text->SetText(WideToUTF16(cases[i]));
+    render_text->SetText(UTF8ToUTF16(cases[i]));
   }
 }
 
@@ -637,14 +635,14 @@
   render_text->SetBaselineStyle(SUPERSCRIPT);
   render_text->SetWeight(Font::Weight::BOLD);
   render_text->SetStyle(UNDERLINE, false);
-  const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
+  const char* const cases[] = {kWeak, kLtr, "Hello", kRtl, "", ""};
   for (size_t i = 0; i < arraysize(cases); ++i) {
     EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(color));
     EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(SUPERSCRIPT));
     EXPECT_TRUE(
         test_api()->weights().EqualsValueForTesting(Font::Weight::BOLD));
     EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsValueForTesting(false));
-    render_text->SetText(WideToUTF16(cases[i]));
+    render_text->SetText(UTF8ToUTF16(cases[i]));
 
     // Ensure custom default styles can be applied after text has been set.
     if (i == 1)
@@ -656,7 +654,7 @@
 
 TEST_P(RenderTextTest, ApplyStyles) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("012345678"));
+  render_text->SetText(UTF8ToUTF16("012345678"));
 
   // Apply a ranged color and style and check the resulting breaks.
   render_text->ApplyColor(SK_ColorRED, Range(1, 4));
@@ -727,30 +725,25 @@
   EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
 
   // Changing the text should clear any breaks except for the first one.
-  render_text->SetText(ASCIIToUTF16("0123456"));
+  render_text->SetText(UTF8ToUTF16("0123456"));
   expected_italic.resize(1);
   EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
   render_text->ApplyStyle(ITALIC, false, Range(2, 4));
-  render_text->SetText(ASCIIToUTF16("012345678"));
+  render_text->SetText(UTF8ToUTF16("012345678"));
   EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
   render_text->ApplyStyle(ITALIC, false, Range(0, 1));
-  render_text->SetText(ASCIIToUTF16("0123456"));
+  render_text->SetText(UTF8ToUTF16("0123456"));
   expected_italic.begin()->second = false;
   EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
   render_text->ApplyStyle(ITALIC, true, Range(2, 4));
-  render_text->SetText(ASCIIToUTF16("012345678"));
+  render_text->SetText(UTF8ToUTF16("012345678"));
   EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
 
   // TODO(tmoniuszko): Enable when RenderTextMac::IsValidCursorIndex is
   //                   implemented. See http://crbug.com/131618.
   if (GetParam() != RENDER_TEXT_MAC) {
     // Styles shouldn't be changed mid-grapheme.
-    render_text->SetText(
-        WideToUTF16(L"0"
-                    L"\x0915\x093f"
-                    L"1"
-                    L"\x0915\x093f"
-                    L"2"));
+    render_text->SetText(UTF8ToUTF16("0\u0915\u093f1\u0915\u093f2"));
     render_text->ApplyStyle(UNDERLINE, true, Range(2, 5));
     std::vector<std::pair<size_t, bool>> expected_underline;
     expected_underline.push_back(std::pair<size_t, bool>(0, false));
@@ -764,7 +757,7 @@
 TEST_P(RenderTextTest, AppendTextKeepsStyles) {
   RenderText* render_text = GetRenderText();
   // Setup basic functionality.
-  render_text->SetText(ASCIIToUTF16("abc"));
+  render_text->SetText(UTF8ToUTF16("abc"));
   render_text->ApplyColor(SK_ColorRED, Range(0, 1));
   render_text->ApplyBaselineStyle(SUPERSCRIPT, Range(1, 2));
   render_text->ApplyStyle(UNDERLINE, true, Range(2, 3));
@@ -785,8 +778,8 @@
   expected_style.push_back(std::pair<size_t, bool>(2, true));
   EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style));
   // Ensure AppendText maintains current text styles.
-  render_text->AppendText(ASCIIToUTF16("def"));
-  EXPECT_EQ(render_text->GetDisplayText(), ASCIIToUTF16("abcdef"));
+  render_text->AppendText(UTF8ToUTF16("def"));
+  EXPECT_EQ(render_text->GetDisplayText(), UTF8ToUTF16("abcdef"));
   EXPECT_TRUE(test_api()->colors().EqualsForTesting(expected_color));
   EXPECT_TRUE(test_api()->baselines().EqualsForTesting(expected_baseline));
   EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(expected_style));
@@ -824,7 +817,7 @@
 
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, ObscuredText) {
-  const base::string16 seuss = ASCIIToUTF16("hop on pop");
+  const base::string16 seuss = UTF8ToUTF16("hop on pop");
   const base::string16 no_seuss = GetObscuredString(seuss.length());
   RenderText* render_text = GetRenderText();
 
@@ -879,20 +872,20 @@
             static_cast<int>(render_text->GetGlyphBounds(0U).length()));
 
   // Cursoring is independent of underlying characters when text is obscured.
-  const wchar_t* const texts[] = {
-    kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl,
-    L"hop on pop",                              // Check LTR word boundaries.
-    L"\x05d0\x05d1 \x05d0\x05d2 \x05d1\x05d2",  // Check RTL word boundaries.
+  const char* const texts[] = {
+      kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl,
+      "hop on pop",                              // Check LTR word boundaries.
+      "\u05d0\u05d1 \u05d0\u05d2 \u05d1\u05d2",  // Check RTL word boundaries.
   };
   for (size_t i = 0; i < arraysize(texts); ++i) {
-    base::string16 text = WideToUTF16(texts[i]);
+    base::string16 text = UTF8ToUTF16(texts[i]);
     TestVisualCursorMotionInObscuredField(render_text, text, SELECTION_NONE);
     TestVisualCursorMotionInObscuredField(render_text, text, SELECTION_RETAIN);
   }
 }
 
 TEST_P(RenderTextTest, RevealObscuredText) {
-  const base::string16 seuss = ASCIIToUTF16("hop on pop");
+  const base::string16 seuss = UTF8ToUTF16("hop on pop");
   const base::string16 no_seuss = GetObscuredString(seuss.length());
   RenderText* render_text = GetRenderText();
 
@@ -928,11 +921,11 @@
   EXPECT_EQ(no_seuss, render_text->GetDisplayText());
 
   // SetText clears the revealed index.
-  render_text->SetText(ASCIIToUTF16("new"));
+  render_text->SetText(UTF8ToUTF16("new"));
   EXPECT_EQ(GetObscuredString(3), render_text->GetDisplayText());
   render_text->RenderText::SetObscuredRevealIndex(2);
   EXPECT_EQ(GetObscuredString(3, 2, 'w'), render_text->GetDisplayText());
-  render_text->SetText(ASCIIToUTF16("new longer"));
+  render_text->SetText(UTF8ToUTF16("new longer"));
   EXPECT_EQ(GetObscuredString(10), render_text->GetDisplayText());
 
   // Text with invalid surrogates.
@@ -983,11 +976,13 @@
   // Ensures text itemization doesn't crash on obscured multi-char glyphs.
   RenderText* render_text = GetRenderText();
   render_text->SetObscured(true);
-  // Test the "Grinning face with smiling eyes" character followed by 'y'.
-  render_text->SetText(UTF8ToUTF16("\xF0\x9F\x98\x81y"));
+  // Test U+1F601 😁 "Grinning face with smiling eyes", followed by 'y'.
+  // Windows requires wide strings for \Unnnnnnnn universal character names.
+  render_text->SetText(WideToUTF16(L"\U0001F601y"));
   render_text->Draw(canvas());
-  // Test two "Camera" characters in a row.
-  render_text->SetText(UTF8ToUTF16("\xF0\x9F\x93\xB7\xF0\x9F\x93\xB7"));
+  // Test two U+1F4F7 📷 "Camera" characters in a row.
+  // Windows requires wide strings for \Unnnnnnnn universal character names.
+  render_text->SetText(WideToUTF16(L"\U0001F4F7\U0001F4F7"));
   render_text->Draw(canvas());
 }
 
@@ -1008,55 +1003,42 @@
       // Strings shorter than the elision width should be laid out in full.
       {L"", L"", false},
       {L"M", L"", false},
-      {L" . ", L" . ", false},
-      {kWeak, kWeak, false},
-      {kLtr, kLtr, false},
-      {kLtrRtl, kLtrRtl, false},
-      {kLtrRtlLtr, kLtrRtlLtr, false},
-      {kRtl, kRtl, false},
-      {kRtlLtr, kRtlLtr, false},
-      {kRtlLtrRtl, kRtlLtrRtl, false},
+      {L" . ", L" . ", false},  // a wide kWeak
+      {L"abc", L"abc", false},  // a wide kLtr
+      {L"\u05d0\u05d1\u05d2", L"\u05d0\u05d1\u05d2", false},  // a wide kRtl
+      {L"a\u05d0\u05d1", L"a\u05d0\u05d1", false},  // a wide kLtrRtl
+      {L"a\u05d1b", L"a\u05d1b", false},  // a wide kLtrRtlLtr
+      {L"\u05d0\u05d1a", L"\u05d0\u05d1a", false},  // a wide kRtlLtr
+      {L"\u05d0a\u05d1", L"\u05d0a\u05d1", false},  // a wide kRtlLtrRtl
       // Strings as long as the elision width should be laid out in full.
       {L"012ab", L"012ab", false},
       // Long strings should be elided with an ellipsis appended at the end.
-      {L"012abc", L"012a\x2026", true},
-      {L"012ab"
-       L"\x5d0\x5d1",
-       L"012a\x2026", true},
-      {L"012a"
-       L"\x5d1"
-       L"b",
-       L"012a\x2026", true},
+      {L"012abc", L"012a\u2026", true},
+      {L"012ab\u05d0\u05d1", L"012a\u2026", true},
+      {L"012a\u05d1b", L"012a\u2026", true},
       // No RLM marker added as digits (012) have weak directionality.
-      {L"01"
-       L"\x5d0\x5d1\x5d2",
-       L"01\x5d0\x5d1\x2026", true},
+      {L"01\u05d0\u05d1\u05d2", L"01\u05d0\u05d1\u2026", true},
       // RLM marker added as "ab" have strong LTR directionality.
-      {L"ab"
-       L"\x5d0\x5d1\x5d2",
-       L"ab\x5d0\x5d1\x2026\x200f", true},
-      // Test surrogate pairs. \xd834\xdd1e forms a single code point U+1D11E;
-      // \xd834\xdd22 forms a second code point U+1D122. The first should be
-      // kept;
-      // the second removed (no surrogate pair should be partially elided).
-      {L"0123\xd834\xdd1e\xd834\xdd22", L"0123\xd834\xdd1e\x2026", true},
+      {L"ab\u05d0\u05d1\u05d2", L"ab\u05d0\u05d1\u2026\u200f", true},
+      // Test surrogate pairs. The first pair 𝄞 'MUSICAL SYMBOL G CLEF' U+1D11E
+      // should be kept, and the second pair 𝄢 'MUSICAL SYMBOL F CLEF' U+1D122
+      // should be removed. No surrogate pair should be partially elided.
+      // Windows requires wide strings for \Unnnnnnnn universal character names.
+      {L"0123\U0001D11E\U0001D122", L"0123\U0001D11E\u2026", true},
       // Test combining character sequences. U+0915 U+093F forms a compound
-      // glyph;
-      // U+0915 U+0942 forms a second compound glyph. The first should be kept;
-      // the second removed (no combining sequence should be partially elided).
-      {L"0123\x0915\x093f\x0915\x0942", L"0123\x0915\x093f\x2026", true},
+      // glyph, as does U+0915 U+0942. The first should be kept; the second
+      // removed. No combining sequence should be partially elided.
+      {L"0123\u0915\u093f\u0915\u0942", L"0123\u0915\u093f\u2026", true},
       // U+05E9 U+05BC U+05C1 U+05B8 forms a four-character compound glyph.
-      // Again,
-      // it should be either fully elided, or not elided at all. If completely
+      // It should be either fully elided, or not elided at all. If completely
       // elided, an LTR Mark (U+200E) should be added.
-      {L"0\x05e9\x05bc\x05c1\x05b8", L"0\x05e9\x05bc\x05c1\x05b8", false},
-      {L"0\x05e9\x05bc\x05c1\x05b8", L"0\x2026\x200E", true},
-      {L"01\x05e9\x05bc\x05c1\x05b8", L"01\x2026\x200E", true},
-      {L"012\x05e9\x05bc\x05c1\x05b8", L"012\x2026\x200E", true},
-      // \xF0\x9D\x84\x9E is the UTF-8 bytestring for MUSICAL SYMBOL G CLEF.  It
-      // should not have any internal grapheme boundaries; it should be
-      // completely removed when eliding.
-      {L"012\xF0\x9D\x84\x9E", L"012\x2026", true},
+      {L"0\u05e9\u05bc\u05c1\u05b8", L"0\u05e9\u05bc\u05c1\u05b8", false},
+      {L"0\u05e9\u05bc\u05c1\u05b8", L"0\u2026\u200E", true},
+      {L"01\u05e9\u05bc\u05c1\u05b8", L"01\u2026\u200E", true},
+      {L"012\u05e9\u05bc\u05c1\u05b8", L"012\u2026\u200E", true},
+      // 𝄞 (U+1D11E, MUSICAL SYMBOL G CLEF) should be fully elided.
+      // Windows requires wide strings for \Unnnnnnnn universal character names.
+      {L"012\U0001D11E", L"012\u2026", true},
   };
 
   std::unique_ptr<RenderText> expected_render_text(CreateRenderTextInstance());
@@ -1079,7 +1061,7 @@
     // Extend the input text to ensure that it is wider than the display_text,
     // and so it will get elided.
     if (cases[i].elision_expected)
-      input.append(WideToUTF16(L" MMMMMMMMMMM"));
+      input.append(UTF8ToUTF16(" MMMMMMMMMMM"));
     render_text->SetText(input);
     render_text->SetDisplayRect(Rect(0, 0, expected_width, 100));
     EXPECT_EQ(input, render_text->text());
@@ -1093,7 +1075,7 @@
   std::unique_ptr<RenderText> expected_render_text(CreateRenderTextInstance());
   expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
   expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
-  expected_render_text->SetText(WideToUTF16(L"**\x2026"));
+  expected_render_text->SetText(UTF8ToUTF16("**\u2026"));
 
   RenderText* render_text = GetRenderText();
   render_text->SetFontList(FontList("serif, Sans serif, 12px"));
@@ -1101,9 +1083,9 @@
   render_text->SetDisplayRect(
       Rect(0, 0, expected_render_text->GetContentWidth(), 100));
   render_text->SetObscured(true);
-  render_text->SetText(WideToUTF16(L"abcdef"));
-  EXPECT_EQ(WideToUTF16(L"abcdef"), render_text->text());
-  EXPECT_EQ(WideToUTF16(L"**\x2026"), render_text->GetDisplayText());
+  render_text->SetText(UTF8ToUTF16("abcdef"));
+  EXPECT_EQ(UTF8ToUTF16("abcdef"), render_text->text());
+  EXPECT_EQ(UTF8ToUTF16("**\u2026"), render_text->GetDisplayText());
 }
 
 #endif  // !defined(OS_MACOSX)
@@ -1114,7 +1096,7 @@
   base::string16 input_text;
   // Aim for 3 lines of text.
   for (int i = 0; i < 20; ++i)
-    input_text.append(ASCIIToUTF16("hello world "));
+    input_text.append(UTF8ToUTF16("hello world "));
   render_text->SetText(input_text);
   // Apply a style that tweaks the layout to make sure elision is calculated
   // with these styles. This can expose a behavior in layout where text is
@@ -1163,11 +1145,11 @@
 
 TEST_P(RenderTextTest, ElidedEmail) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("test@example.com"));
+  render_text->SetText(UTF8ToUTF16("test@example.com"));
   const Size size = render_text->GetStringSize();
 
   const base::string16 long_email =
-      ASCIIToUTF16("longemailaddresstest@example.com");
+      UTF8ToUTF16("longemailaddresstest@example.com");
   render_text->SetText(long_email);
   render_text->SetElideBehavior(ELIDE_EMAIL);
   render_text->SetDisplayRect(Rect(size));
@@ -1180,34 +1162,34 @@
     const wchar_t* text;
     const wchar_t* display_text;
   } cases[] = {
-    // Strings shorter than the truncation length should be laid out in full.
-    { L"",        L""        },
-    { kWeak,      kWeak      },
-    { kLtr,       kLtr       },
-    { kLtrRtl,    kLtrRtl    },
-    { kLtrRtlLtr, kLtrRtlLtr },
-    { kRtl,       kRtl       },
-    { kRtlLtr,    kRtlLtr    },
-    { kRtlLtrRtl, kRtlLtrRtl },
-    // Strings as long as the truncation length should be laid out in full.
-    { L"01234",   L"01234"   },
-    // Long strings should be truncated with an ellipsis appended at the end.
-    { L"012345",                  L"0123\x2026"     },
-    { L"012" L" . ",              L"012 \x2026"     },
-    { L"012" L"abc",              L"012a\x2026"     },
-    { L"012" L"a" L"\x5d0\x5d1",  L"012a\x2026"     },
-    { L"012" L"a" L"\x5d1" L"b",  L"012a\x2026"     },
-    { L"012" L"\x5d0\x5d1\x5d2",  L"012\x5d0\x2026" },
-    { L"012" L"\x5d0\x5d1" L"a",  L"012\x5d0\x2026" },
-    { L"012" L"\x5d0" L"a" L"\x5d1",    L"012\x5d0\x2026" },
-    // Surrogate pairs should be truncated reasonably enough.
-    { L"0123\x0915\x093f",              L"0123\x2026"                },
-    { L"0\x05e9\x05bc\x05c1\x05b8",     L"0\x05e9\x05bc\x05c1\x05b8" },
-    { L"01\x05e9\x05bc\x05c1\x05b8",    L"01\x05e9\x05bc\x2026"      },
-    { L"012\x05e9\x05bc\x05c1\x05b8",   L"012\x05e9\x2026"           },
-    { L"0123\x05e9\x05bc\x05c1\x05b8",  L"0123\x2026"                },
-    { L"01234\x05e9\x05bc\x05c1\x05b8", L"0123\x2026"                },
-    { L"012\xF0\x9D\x84\x9E",           L"012\xF0\x2026"             },
+      // Strings shorter than the truncation length should be laid out in full.
+      {L"", L""},
+      {L" . ", L" . "},  // a wide kWeak
+      {L"abc", L"abc"},  // a wide kLtr
+      {L"\u05d0\u05d1\u05d2", L"\u05d0\u05d1\u05d2"},  // a wide kRtl
+      {L"a\u05d0\u05d1", L"a\u05d0\u05d1"},  // a wide kLtrRtl
+      {L"a\u05d1b", L"a\u05d1b"},  // a wide kLtrRtlLtr
+      {L"\u05d0\u05d1a", L"\u05d0\u05d1a"},  // a wide kRtlLtr
+      {L"\u05d0a\u05d1", L"\u05d0a\u05d1"},  // a wide kRtlLtrRtl
+      {L"01234", L"01234"},
+      // Long strings should be truncated with an ellipsis appended at the end.
+      {L"012345", L"0123\u2026"},
+      {L"012 . ", L"012 \u2026"},
+      {L"012abc", L"012a\u2026"},
+      {L"012a\u05d0\u05d1", L"012a\u2026"},
+      {L"012a\u05d1b", L"012a\u2026"},
+      {L"012\u05d0\u05d1\u05d2", L"012\u05d0\u2026"},
+      {L"012\u05d0\u05d1a", L"012\u05d0\u2026"},
+      {L"012\u05d0a\u05d1", L"012\u05d0\u2026"},
+      // Surrogate pairs should be truncated reasonably enough.
+      {L"0123\u0915\u093f", L"0123\u2026"},
+      {L"0\u05e9\u05bc\u05c1\u05b8", L"0\u05e9\u05bc\u05c1\u05b8"},
+      {L"01\u05e9\u05bc\u05c1\u05b8", L"01\u05e9\u05bc\u2026"},
+      {L"012\u05e9\u05bc\u05c1\u05b8", L"012\u05e9\u2026"},
+      {L"0123\u05e9\u05bc\u05c1\u05b8", L"0123\u2026"},
+      {L"01234\u05e9\u05bc\u05c1\u05b8", L"0123\u2026"},
+      // Windows requires wide strings for \Unnnnnnnn universal character names.
+      {L"0123\U0001D11E", L"0123\u2026"},
   };
 
   RenderText* render_text = GetRenderText();
@@ -1224,8 +1206,8 @@
   RenderText* render_text = GetRenderText();
   render_text->set_truncate_length(3);
   render_text->SetObscured(true);
-  render_text->SetText(WideToUTF16(L"abcdef"));
-  EXPECT_EQ(WideToUTF16(L"abcdef"), render_text->text());
+  render_text->SetText(UTF8ToUTF16("abcdef"));
+  EXPECT_EQ(UTF8ToUTF16("abcdef"), render_text->text());
   EXPECT_EQ(GetObscuredString(3, 2, 0x2026), render_text->GetDisplayText());
 }
 
@@ -1233,7 +1215,7 @@
 TEST_P(RenderTextHarfBuzzTest, TruncatedCursorMovementLTR) {
   RenderText* render_text = GetRenderText();
   render_text->set_truncate_length(2);
-  render_text->SetText(WideToUTF16(L"abcd"));
+  render_text->SetText(UTF8ToUTF16("abcd"));
 
   EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
   render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, SELECTION_NONE);
@@ -1262,7 +1244,7 @@
 TEST_P(RenderTextHarfBuzzTest, TruncatedCursorMovementRTL) {
   RenderText* render_text = GetRenderText();
   render_text->set_truncate_length(2);
-  render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3"));
+  render_text->SetText(UTF8ToUTF16("\u05d0\u05d1\u05d2\u05d3"));
 
   EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
   render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, SELECTION_NONE);
@@ -1290,7 +1272,7 @@
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, MoveCursor_Character) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"123 456 789"));
+  render_text->SetText(UTF8ToUTF16("123 456 789"));
   std::vector<Range> expected;
 
   // SELECTION_NONE.
@@ -1354,7 +1336,7 @@
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, MoveCursor_Word) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"123 456 789"));
+  render_text->SetText(UTF8ToUTF16("123 456 789"));
   std::vector<Range> expected;
 
   // SELECTION_NONE.
@@ -1432,7 +1414,7 @@
 
 TEST_P(RenderTextTest, MoveCursor_Line) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"123 456 789"));
+  render_text->SetText(UTF8ToUTF16("123 456 789"));
   std::vector<Range> expected;
 
   // SELECTION_NONE.
@@ -1510,20 +1492,20 @@
 
 TEST_P(RenderTextTest, GetDisplayTextDirection) {
   struct {
-    const wchar_t* text;
+    const char* text;
     const base::i18n::TextDirection text_direction;
   } cases[] = {
-    // Blank strings and those with no/weak directionality default to LTR.
-    { L"",        base::i18n::LEFT_TO_RIGHT },
-    { kWeak,      base::i18n::LEFT_TO_RIGHT },
-    // Strings that begin with strong LTR characters.
-    { kLtr,       base::i18n::LEFT_TO_RIGHT },
-    { kLtrRtl,    base::i18n::LEFT_TO_RIGHT },
-    { kLtrRtlLtr, base::i18n::LEFT_TO_RIGHT },
-    // Strings that begin with strong RTL characters.
-    { kRtl,       base::i18n::RIGHT_TO_LEFT },
-    { kRtlLtr,    base::i18n::RIGHT_TO_LEFT },
-    { kRtlLtrRtl, base::i18n::RIGHT_TO_LEFT },
+      // Blank strings and those with no/weak directionality default to LTR.
+      {"", base::i18n::LEFT_TO_RIGHT},
+      {kWeak, base::i18n::LEFT_TO_RIGHT},
+      // Strings that begin with strong LTR characters.
+      {kLtr, base::i18n::LEFT_TO_RIGHT},
+      {kLtrRtl, base::i18n::LEFT_TO_RIGHT},
+      {kLtrRtlLtr, base::i18n::LEFT_TO_RIGHT},
+      // Strings that begin with strong RTL characters.
+      {kRtl, base::i18n::RIGHT_TO_LEFT},
+      {kRtlLtr, base::i18n::RIGHT_TO_LEFT},
+      {kRtlLtrRtl, base::i18n::RIGHT_TO_LEFT},
   };
 
   RenderText* render_text = GetRenderText();
@@ -1537,7 +1519,7 @@
 
     // Ensure that directionality modes yield the correct text directions.
     for (size_t j = 0; j < arraysize(cases); j++) {
-      render_text->SetText(WideToUTF16(cases[j].text));
+      render_text->SetText(UTF8ToUTF16(cases[j].text));
       render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
       EXPECT_EQ(render_text->GetDisplayTextDirection(),cases[j].text_direction);
       render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_UI);
@@ -1555,9 +1537,9 @@
 
   // Ensure that text changes update the direction for DIRECTIONALITY_FROM_TEXT.
   render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
-  render_text->SetText(WideToUTF16(kLtr));
+  render_text->SetText(UTF8ToUTF16(kLtr));
   EXPECT_EQ(render_text->GetDisplayTextDirection(), base::i18n::LEFT_TO_RIGHT);
-  render_text->SetText(WideToUTF16(kRtl));
+  render_text->SetText(UTF8ToUTF16(kRtl));
   EXPECT_EQ(render_text->GetDisplayTextDirection(), base::i18n::RIGHT_TO_LEFT);
 }
 
@@ -1565,7 +1547,7 @@
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtr) {
   RenderText* render_text = GetRenderText();
   // Pure LTR.
-  render_text->SetText(ASCIIToUTF16("abc"));
+  render_text->SetText(UTF8ToUTF16("abc"));
   // |expected| saves the expected SelectionModel when moving cursor from left
   // to right.
   std::vector<SelectionModel> expected;
@@ -1589,7 +1571,7 @@
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtrRtl) {
   RenderText* render_text = GetRenderText();
   // LTR-RTL
-  render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
+  render_text->SetText(UTF8ToUTF16("abc\u05d0\u05d1\u05d2"));
   // The last one is the expected END position.
   std::vector<SelectionModel> expected;
   expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
@@ -1618,7 +1600,7 @@
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtrRtlLtr) {
   RenderText* render_text = GetRenderText();
   // LTR-RTL-LTR.
-  render_text->SetText(WideToUTF16(L"a" L"\x05d1" L"b"));
+  render_text->SetText(UTF8ToUTF16("a\u05d1b"));
   std::vector<SelectionModel> expected;
   expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
   expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
@@ -1640,7 +1622,7 @@
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtl) {
   RenderText* render_text = GetRenderText();
   // Pure RTL.
-  render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"));
+  render_text->SetText(UTF8ToUTF16("\u05d0\u05d1\u05d2"));
   render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, SELECTION_NONE);
   std::vector<SelectionModel> expected;
 
@@ -1665,7 +1647,7 @@
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtlLtr) {
   RenderText* render_text = GetRenderText();
   // RTL-LTR
-  render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2" L"abc"));
+  render_text->SetText(UTF8ToUTF16("\u05d0\u05d1\u05d2abc"));
   render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, SELECTION_NONE);
   std::vector<SelectionModel> expected;
   expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
@@ -1694,7 +1676,7 @@
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtlLtrRtl) {
   RenderText* render_text = GetRenderText();
   // RTL-LTR-RTL.
-  render_text->SetText(WideToUTF16(L"\x05d0" L"a" L"\x05d1"));
+  render_text->SetText(UTF8ToUTF16("\u05d0a\u05d1"));
   render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, SELECTION_NONE);
   std::vector<SelectionModel> expected;
   expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
@@ -1716,7 +1698,7 @@
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_ComplexScript) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
+  render_text->SetText(UTF8ToUTF16("\u0915\u093f\u0915\u094d\u0915"));
   EXPECT_EQ(0U, render_text->cursor_position());
   render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_NONE);
   EXPECT_EQ(2U, render_text->cursor_position());
@@ -1745,7 +1727,7 @@
   // Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
   // (code point) has unique bounds, so mid-glyph cursoring should be possible.
   render_text->SetFontList(FontList("Meiryo UI, 12px"));
-  render_text->SetText(WideToUTF16(L"ff ffi"));
+  render_text->SetText(UTF8ToUTF16("ff ffi"));
   render_text->SetDisplayRect(gfx::Rect(100, 100));
   test_api()->EnsureLayout();
   EXPECT_EQ(0U, render_text->cursor_position());
@@ -1766,21 +1748,16 @@
 }
 #endif  // !defined(OS_MACOSX)
 
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, GraphemePositions) {
-  // LTR 2-character grapheme, LTR abc, LTR 2-character grapheme.
-  const base::string16 kText1 =
-      WideToUTF16(L"\x0915\x093f" L"abc" L"\x0915\x093f");
+  // LTR कि (DEVANAGARI KA with VOWEL I) (2-char grapheme), LTR abc, and LTR कि.
+  const base::string16 kText1 = WideToUTF16(L"\u0915\u093fabc\u0915\u093f");
 
-  // LTR ab, LTR 2-character grapheme, LTR cd.
-  const base::string16 kText2 = WideToUTF16(L"ab" L"\x0915\x093f" L"cd");
+  // LTR ab, LTR कि (DEVANAGARI KA with VOWEL I) (2-char grapheme), LTR cd.
+  const base::string16 kText2 = UTF8ToUTF16("ab\u0915\u093fcd");
 
-  // The below is 'MUSICAL SYMBOL G CLEF', which is represented in UTF-16 as
-  // two characters forming the surrogate pair 0x0001D11E.
-  const std::string kSurrogate = "\xF0\x9D\x84\x9E";
-
-  // LTR ab, UTF16 surrogate pair, LTR cd.
-  const base::string16 kText3 = UTF8ToUTF16("ab" + kSurrogate + "cd");
+  // LTR ab, 𝄞 'MUSICAL SYMBOL G CLEF' U+1D11E (surrogate pair), LTR cd.
+  // Windows requires wide strings for \Unnnnnnnn universal character names.
+  const base::string16 kText3 = WideToUTF16(L"ab\U0001D11Ecd");
 
   struct {
     base::string16 text;
@@ -1841,8 +1818,8 @@
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, MidGraphemeSelectionBounds) {
   // Test that selection bounds may be set amid multi-character graphemes.
-  const base::string16 kHindi = WideToUTF16(L"\x0915\x093f");
-  const base::string16 kThai = WideToUTF16(L"\x0e08\x0e33");
+  const base::string16 kHindi = UTF8ToUTF16("\u0915\u093f");
+  const base::string16 kThai = UTF8ToUTF16("\u0e08\u0e33");
   const base::string16 cases[] = { kHindi, kThai };
 
   RenderText* render_text = GetRenderText();
@@ -1875,12 +1852,12 @@
 
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, FindCursorPosition) {
-  const wchar_t* kTestStrings[] = { kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl };
+  const char* kTestStrings[] = {kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl};
   RenderText* render_text = GetRenderText();
   render_text->SetDisplayRect(Rect(0, 0, 100, 20));
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
     for (size_t j = 0; j < render_text->text().length(); ++j) {
       const Range range(render_text->GetGlyphBounds(j));
       // Test a point just inside the leading edge of the glyph bounds.
@@ -1894,8 +1871,8 @@
 
 // Tests that FindCursorPosition behaves correctly for multi-line text.
 TEST_P(RenderTextHarfBuzzTest, FindCursorPositionMultiline) {
-  const wchar_t* kTestStrings[] = {L"abc def",
-                                   L"\x5d0\x5d1\x5d2 \x5d3\x5d4\x5d5" /*rtl*/};
+  const char* kTestStrings[] = {"abc def",
+                                "\u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5"};
 
   SetGlyphWidth(5);
   RenderText* render_text = GetRenderText();
@@ -1903,7 +1880,7 @@
   render_text->SetMultiline(true);
 
   for (size_t i = 0; i < arraysize(kTestStrings); i++) {
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
     test_api()->EnsureLayout();
     EXPECT_EQ(2u, test_api()->lines().size());
 
@@ -1934,21 +1911,13 @@
     base::string16 text;
     std::set<size_t> expected_cursor_positions;
   } cases[] = {
-      // LTR 2-character grapheme, LTR abc, LTR 2-character grapheme.
-      {WideToUTF16(L"\x0915\x093f"
-                   L"abc"
-                   L"\x0915\x093f"),
-       {0, 2, 3, 4, 5, 7}},
-      // LTR ab, LTR 2-character grapheme, LTR cd.
-      {WideToUTF16(L"ab"
-                   L"\x0915\x093f"
-                   L"cd"),
-       {0, 1, 2, 4, 5, 6}},
+      // LTR कि (DEVANAGARI KA with VOWEL I) (2-char grapheme), LTR abc, LTR कि.
+      {UTF8ToUTF16("\u0915\u093fabc\u0915\u093f"), {0, 2, 3, 4, 5, 7}},
+      // LTR ab, LTR कि (DEVANAGARI KA with VOWEL I) (2-char grapheme), LTR cd.
+      {UTF8ToUTF16("ab\u0915\u093fcd"), {0, 1, 2, 4, 5, 6}},
       // LTR ab, surrogate pair composed of two 16 bit characters, LTR cd.
-      {UTF8ToUTF16("ab"
-                   "\xF0\x9D\x84\x9E"
-                   "cd"),
-       {0, 1, 2, 4, 5, 6}}};
+      // Windows requires wide strings for \Unnnnnnnn universal character names.
+      {WideToUTF16(L"ab\U0001D11Ecd"), {0, 1, 2, 4, 5, 6}}};
 
   RenderText* render_text = GetRenderText();
   render_text->SetDisplayRect(gfx::Rect(100, 30));
@@ -1967,17 +1936,15 @@
 
 TEST_P(RenderTextTest, EdgeSelectionModels) {
   // Simple Latin text.
-  const base::string16 kLatin = WideToUTF16(L"abc");
-  // LTR 2-character grapheme.
-  const base::string16 kLTRGrapheme = WideToUTF16(L"\x0915\x093f");
-  // LTR 2-character grapheme, LTR a, LTR 2-character grapheme.
-  const base::string16 kHindiLatin =
-      WideToUTF16(L"\x0915\x093f" L"a" L"\x0915\x093f");
-  // RTL 2-character grapheme.
-  const base::string16 kRTLGrapheme = WideToUTF16(L"\x05e0\x05b8");
-  // RTL 2-character grapheme, LTR a, RTL 2-character grapheme.
-  const base::string16 kHebrewLatin =
-      WideToUTF16(L"\x05e0\x05b8" L"a" L"\x05e0\x05b8");
+  const base::string16 kLatin = UTF8ToUTF16("abc");
+  // LTR कि (DEVANAGARI KA with VOWEL I).
+  const base::string16 kLTRGrapheme = UTF8ToUTF16("\u0915\u093f");
+  // LTR कि (DEVANAGARI KA with VOWEL I), LTR a, LTR कि.
+  const base::string16 kHindiLatin = UTF8ToUTF16("\u0915\u093fa\u0915\u093f");
+  // RTL נָ (Hebrew letter NUN and point QAMATS).
+  const base::string16 kRTLGrapheme = UTF8ToUTF16("\u05e0\u05b8");
+  // RTL נָ (Hebrew letter NUN and point QAMATS), LTR a, RTL נָ.
+  const base::string16 kHebrewLatin = UTF8ToUTF16("\u05e0\u05b8a\u05e0\u05b8");
 
   struct {
     base::string16 text;
@@ -2007,8 +1974,8 @@
 }
 
 TEST_P(RenderTextTest, SelectAll) {
-  const wchar_t* const cases[] =
-      { kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl };
+  const char* const cases[] = {kWeak, kLtr,    kLtrRtl,   kLtrRtlLtr,
+                               kRtl,  kRtlLtr, kRtlLtrRtl};
 
   // Ensure that SelectAll respects the |reversed| argument regardless of
   // application locale and text content directionality.
@@ -2025,7 +1992,7 @@
 
     // Test the weak, LTR, RTL, and Bidi string cases.
     for (size_t j = 0; j < arraysize(cases); j++) {
-      render_text->SetText(WideToUTF16(cases[j]));
+      render_text->SetText(UTF8ToUTF16(cases[j]));
       render_text->SelectAll(false);
       EXPECT_EQ(render_text->selection_model(), expected_forwards);
       render_text->SelectAll(true);
@@ -2039,7 +2006,7 @@
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightWithSelection) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
+  render_text->SetText(UTF8ToUTF16("abc\u05d0\u05d1\u05d2"));
   // Left arrow on select ranging (6, 4).
   render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, SELECTION_NONE);
   EXPECT_EQ(Range(6), render_text->selection());
@@ -2079,7 +2046,7 @@
 
 TEST_P(RenderTextTest, CenteredDisplayOffset) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("abcdefghij"));
+  render_text->SetText(UTF8ToUTF16("abcdefghij"));
   render_text->SetHorizontalAlignment(ALIGN_CENTER);
 
   const int kEnlargement = 10;
@@ -2116,9 +2083,8 @@
   }
 }
 
-void MoveLeftRightByWordVerifier(RenderText* render_text,
-                                 const wchar_t* str) {
-  render_text->SetText(WideToUTF16(str));
+void MoveLeftRightByWordVerifier(RenderText* render_text, const char* str) {
+  render_text->SetText(UTF8ToUTF16(str));
 
   // Test moving by word from left ro right.
   render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, SELECTION_NONE);
@@ -2184,32 +2150,37 @@
 TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInBidiText) {
   RenderText* render_text = GetRenderText();
   // For testing simplicity, each word is a 3-character word.
-  std::vector<const wchar_t*> test;
-  test.push_back(L"abc");
-  test.push_back(L"abc def");
-  test.push_back(L"\x05E1\x05E2\x05E3");
-  test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
-  test.push_back(L"abc \x05E1\x05E2\x05E3");
-  test.push_back(L"abc def \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
-  test.push_back(L"abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
-                 L" \x05E7\x05E8\x05E9");
+  std::vector<const char*> test;
+  test.push_back("abc");
+  test.push_back("abc def");
+  test.push_back("\u05E1\u05E2\u05E3");
+  test.push_back("\u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6");
+  test.push_back("abc \u05E1\u05E2\u05E3");
+  test.push_back("abc def \u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6");
+  test.push_back(
+      "abc def hij \u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6"
+      " \u05E7\u05E8\u05E9");
 
-  test.push_back(L"abc \x05E1\x05E2\x05E3 hij");
-  test.push_back(L"abc def \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 hij opq");
-  test.push_back(L"abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
-                 L" \x05E7\x05E8\x05E9" L" opq rst uvw");
+  test.push_back("abc \u05E1\u05E2\u05E3 hij");
+  test.push_back("abc def \u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6 hij opq");
+  test.push_back(
+      "abc def hij \u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6"
+      " \u05E7\u05E8\u05E9 opq rst uvw");
 
-  test.push_back(L"\x05E1\x05E2\x05E3 abc");
-  test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 abc def");
-  test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 \x05E7\x05E8\x05E9"
-                 L" abc def hij");
+  test.push_back("\u05E1\u05E2\u05E3 abc");
+  test.push_back("\u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6 abc def");
+  test.push_back(
+      "\u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6 \u05E7\u05E8\u05E9"
+      " abc def hij");
 
-  test.push_back(L"\x05D1\x05D2\x05D3 abc \x05E1\x05E2\x05E3");
-  test.push_back(L"\x05D1\x05D2\x05D3 \x05D4\x05D5\x05D6 abc def"
-                 L" \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
-  test.push_back(L"\x05D1\x05D2\x05D3 \x05D4\x05D5\x05D6 \x05D7\x05D8\x05D9"
-                 L" abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
-                 L" \x05E7\x05E8\x05E9");
+  test.push_back("\u05D1\u05D2\u05D3 abc \u05E1\u05E2\u05E3");
+  test.push_back(
+      "\u05D1\u05D2\u05D3 \u05D4\u05D5\u05D6 abc def"
+      " \u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6");
+  test.push_back(
+      "\u05D1\u05D2\u05D3 \u05D4\u05D5\u05D6 \u05D7\u05D8\u05D9"
+      " abc def hij \u05E1\u05E2\u05E3 \u05E4\u05E5\u05E6"
+      " \u05E7\u05E8\u05E9");
 
   for (size_t i = 0; i < test.size(); ++i)
     MoveLeftRightByWordVerifier(render_text, test[i]);
@@ -2219,7 +2190,7 @@
 TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInBidiText_TestEndOfText) {
   RenderText* render_text = GetRenderText();
 
-  render_text->SetText(WideToUTF16(L"ab\x05E1"));
+  render_text->SetText(UTF8ToUTF16("ab\u05E1"));
   // Moving the cursor by word from "abC|" to the left should return "|abC".
   // But since end of text is always treated as a word break, it returns
   // position "ab|C".
@@ -2233,7 +2204,7 @@
   render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
   EXPECT_EQ(SelectionModel(3, CURSOR_FORWARD), render_text->selection_model());
 
-  render_text->SetText(WideToUTF16(L"\x05E1\x05E2" L"a"));
+  render_text->SetText(UTF8ToUTF16("\u05E1\u05E2a"));
   // For logical text "BCa", moving the cursor by word from "aCB|" to the left
   // returns "|aCB".
   render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, SELECTION_NONE);
@@ -2252,7 +2223,7 @@
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInTextWithMultiSpaces) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"abc     def"));
+  render_text->SetText(UTF8ToUTF16("abc     def"));
   render_text->MoveCursorTo(SelectionModel(5, CURSOR_FORWARD));
   render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
   EXPECT_EQ(11U, render_text->cursor_position());
@@ -2266,7 +2237,7 @@
 // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
 TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInChineseText) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"\x6211\x4EEC\x53BB\x516C\x56ED\x73A9"));
+  render_text->SetText(UTF8ToUTF16("\u6211\u4EEC\u53BB\u516C\u56ED\u73A9"));
   render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, SELECTION_NONE);
   EXPECT_EQ(0U, render_text->cursor_position());
   render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
@@ -2333,9 +2304,8 @@
   EXPECT_NE(arial_font.GetBaseline(), cjk_font.GetBaseline());
   // "a" should be rendered with Arial, not with the CJK font.
   const char* arial_font_text = "a";
-  // "円" CJK UNIFIED IDEOGRAPH-5186, aka the Yen sign should be rendered with
-  // the CJK font, not with Arial.
-  const char* cjk_font_text = "\xE5\x86\x86";
+  // "円" (U+5168 Han character YEN) should render with the CJK font, not Arial.
+  const char* cjk_font_text = "\u5168";
   Font smaller_font = arial_font;
   Font larger_font = cjk_font;
   const char* smaller_font_text = arial_font_text;
@@ -2381,7 +2351,7 @@
 
 TEST_P(RenderTextTest, MinLineHeight) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("Hello!"));
+  render_text->SetText(UTF8ToUTF16("Hello!"));
   SizeF default_size = render_text->GetStringSizeF();
   ASSERT_NE(0, default_size.height());
   ASSERT_NE(0, default_size.width());
@@ -2402,7 +2372,7 @@
 TEST_P(RenderTextTest, DISABLED_DefaultLineHeights) {
   RenderText* render_text = GetRenderText();
   render_text->SetText(
-      ASCIIToUTF16("A quick brown fox jumped over the lazy dog!"));
+      UTF8ToUTF16("A quick brown fox jumped over the lazy dog!"));
 
 #if defined(OS_MACOSX)
   const FontList body2_font = FontList().DeriveWithSizeDelta(-1);
@@ -2477,10 +2447,10 @@
 
 TEST_P(RenderTextTest, StringSizeHeight) {
   base::string16 cases[] = {
-    WideToUTF16(L"Hello World!"),  // English
-    WideToUTF16(L"\x6328\x62f6"),  // Japanese
-    WideToUTF16(L"\x0915\x093f"),  // Hindi
-    WideToUTF16(L"\x05e0\x05b8"),  // Hebrew
+      UTF8ToUTF16("Hello World!"),  // English
+      UTF8ToUTF16("\u6328\u62f6"),  // Japanese 挨拶 (characters press & near)
+      UTF8ToUTF16("\u0915\u093f"),  // Hindi कि (letter KA with vowel I)
+      UTF8ToUTF16("\u05e0\u05b8"),  // Hebrew נָ (letter NUN and point QAMATS)
   };
 
   const FontList default_font_list;
@@ -2512,7 +2482,7 @@
 
 TEST_P(RenderTextTest, CursorBoundsInReplacementMode) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("abcdefg"));
+  render_text->SetText(UTF8ToUTF16("abcdefg"));
   render_text->SetDisplayRect(Rect(100, 17));
   SelectionModel sel_b(1, CURSOR_FORWARD);
   SelectionModel sel_c(2, CURSOR_FORWARD);
@@ -2534,7 +2504,7 @@
   ResetRenderTextInstance();
   RenderText* render_text = GetRenderText();
 
-  render_text->SetText(ASCIIToUTF16("abcdefg"));
+  render_text->SetText(UTF8ToUTF16("abcdefg"));
   render_text->SetFontList(FontList("Arial, 13px"));
 
   // Set display area's size equal to the font size.
@@ -2588,7 +2558,7 @@
   ResetRenderTextInstance();
   RenderText* render_text = GetRenderText();
 
-  render_text->SetText(ASCIIToUTF16("abcdefg"));
+  render_text->SetText(UTF8ToUTF16("abcdefg"));
   render_text->SetFontList(FontList("Arial, 13px"));
   const int kEnlargement = 2;
   const Size font_size(render_text->GetContentWidth() + kEnlargement,
@@ -2602,7 +2572,7 @@
 
 TEST_P(RenderTextTest, SetDisplayOffset) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("abcdefg"));
+  render_text->SetText(UTF8ToUTF16("abcdefg"));
   render_text->SetFontList(FontList("Arial, 13px"));
 
   const Size font_size(render_text->GetContentWidth(),
@@ -2686,31 +2656,31 @@
   struct {
     base::string16 text;
   } cases[] = {
-    // English(English)
-    { WideToUTF16(L"Hello World(a)") },
-    // English(English)English
-    { WideToUTF16(L"Hello World(a)Hello World") },
+      // English(English)
+      {UTF8ToUTF16("Hello World(a)")},
+      // English(English)English
+      {UTF8ToUTF16("Hello World(a)Hello World")},
 
-    // Japanese(English)
-    { WideToUTF16(L"\x6328\x62f6(a)") },
-    // Japanese(English)Japanese
-    { WideToUTF16(L"\x6328\x62f6(a)\x6328\x62f6") },
-    // English(Japanese)English
-    { WideToUTF16(L"Hello World(\x6328\x62f6)Hello World") },
+      // Japanese(English)
+      {UTF8ToUTF16("\u6328\u62f6(a)")},
+      // Japanese(English)Japanese
+      {UTF8ToUTF16("\u6328\u62f6(a)\u6328\u62f6")},
+      // English(Japanese)English
+      {UTF8ToUTF16("Hello World(\u6328\u62f6)Hello World")},
 
-    // Hindi(English)
-    { WideToUTF16(L"\x0915\x093f(a)") },
-    // Hindi(English)Hindi
-    { WideToUTF16(L"\x0915\x093f(a)\x0915\x093f") },
-    // English(Hindi)English
-    { WideToUTF16(L"Hello World(\x0915\x093f)Hello World") },
+      // Hindi(English)
+      {UTF8ToUTF16("\u0915\u093f(a)")},
+      // Hindi(English)Hindi
+      {UTF8ToUTF16("\u0915\u093f(a)\u0915\u093f")},
+      // English(Hindi)English
+      {UTF8ToUTF16("Hello World(\u0915\u093f)Hello World")},
 
-    // Hebrew(English)
-    { WideToUTF16(L"\x05e0\x05b8(a)") },
-    // Hebrew(English)Hebrew
-    { WideToUTF16(L"\x05e0\x05b8(a)\x05e0\x05b8") },
-    // English(Hebrew)English
-    { WideToUTF16(L"Hello World(\x05e0\x05b8)Hello World") },
+      // Hebrew(English)
+      {UTF8ToUTF16("\u05e0\u05b8(a)")},
+      // Hebrew(English)Hebrew
+      {UTF8ToUTF16("\u05e0\u05b8(a)\u05e0\u05b8")},
+      // English(Hebrew)English
+      {UTF8ToUTF16("Hello World(\u05e0\u05b8)Hello World")},
   };
 
   RenderText* render_text = GetRenderText();
@@ -2753,13 +2723,13 @@
 // caret is drawn at high DPI. crbug.com/164100.
 TEST_P(RenderTextTest, CaretWidth) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("abcdefg"));
+  render_text->SetText(UTF8ToUTF16("abcdefg"));
   EXPECT_GE(render_text->GetUpdatedCursorBounds().width(), 1);
 }
 
 TEST_P(RenderTextTest, SelectWord) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16(" foo  a.bc.d bar"));
+  render_text->SetText(UTF8ToUTF16(" foo  a.bc.d bar"));
 
   struct {
     size_t cursor;
@@ -2800,16 +2770,16 @@
 
   RenderText* render_text = GetRenderText();
 
-  render_text->SetText(ASCIIToUTF16(kTestURL1));
+  render_text->SetText(UTF8ToUTF16(kTestURL1));
   render_text->SetCursorPosition(kTestURL1.length());
   render_text->SelectWord();
-  EXPECT_EQ(ASCIIToUTF16("com"), GetSelectedText(render_text));
+  EXPECT_EQ(UTF8ToUTF16("com"), GetSelectedText(render_text));
   EXPECT_FALSE(render_text->selection().is_reversed());
 
-  render_text->SetText(ASCIIToUTF16(kTestURL2));
+  render_text->SetText(UTF8ToUTF16(kTestURL2));
   render_text->SetCursorPosition(kTestURL2.length());
   render_text->SelectWord();
-  EXPECT_EQ(ASCIIToUTF16("/"), GetSelectedText(render_text));
+  EXPECT_EQ(UTF8ToUTF16("/"), GetSelectedText(render_text));
   EXPECT_FALSE(render_text->selection().is_reversed());
 }
 
@@ -2820,16 +2790,16 @@
 
   RenderText* render_text = GetRenderText();
 
-  render_text->SetText(ASCIIToUTF16(kTestURL));
+  render_text->SetText(UTF8ToUTF16(kTestURL));
   render_text->SelectRange(Range(16, 20));
   render_text->SelectWord();
-  EXPECT_EQ(ASCIIToUTF16("google.com"), GetSelectedText(render_text));
+  EXPECT_EQ(UTF8ToUTF16("google.com"), GetSelectedText(render_text));
   EXPECT_FALSE(render_text->selection().is_reversed());
 
   // SelectWord should preserve the selection direction.
   render_text->SelectRange(Range(20, 16));
   render_text->SelectWord();
-  EXPECT_EQ(ASCIIToUTF16("google.com"), GetSelectedText(render_text));
+  EXPECT_EQ(UTF8ToUTF16("google.com"), GetSelectedText(render_text));
   EXPECT_TRUE(render_text->selection().is_reversed());
 }
 
@@ -2839,7 +2809,7 @@
   ASSERT_FALSE(base::i18n::ICUIsRTL());
 
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"abcdefghijklmnopqrstuvwxzyabcdefg"));
+  render_text->SetText(UTF8ToUTF16("abcdefghijklmnopqrstuvwxzyabcdefg"));
   render_text->MoveCursorTo(SelectionModel(render_text->text().length(),
                                            CURSOR_FORWARD));
   int width = render_text->GetStringSize().width();
@@ -2864,8 +2834,9 @@
   EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
 
   // Repeat the test with RTL text.
-  render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7"
-      L"\x5d8\x5d9\x5da\x5db\x5dc\x5dd\x5de\x5df"));
+  render_text->SetText(
+      UTF8ToUTF16("\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7"
+                  "\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df"));
   render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
   width = render_text->GetStringSize().width();
   ASSERT_GT(width, 10);
@@ -2897,7 +2868,7 @@
   // Reset the render text instance since the locale was changed.
   ResetRenderTextInstance();
   RenderText* render_text = GetRenderText();
-  render_text->SetText(WideToUTF16(L"abcdefghijklmnopqrstuvwxzyabcdefg"));
+  render_text->SetText(UTF8ToUTF16("abcdefghijklmnopqrstuvwxzyabcdefg"));
   render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
   int width = render_text->GetStringSize().width();
   ASSERT_GT(width, 10);
@@ -2921,8 +2892,9 @@
             render_text->GetUpdatedCursorBounds().x());
 
   // Repeat the test with RTL text.
-  render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7"
-      L"\x5d8\x5d9\x5da\x5db\x5dc\x5dd\x5de\x5df"));
+  render_text->SetText(
+      UTF8ToUTF16("\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7"
+                  "\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df"));
   render_text->MoveCursorTo(SelectionModel(render_text->text().length(),
                                            CURSOR_FORWARD));
   width = render_text->GetStringSize().width();
@@ -2953,12 +2925,12 @@
 
 // Changing colors between or inside ligated glyphs should not break shaping.
 TEST_P(RenderTextTest, SelectionKeepsLigatures) {
-  const wchar_t* kTestStrings[] = { L"\x644\x623", L"\x633\x627" };
+  const char* kTestStrings[] = {"\u0644\u0623", "\u0633\u0627"};
   RenderText* render_text = GetRenderText();
   render_text->set_selection_color(SK_ColorRED);
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
     const int expected_width = render_text->GetStringSize().width();
     render_text->MoveCursorTo(SelectionModel(Range(0, 1), CURSOR_FORWARD));
     EXPECT_EQ(expected_width, render_text->GetStringSize().width());
@@ -3000,7 +2972,7 @@
   // Note that the hyphens that Wikipedia uses are different. English uses
   // ASCII (U+002D) "hyphen minus", Hebrew uses the U+2013 "EN Dash".
   const base::string16 ascii_space_he = UTF8ToUTF16("סיבית – ויקיפדיה");
-  const base::string16 ascii_space_en = ASCIIToUTF16("Bit - Wikipedia");
+  const base::string16 ascii_space_en = UTF8ToUTF16("Bit - Wikipedia");
 
   // This says "thank you very much" with a full-width non-ascii space (U+3000).
   const base::string16 full_width_space = UTF8ToUTF16("ども ありがと");
@@ -3035,8 +3007,8 @@
 
 // Ensure strings wrap onto multiple lines for a small available width.
 TEST_P(RenderTextHarfBuzzTest, Multiline_MinWidth) {
-  const wchar_t* kTestStrings[] = { kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl,
-                                    kRtlLtr, kRtlLtrRtl };
+  const char* kTestStrings[] = {kWeak, kLtr,    kLtrRtl,   kLtrRtlLtr,
+                                kRtl,  kRtlLtr, kRtlLtrRtl};
 
   RenderText* render_text = GetRenderText();
   render_text->SetDisplayRect(Rect(1, 1000));
@@ -3045,7 +3017,7 @@
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
     render_text->Draw(canvas());
     EXPECT_GT(test_api()->lines().size(), 1U);
   }
@@ -3056,7 +3028,7 @@
   // Should RenderText suppress drawing whitespace at the end of a line?
   // Currently it does not.
   const struct {
-    const wchar_t* const text;
+    const char* const text;
     const Range first_line_char_range;
     const Range second_line_char_range;
 
@@ -3068,22 +3040,22 @@
 
     bool is_ltr;
   } kTestStrings[] = {
-      {L"abc defg hijkl", Range(0, 9), Range(9, 14), {3, 1, 4, 1, 5}, 4, true},
-      {L"qwertyzxcvbn", Range(0, 10), Range(10, 12), {10, 2}, 1, true},
+      {"abc defg hijkl", Range(0, 9), Range(9, 14), {3, 1, 4, 1, 5}, 4, true},
+      {"qwertyzxcvbn", Range(0, 10), Range(10, 12), {10, 2}, 1, true},
       // RTL: should render left-to-right as "<space>43210 \n cba9876".
       // Note this used to say "Arabic language", in Arabic, but the last
-      // character in the string (\x0629) got fancy in an updated Mac font, so
+      // character in the string (\u0629) got fancy in an updated Mac font, so
       // now the penultimate character repeats. (See "NOTE" below).
-      {L"\x0627\x0644\x0644\x063A\x0629 "
-       L"\x0627\x0644\x0639\x0631\x0628\x064A\x064A",
+      {"\u0627\u0644\u0644\u063A\u0629 "
+       "\u0627\u0644\u0639\u0631\u0628\u064A\u064A",
        Range(0, 6),
        Range(6, 13),
        {1 /* space first */, 5, 7},
        2,
        false},
       // RTL: should render left-to-right as "<space>3210 \n cba98765".
-      {L"\x062A\x0641\x0627\x062D \x05EA\x05E4\x05D5\x05D6\x05D9"
-       L"\x05DA\x05DB\x05DD",
+      {"\u062A\u0641\u0627\u062D \u05EA\u05E4\u05D5\u05D6\u05D9"
+       "\u05DA\u05DB\u05DD",
        Range(0, 5),
        Range(5, 13),
        {1 /* space first */, 5, 8},
@@ -3102,7 +3074,7 @@
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestStrings[i].text));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
     DrawVisualText();
 
     ASSERT_EQ(2U, test_api()->lines().size());
@@ -3138,8 +3110,8 @@
 // Ensure strings don't wrap onto multiple lines for a sufficient available
 // width.
 TEST_P(RenderTextHarfBuzzTest, Multiline_SufficientWidth) {
-  const wchar_t* kTestStrings[] = { L"", L" ", L".", L" . ", L"abc", L"a b c",
-                                    L"\x62E\x628\x632", L"\x62E \x628 \x632" };
+  const char* kTestStrings[] = {"", " ", ".", " . ", "abc", "a b c",
+                                "\u062E\u0628\u0632", "\u062E \u0628 \u0632"};
 
   RenderText* render_text = GetRenderText();
   render_text->SetDisplayRect(Rect(1000, 1000));
@@ -3147,7 +3119,7 @@
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
     render_text->Draw(canvas());
     EXPECT_EQ(1U, test_api()->lines().size());
   }
@@ -3155,17 +3127,17 @@
 
 TEST_P(RenderTextHarfBuzzTest, Multiline_Newline) {
   const struct {
-    const wchar_t* const text;
+    const char* const text;
     const size_t lines_count;
     // Ranges of the characters on each line preceding the newline.
     const Range line_char_ranges[3];
   } kTestStrings[] = {
-      {L"abc\ndef", 2ul, {Range(0, 3), Range(4, 7), Range::InvalidRange()}},
-      {L"a \n b ", 2ul, {Range(0, 2), Range(3, 6), Range::InvalidRange()}},
-      {L"ab\n", 2ul, {Range(0, 2), Range(), Range::InvalidRange()}},
-      {L"a\n\nb", 3ul, {Range(0, 1), Range(2, 3), Range(3, 4)}},
-      {L"\nab", 2ul, {Range(0, 1), Range(1, 3), Range::InvalidRange()}},
-      {L"\n", 2ul, {Range(0, 1), Range(), Range::InvalidRange()}},
+      {"abc\ndef", 2ul, {Range(0, 3), Range(4, 7), Range::InvalidRange()}},
+      {"a \n b ", 2ul, {Range(0, 2), Range(3, 6), Range::InvalidRange()}},
+      {"ab\n", 2ul, {Range(0, 2), Range(), Range::InvalidRange()}},
+      {"a\n\nb", 3ul, {Range(0, 1), Range(2, 3), Range(3, 4)}},
+      {"\nab", 2ul, {Range(0, 1), Range(1, 3), Range::InvalidRange()}},
+      {"\n", 2ul, {Range(0, 1), Range(), Range::InvalidRange()}},
   };
 
   RenderText* render_text = GetRenderText();
@@ -3174,7 +3146,7 @@
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestStrings[i].text));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
     render_text->Draw(canvas());
     EXPECT_EQ(kTestStrings[i].lines_count, test_api()->lines().size());
     if (kTestStrings[i].lines_count != test_api()->lines().size())
@@ -3197,25 +3169,25 @@
 
 // Make sure that multiline mode ignores elide behavior.
 TEST_P(RenderTextHarfBuzzTest, Multiline_IgnoreElide) {
-  const wchar_t kTestString[] =
-      L"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx";
-  const wchar_t kEllipsis[] = L"\x2026";
+  const char kTestString[] =
+      "very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx";
+  const char kEllipsis[] = "\u2026";
 
   RenderText* render_text = GetRenderText();
   render_text->SetElideBehavior(ELIDE_TAIL);
   render_text->SetDisplayRect(Rect(20, 1000));
-  render_text->SetText(base::WideToUTF16(kTestString));
+  render_text->SetText(base::UTF8ToUTF16(kTestString));
   EXPECT_NE(base::string16::npos,
-            render_text->GetDisplayText().find(base::WideToUTF16(kEllipsis)));
+            render_text->GetDisplayText().find(base::UTF8ToUTF16(kEllipsis)));
 
   render_text->SetMultiline(true);
   EXPECT_EQ(base::string16::npos,
-            render_text->GetDisplayText().find(base::WideToUTF16(kEllipsis)));
+            render_text->GetDisplayText().find(base::UTF8ToUTF16(kEllipsis)));
 }
 
 TEST_P(RenderTextHarfBuzzTest, Multiline_NewlineCharacterReplacement) {
-  const wchar_t* kTestStrings[] = {
-    L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n",
+  const char* kTestStrings[] = {
+      "abc\ndef", "a \n b ", "ab\n", "a\n\nb", "\nab", "\n",
   };
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
@@ -3223,43 +3195,49 @@
     ResetRenderTextInstance();
     RenderText* render_text = GetRenderText();
     render_text->SetDisplayRect(Rect(200, 1000));
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
 
     base::string16 display_text = render_text->GetDisplayText();
     // If RenderText is not multiline, the newline characters are replaced
     // by symbols, therefore the character should be changed.
-    EXPECT_NE(WideToUTF16(kTestStrings[i]), render_text->GetDisplayText());
+    EXPECT_NE(UTF8ToUTF16(kTestStrings[i]), render_text->GetDisplayText());
 
     // Setting multiline will fix this, the newline characters will be back
     // to the original text.
     render_text->SetMultiline(true);
-    EXPECT_EQ(WideToUTF16(kTestStrings[i]), render_text->GetDisplayText());
+    EXPECT_EQ(UTF8ToUTF16(kTestStrings[i]), render_text->GetDisplayText());
   }
 }
 
 // Ensure horizontal alignment works in multiline mode.
 TEST_P(RenderTextHarfBuzzTest, Multiline_HorizontalAlignment) {
   constexpr struct {
-    const wchar_t* const text;
+    const char* const text;
     const HorizontalAlignment alignment;
     const base::i18n::TextDirection display_text_direction;
   } kTestStrings[] = {
-      {L"abcdefghi\nhijk", ALIGN_LEFT, base::i18n::LEFT_TO_RIGHT},
-      {L"nhij\nabcdefghi", ALIGN_LEFT, base::i18n::LEFT_TO_RIGHT},
+      {"abcdefghi\nhijk", ALIGN_LEFT, base::i18n::LEFT_TO_RIGHT},
+      {"nhij\nabcdefghi", ALIGN_LEFT, base::i18n::LEFT_TO_RIGHT},
       // Hebrew, 2nd line shorter
-      {L"\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7\n\x5d0\x5d1\x5d2\x5d3",
-       ALIGN_RIGHT, base::i18n::RIGHT_TO_LEFT},
+      {"\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\n"
+       "\u05d0\u05d1\u05d2\u05d3",
+       ALIGN_RIGHT,
+       base::i18n::RIGHT_TO_LEFT},
       // Hebrew, 2nd line longer
-      {L"\x5d0\x5d1\x5d2\x5d3\n\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7",
-       ALIGN_RIGHT, base::i18n::RIGHT_TO_LEFT},
+      {"\u05d0\u05d1\u05d2\u05d3\n"
+       "\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7",
+       ALIGN_RIGHT,
+       base::i18n::RIGHT_TO_LEFT},
       // Arabic, 2nd line shorter.
-      {L"\x0627\x0627\x0627\x0627\x0627\x0627\x0627\x0627\n\x0627\x0644\x0644"
-       L"\x063A",
-       ALIGN_RIGHT, base::i18n::RIGHT_TO_LEFT},
+      {"\u0627\u0627\u0627\u0627\u0627\u0627\u0627\u0627\n"
+       "\u0627\u0644\u0644\u063A",
+       ALIGN_RIGHT,
+       base::i18n::RIGHT_TO_LEFT},
       // Arabic, 2nd line longer.
-      {L"\x0627\x0644\x0644\x063A\n\x0627\x0627\x0627\x0627\x0627\x0627\x0627"
-       L"\x0627",
-       ALIGN_RIGHT, base::i18n::RIGHT_TO_LEFT},
+      {"\u0627\u0644\u0644\u063A\n"
+       "\u0627\u0627\u0627\u0627\u0627\u0627\u0627\u0627",
+       ALIGN_RIGHT,
+       base::i18n::RIGHT_TO_LEFT},
   };
   const int kGlyphSize = 5;
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
@@ -3271,7 +3249,7 @@
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(testing::Message("kTestStrings[")
                  << i << "] = " << kTestStrings[i].text);
-    render_text->SetText(WideToUTF16(kTestStrings[i].text));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
     EXPECT_EQ(kTestStrings[i].display_text_direction,
               render_text->GetDisplayTextDirection());
     render_text->Draw(canvas());
@@ -3281,8 +3259,8 @@
       EXPECT_EQ(0, test_api()->GetAlignmentOffset(1).x());
     } else {
       std::vector<base::string16> lines = base::SplitString(
-          base::WideToUTF16(kTestStrings[i].text),
-          base::string16(1, '\n'), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+          base::UTF8ToUTF16(kTestStrings[i].text), base::string16(1, '\n'),
+          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
       ASSERT_EQ(2u, lines.size());
 
       // Sanity check the input string lengths match the glyph lengths.
@@ -3318,7 +3296,7 @@
   };
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
   render_text->SetMultiline(true);
-  render_text->SetText(ASCIIToUTF16("foo fooooo foo"));
+  render_text->SetText(UTF8ToUTF16("foo fooooo foo"));
   SetGlyphWidth(kGlyphSize);
   render_text->SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0));
 
@@ -3342,36 +3320,37 @@
 TEST_P(RenderTextHarfBuzzTest, Multiline_LineBreakerBehavior) {
   const int kGlyphSize = 5;
   const struct {
-    const wchar_t* const text;
+    const char* const text;
     const WordWrapBehavior behavior;
     const Range char_ranges[3];
   } kTestScenarios[] = {
-      { L"a single run", IGNORE_LONG_WORDS,
-        {Range(0, 2), Range(2, 9), Range(9, 12) } },
+      {"a single run",
+       IGNORE_LONG_WORDS,
+       {Range(0, 2), Range(2, 9), Range(9, 12)}},
       // 3 words: "That's ", ""good". ", "aaa" and 7 runs: "That", "'", "s ",
       // """, "good", "". ", "aaa". They all mixed together.
-      { L"That's \"good\". aaa", IGNORE_LONG_WORDS,
-        {Range(0, 7), Range(7, 15), Range(15, 18) } },
+      {"That's \"good\". aaa", IGNORE_LONG_WORDS,
+       {Range(0, 7), Range(7, 15), Range(15, 18)}},
       // Test "\"" should be put into a new line correctly.
-      { L"a \"good\" one.", IGNORE_LONG_WORDS,
-        {Range(0, 2), Range(2, 9), Range(9, 13) } },
+      {"a \"good\" one.", IGNORE_LONG_WORDS,
+       {Range(0, 2), Range(2, 9), Range(9, 13)}},
       // Test for full-width space.
-      { L"That's\x3000good.\x3000yyy", IGNORE_LONG_WORDS,
-        {Range(0, 7), Range(7, 13), Range(13, 16) } },
-      { L"a single run", TRUNCATE_LONG_WORDS,
-        {Range(0, 2), Range(2, 6), Range(9, 12) } },
-      { L"That's \"good\". aaa", TRUNCATE_LONG_WORDS,
-        {Range(0, 4), Range(7, 11), Range(15, 18) } },
-      { L"That's good. aaa", TRUNCATE_LONG_WORDS,
-        {Range(0, 4), Range(7, 11), Range(13, 16) } },
-      { L"a \"good\" one.", TRUNCATE_LONG_WORDS,
-        {Range(0, 2), Range(2, 6), Range(9, 13) } },
-      { L"asingleword", WRAP_LONG_WORDS,
-        {Range(0, 4), Range(4, 8), Range(8, 11) } },
-      { L"That's good", WRAP_LONG_WORDS,
-        {Range(0, 4), Range(4, 7), Range(7, 11) } },
-      { L"That's \"g\".", WRAP_LONG_WORDS,
-        {Range(0, 4), Range(4, 7), Range(7, 11) } },
+      {"That's\u3000good.\u3000yyy", IGNORE_LONG_WORDS,
+       {Range(0, 7), Range(7, 13), Range(13, 16)}},
+      {"a single run", TRUNCATE_LONG_WORDS,
+       {Range(0, 2), Range(2, 6), Range(9, 12)}},
+      {"That's \"good\". aaa", TRUNCATE_LONG_WORDS,
+       {Range(0, 4), Range(7, 11), Range(15, 18)}},
+      {"That's good. aaa", TRUNCATE_LONG_WORDS,
+       {Range(0, 4), Range(7, 11), Range(13, 16)}},
+      {"a \"good\" one.", TRUNCATE_LONG_WORDS,
+       {Range(0, 2), Range(2, 6), Range(9, 13)}},
+      {"asingleword", WRAP_LONG_WORDS,
+       {Range(0, 4), Range(4, 8), Range(8, 11)}},
+      {"That's good", WRAP_LONG_WORDS,
+       {Range(0, 4), Range(4, 7), Range(7, 11)}},
+      {"That's \"g\".", WRAP_LONG_WORDS,
+       {Range(0, 4), Range(4, 7), Range(7, 11)}},
   };
 
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
@@ -3381,7 +3360,7 @@
 
   for (size_t i = 0; i < arraysize(kTestScenarios); ++i) {
     SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestScenarios[i].text));
+    render_text->SetText(UTF8ToUTF16(kTestScenarios[i].text));
     render_text->SetWordWrapBehavior(kTestScenarios[i].behavior);
     render_text->Draw(canvas());
 
@@ -3483,8 +3462,8 @@
 }
 
 TEST_P(RenderTextHarfBuzzTest, NewlineWithoutMultilineFlag) {
-  const wchar_t* kTestStrings[] = {
-    L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n",
+  const char* kTestStrings[] = {
+      "abc\ndef", "a \n b ", "ab\n", "a\n\nb", "\nab", "\n",
   };
 
   RenderText* render_text = GetRenderText();
@@ -3492,7 +3471,7 @@
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
     render_text->Draw(canvas());
 
     EXPECT_EQ(1U, test_api()->lines().size());
@@ -3503,20 +3482,18 @@
 // LTR languages and right-to-left for RTL languages).
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_HorizontalPositions) {
   const struct {
-    const wchar_t* const text;
+    const char* const text;
     const char* expected_runs;
   } kTestStrings[] = {
-      {L"abc\x3042\x3044\x3046\x3048\x304A", "[0->2][3->7]"},
-      {L"\x062A\x0641\x0627\x062D"
-       L"\x05EA\x05E4\x05D5\x05D6\x05D9\x05DA\x05DB\x05DD",
-       "[11<-4][3<-0]"},
+      {"abc\u3042\u3044\u3046\u3048\u304A", "[0->2][3->7]"},
+      {"\u062A\u0641\u0627\u062D\u05EA\u05E4\u05D5\u05D6", "[7<-4][3<-0]"},
   };
 
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
     SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
-    render_text->SetText(WideToUTF16(kTestStrings[i].text));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i].text));
 
     test_api()->EnsureLayout();
     EXPECT_EQ(kTestStrings[i].expected_runs, GetRunListStructureString());
@@ -3611,14 +3588,13 @@
 
 // Ensure that graphemes with multiple code points do not get split.
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_SubglyphGraphemeCases) {
-  const wchar_t* cases[] = {
-    // "A" with a combining umlaut, followed by a "B".
-    L"A\x0308" L"B",
-    // Devanagari biconsonantal conjunct "ki", followed by an "a".
-    L"\x0915\x093f\x0905",
-    // Thai consonant and vowel pair "cho chan" + "sara am", followed by Thai
-    // digit 0.
-    L"\x0e08\x0e33\x0E50",
+  const char* cases[] = {
+      // Ä (A with combining umlaut), followed by a "B".
+      "A\u0308B",
+      // कि (Devangari letter KA with vowel I), followed by an "a".
+      "\u0915\u093f\u0905",
+      // จำ (Thai charcters CHO CHAN and SARA AM, followed by Thai digit 0.
+      "\u0e08\u0e33\u0E50",
   };
 
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
@@ -3626,7 +3602,7 @@
   for (size_t i = 0; i < arraysize(cases); ++i) {
     SCOPED_TRACE(base::StringPrintf("Case %" PRIuS, i));
 
-    base::string16 text = WideToUTF16(cases[i]);
+    base::string16 text = UTF8ToUTF16(cases[i]);
     render_text->SetText(text);
     test_api()->EnsureLayout();
     const internal::TextRunList* run_list = GetHarfBuzzRunList();
@@ -3677,7 +3653,7 @@
   run.width = 20;
 
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
-  render_text->SetText(ASCIIToUTF16("abcd"));
+  render_text->SetText(UTF8ToUTF16("abcd"));
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
     std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 2,
@@ -3696,11 +3672,7 @@
 
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_RunDirection) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
-  const base::string16 mixed = WideToUTF16(
-      L"\x05D0\x05D1"
-      L"1234"
-      L"\x05D2\x05D3"
-      L"abc");
+  const base::string16 mixed = UTF8ToUTF16("\u05D0\u05D11234\u05D2\u05D3abc");
   render_text->SetText(mixed);
 
   // Get the run list for both display directions.
@@ -3716,13 +3688,13 @@
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByUnicodeBlocks) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
 
-  // The '\x25B6' "play character" should break runs. http://crbug.com/278913
-  render_text->SetText(WideToUTF16(L"x\x25B6y"));
+  // The ▶ (U+25B6) "play character" should break runs. http://crbug.com/278913
+  render_text->SetText(UTF8ToUTF16("x\u25B6y"));
   test_api()->EnsureLayout();
   EXPECT_EQ(ToString16Vec({"x", "▶", "y"}), GetRunListStrings());
   EXPECT_EQ("[0][1][2]", GetRunListStructureString());
 
-  render_text->SetText(WideToUTF16(L"x \x25B6 y"));
+  render_text->SetText(UTF8ToUTF16("x \u25B6 y"));
   test_api()->EnsureLayout();
   EXPECT_EQ(ToString16Vec({"x", " ", "▶", " ", "y"}), GetRunListStrings());
   EXPECT_EQ("[0][1][2][3][4]", GetRunListStructureString());
@@ -3731,10 +3703,10 @@
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByEmoji) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
 
-  // \xF0\x9F\x98\x81 (U+1F601) is smile icon emoji. \xE2\x9C\xA8 (U+2728) is
-  // a sparkle icon. Both can be drawn with color emoji fonts, so runs should be
-  // separated. See crbug.com/448909
-  render_text->SetText(UTF8ToUTF16("x\xF0\x9F\x98\x81y\xE2\x9C\xA8"));
+  // 😁 (U+1F601, a smile emoji) and ✨ (U+2728, a sparkle icon) can both be
+  // drawn with color emoji fonts, so runs should be separated. crbug.com/448909
+  // Windows requires wide strings for \Unnnnnnnn universal character names.
+  render_text->SetText(WideToUTF16(L"x\U0001F601y\u2728"));
   test_api()->EnsureLayout();
   EXPECT_EQ(ToString16Vec({"x", "😁", "y", "✨"}), GetRunListStrings());
   // U+1F601 is represented as a surrogate pair in UTF-16.
@@ -3744,9 +3716,9 @@
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByAscii) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
 
-  // \xF0\x9F\x90\xB1 (U+1F431) is a cat face. It should be put into a separate
-  // run from the ASCII period character.
-  render_text->SetText(UTF8ToUTF16("\xF0\x9F\x90\xB1."));
+  // 🐱 (U+1F431, a cat face) and an ASCII period should have separate runs.
+  // Windows requires wide strings for \Unnnnnnnn universal character names.
+  render_text->SetText(WideToUTF16(L"\U0001F431."));
   test_api()->EnsureLayout();
   EXPECT_EQ(ToString16Vec({"🐱", "."}), GetRunListStrings());
   // U+1F431 is represented as a surrogate pair in UTF-16.
@@ -3754,13 +3726,12 @@
 }
 
 TEST_P(RenderTextHarfBuzzTest, GlyphBounds) {
-  const wchar_t* kTestStrings[] = {
-      L"asdf 1234 qwer", L"\x0647\x0654", L"\x0645\x0631\x062D\x0628\x0627"
-  };
+  const char* kTestStrings[] = {"asdf 1234 qwer", "\u0647\u0654",
+                                "\u0645\u0631\u062D\u0628\u0627"};
   RenderText* render_text = GetRenderText();
 
   for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
-    render_text->SetText(WideToUTF16(kTestStrings[i]));
+    render_text->SetText(UTF8ToUTF16(kTestStrings[i]));
     test_api()->EnsureLayout();
 
     for (size_t j = 0; j < render_text->text().length(); ++j)
@@ -3771,7 +3742,7 @@
 // Ensure that shaping with a non-existent font does not cause a crash.
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_NonExistentFont) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
-  render_text->SetText(ASCIIToUTF16("test"));
+  render_text->SetText(UTF8ToUTF16("test"));
   test_api()->EnsureLayout();
   const internal::TextRunList* run_list = GetHarfBuzzRunList();
   ASSERT_EQ(1U, run_list->size());
@@ -3784,7 +3755,7 @@
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_EmptyRun) {
   internal::TextRunHarfBuzz run((Font()));
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
-  render_text->SetText(ASCIIToUTF16("abcdefgh"));
+  render_text->SetText(UTF8ToUTF16("abcdefgh"));
 
   run.range = Range(3, 8);
   run.glyph_count = 0;
@@ -3801,7 +3772,7 @@
 // actual size. See http://crbug.com/470073
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_WordWidthWithDiacritics) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
-  const base::string16 kWord = WideToUTF16(L"\u0906\u092A\u0915\u0947 ");
+  const base::string16 kWord = UTF8ToUTF16("\u0906\u092A\u0915\u0947 ");
   render_text->SetText(kWord);
   const SizeF text_size = render_text->GetStringSizeF();
 
@@ -3817,7 +3788,7 @@
 // Ensure a string fits in a display rect with a width equal to the string's.
 TEST_P(RenderTextTest, StringFitsOwnWidth) {
   RenderText* render_text = GetRenderText();
-  const base::string16 kString = ASCIIToUTF16("www.example.com");
+  const base::string16 kString = UTF8ToUTF16("www.example.com");
 
   render_text->SetText(kString);
   render_text->ApplyWeight(Font::Weight::BOLD, Range(0, 3));
@@ -3843,11 +3814,11 @@
   ASSERT_EQ(base::ToLowerASCII(kSymbolFontName),
             base::ToLowerASCII(fonts[1].GetActualFontNameForTesting()));
 
-  // "⊕" (CIRCLED PLUS) should be rendered with Symbol rather than falling back
-  // to some other font that's present on the system.
+  // "⊕" (U+2295, CIRCLED PLUS) should be rendered with Symbol rather than
+  // falling back to some other font that's present on the system.
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
   render_text->SetFontList(font_list);
-  render_text->SetText(UTF8ToUTF16("\xE2\x8A\x95"));
+  render_text->SetText(UTF8ToUTF16("\u2295"));
   const std::vector<RenderText::FontSpan> spans =
       render_text->GetFontSpansForTesting();
   ASSERT_EQ(static_cast<size_t>(1), spans.size());
@@ -3862,12 +3833,12 @@
   PlatformFontWin* font_win = new PlatformFontWin("Meiryo", 12);
   // Japanese name for Meiryo. This name won't be found in the system's linked
   // fonts, forcing RTHB to try the Uniscribe font and its fallbacks.
-  font_win->font_ref_->font_name_ = WideToUTF8(L"\x30e1\x30a4\x30ea\x30aa");
+  font_win->font_ref_->font_name_ = "\u30e1\u30a4\u30ea\u30aa";
   FontList font_list((Font(font_win)));
 
   render_text->SetFontList(font_list);
-  // Korean character "han".
-  render_text->SetText(WideToUTF16(L"\xd55c"));
+  // An invalid Unicode character that somehow yields Korean character "han".
+  render_text->SetText(UTF8ToUTF16("\ud55c"));
   test_api()->EnsureLayout();
   const internal::TextRunList* run_list = GetHarfBuzzRunList();
   ASSERT_EQ(1U, run_list->size());
@@ -3875,18 +3846,17 @@
 }
 #endif  // defined(OS_WIN)
 
-// Ensure that the fallback fonts offered by GetFallbackFonts() are
-// tried. Note this test assumes the font "Arial" doesn't provide a unicode
-// glyph for a particular character, and that there exists a system fallback
-// font which does.
+// Ensure that the fallback fonts offered by GetFallbackFonts() are tried. Note
+// this test assumes the font "Arial" doesn't provide a unicode glyph for a
+// particular character, and that there is a system fallback font which does.
 // TODO(msw): Fallback doesn't find a glyph on Linux.
 #if !defined(OS_LINUX)
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_UnicodeFallback) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
   render_text->SetFontList(FontList("Arial, 12px"));
 
-  // Korean character "han".
-  render_text->SetText(WideToUTF16(L"\xd55c"));
+  // An invalid Unicode character that somehow yields Korean character "han".
+  render_text->SetText(UTF8ToUTF16("\ud55c"));
   test_api()->EnsureLayout();
   const internal::TextRunList* run_list = GetHarfBuzzRunList();
   ASSERT_EQ(1U, run_list->size());
@@ -3905,19 +3875,17 @@
     return;
 #endif
 
-  const wchar_t* kTestStrings[] = {
-      L"            ",
+  const char* kTestStrings[] = {
+      "            ",
       // TODO(dschuyler): Underscores draw outside GetStringSize;
       // crbug.com/459812.  This appears to be a preexisting issue that wasn't
       // revealed by the prior unit tests.
-      // L"TEST_______",
-      L"TEST some stuff",
-      L"WWWWWWWWWW",
-      L"gAXAXAXAXAXAXA",
+      // "TEST_______",
+      "TEST some stuff", "WWWWWWWWWW", "gAXAXAXAXAXAXA",
       // TODO(dschuyler): A-Ring draws outside GetStringSize; crbug.com/459812.
-      // L"g\x00C5X\x00C5X\x00C5X\x00C5X\x00C5X\x00C5X\x00C5",
-      L"\x0647\x0654\x0647\x0654\x0647\x0654\x0647\x0654\x0645\x0631\x062D"
-      L"\x0628\x0627"};
+      // "g\u00C5X\u00C5X\u00C5X\u00C5X\u00C5X\u00C5X\u00C5",
+      "\u0647\u0654\u0647\u0654\u0647\u0654\u0647\u0654\u0645\u0631\u062D"
+      "\u0628\u0627"};
   const Size kCanvasSize(300, 50);
   const int kTestSize = 10;
 
@@ -3932,7 +3900,7 @@
 
   for (auto* string : kTestStrings) {
     paint_canvas.clear(SK_ColorWHITE);
-    render_text->SetText(WideToUTF16(string));
+    render_text->SetText(UTF8ToUTF16(string));
     const Size string_size = render_text->GetStringSize();
     render_text->ApplyBaselineStyle(SUPERSCRIPT, Range(1, 2));
     render_text->ApplyBaselineStyle(SUPERIOR, Range(3, 4));
@@ -4008,7 +3976,7 @@
 // Ensure that the text will clip to the display rect. Draws to a canvas and
 // checks whether any pixel beyond the bounding rectangle is colored.
 TEST_P(RenderTextTest, TextDoesClip) {
-  const wchar_t* kTestStrings[] = {L"TEST", L"W", L"WWWW", L"gAXAXWWWW"};
+  const char* kTestStrings[] = {"TEST", "W", "WWWW", "gAXAXWWWW"};
   const Size kCanvasSize(300, 50);
   const int kTestSize = 10;
 
@@ -4023,7 +3991,7 @@
 
   for (auto* string : kTestStrings) {
     paint_canvas.clear(SK_ColorWHITE);
-    render_text->SetText(WideToUTF16(string));
+    render_text->SetText(UTF8ToUTF16(string));
     const Size string_size = render_text->GetStringSize();
     int fake_width = string_size.width() / 2;
     int fake_height = string_size.height() / 2;
@@ -4063,7 +4031,7 @@
 #if defined(OS_MACOSX)
 TEST_P(RenderTextMacTest, Mac_ElidedText) {
   RenderTextMac* render_text = GetRenderTextMac();
-  base::string16 text(ASCIIToUTF16("This is an example."));
+  base::string16 text(UTF8ToUTF16("This is an example."));
   render_text->SetText(text);
   Size string_size = render_text->GetStringSize();
   render_text->SetDisplayRect(Rect(string_size));
@@ -4083,7 +4051,7 @@
 
 TEST_P(RenderTextMacTest, LinesInvalidationOnElideBehaviorChange) {
   RenderTextMac* render_text = GetRenderTextMac();
-  render_text->SetText(ASCIIToUTF16("This is an example"));
+  render_text->SetText(UTF8ToUTF16("This is an example"));
   test_api()->EnsureLayout();
   EXPECT_TRUE(GetCoreTextLine());
 
@@ -4096,7 +4064,7 @@
 // Ensure color changes are picked up by the RenderText implementation.
 TEST_P(RenderTextTest, ColorChange) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("x"));
+  render_text->SetText(UTF8ToUTF16("x"));
   DrawVisualText();
 
   std::vector<TestSkiaTextRenderer::TextLog> text_log;
@@ -4121,7 +4089,7 @@
   // needed). They also vary depending on the OS version, so set a known font.
   FontList font_list(Font("Arial", 10));
 
-  render_text->SetText(ASCIIToUTF16("x"));
+  render_text->SetText(UTF8ToUTF16("x"));
   render_text->SetFontList(font_list);
 
   DrawVisualText();
@@ -4146,7 +4114,7 @@
 // Ensure the painter adheres to RenderText::subpixel_rendering_suppressed().
 TEST_P(RenderTextTest, SubpixelRenderingSuppressed) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("x"));
+  render_text->SetText(UTF8ToUTF16("x"));
 
   DrawVisualText();
 #if defined(OS_LINUX)
@@ -4176,7 +4144,7 @@
 // Verify GetDecoratedWordAtPoint returns the correct baseline point and
 // decorated word for an LTR string.
 TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_LTR) {
-  const base::string16 ltr = ASCIIToUTF16("  ab  c ");
+  const base::string16 ltr = UTF8ToUTF16("  ab  c ");
   const int kWordOneStartIndex = 2;
   const int kWordTwoStartIndex = 6;
 
@@ -4194,7 +4162,7 @@
 
   // Create expected decorated text instances.
   DecoratedText expected_word_1;
-  expected_word_1.text = ASCIIToUTF16("ab");
+  expected_word_1.text = UTF8ToUTF16("ab");
   // Attributes for the characters 'a' and 'b' at logical indices 2 and 3
   // respectively.
   expected_word_1.attributes.push_back(CreateRangedAttribute(
@@ -4207,7 +4175,7 @@
       SelectionModel(kWordOneStartIndex, CURSOR_FORWARD), false);
 
   DecoratedText expected_word_2;
-  expected_word_2.text = ASCIIToUTF16("c");
+  expected_word_2.text = UTF8ToUTF16("c");
   // Attributes for character 'c' at logical index |kWordTwoStartIndex|.
   expected_word_2.attributes.push_back(
       CreateRangedAttribute(font_spans, 0, kWordTwoStartIndex,
@@ -4256,11 +4224,7 @@
 // Verify GetDecoratedWordAtPoint returns the correct baseline point and
 // decorated word for an RTL string.
 TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_RTL) {
-  const base::string16 rtl = WideToUTF16(
-      L" "
-      L"\x0634\x0632"
-      L"  "
-      L"\x0634");
+  const base::string16 rtl = UTF8ToUTF16(" \u0634\u0632  \u0634");
   const int kWordOneStartIndex = 1;
   const int kWordTwoStartIndex = 5;
 
@@ -4278,7 +4242,7 @@
 
   // Create expected decorated text instance.
   DecoratedText expected_word_1;
-  expected_word_1.text = WideToUTF16(L"\x0634\x0632");
+  expected_word_1.text = UTF8ToUTF16("\u0634\u0632");
   // Attributes for characters at logical indices 1 and 2.
   expected_word_1.attributes.push_back(CreateRangedAttribute(
       font_spans, 0, kWordOneStartIndex, Font::Weight::NORMAL, ITALIC_MASK));
@@ -4290,7 +4254,7 @@
       SelectionModel(kWordOneStartIndex + 1, CURSOR_FORWARD), false);
 
   DecoratedText expected_word_2;
-  expected_word_2.text = WideToUTF16(L"\x0634");
+  expected_word_2.text = UTF8ToUTF16("\u0634");
   // Attributes for character at logical index |kWordTwoStartIndex|.
   expected_word_2.attributes.push_back(CreateRangedAttribute(
       font_spans, 0, kWordTwoStartIndex, Font::Weight::NORMAL, UNDERLINE_MASK));
@@ -4338,7 +4302,7 @@
 
 // Test that GetDecoratedWordAtPoint behaves correctly for multiline text.
 TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Multiline) {
-  const base::string16 text = ASCIIToUTF16("a b\n..\ncd.");
+  const base::string16 text = UTF8ToUTF16("a b\n..\ncd.");
   const size_t kWordOneIndex = 0;    // Index of character 'a'.
   const size_t kWordTwoIndex = 2;    // Index of character 'b'.
   const size_t kWordThreeIndex = 7;  // Index of character 'c'.
@@ -4358,14 +4322,14 @@
       render_text->GetFontSpansForTesting();
 
   DecoratedText expected_word_1;
-  expected_word_1.text = ASCIIToUTF16("a");
+  expected_word_1.text = UTF8ToUTF16("a");
   expected_word_1.attributes.push_back(CreateRangedAttribute(
       font_spans, 0, kWordOneIndex, Font::Weight::SEMIBOLD, 0));
   const Rect left_glyph_word_1 =
       GetSubstringBoundsUnion(Range(kWordOneIndex, kWordOneIndex + 1));
 
   DecoratedText expected_word_2;
-  expected_word_2.text = ASCIIToUTF16("b");
+  expected_word_2.text = UTF8ToUTF16("b");
   expected_word_2.attributes.push_back(CreateRangedAttribute(
       font_spans, 0, kWordTwoIndex, Font::Weight::SEMIBOLD,
       UNDERLINE_MASK | STRIKE_MASK));
@@ -4373,7 +4337,7 @@
       GetSubstringBoundsUnion(Range(kWordTwoIndex, kWordTwoIndex + 1));
 
   DecoratedText expected_word_3;
-  expected_word_3.text = ASCIIToUTF16("cd");
+  expected_word_3.text = UTF8ToUTF16("cd");
   expected_word_3.attributes.push_back(
       CreateRangedAttribute(font_spans, 0, kWordThreeIndex,
                             Font::Weight::NORMAL, STRIKE_MASK | ITALIC_MASK));
@@ -4418,7 +4382,7 @@
 // Verify the boolean return value of GetDecoratedWordAtPoint.
 TEST_P(RenderTextHarfBuzzTest, GetDecoratedWordAtPoint_Return) {
   RenderText* render_text = GetRenderText();
-  render_text->SetText(ASCIIToUTF16("..."));
+  render_text->SetText(UTF8ToUTF16("..."));
 
   DecoratedText decorated_word;
   Point baseline_point;
@@ -4430,7 +4394,7 @@
   EXPECT_FALSE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
                                                     &baseline_point));
 
-  render_text->SetText(ASCIIToUTF16("abc"));
+  render_text->SetText(UTF8ToUTF16("abc"));
   query = render_text->GetCursorBounds(SelectionModel(0, CURSOR_FORWARD), false)
               .origin();
   EXPECT_TRUE(render_text->GetDecoratedWordAtPoint(query, &decorated_word,
@@ -4447,25 +4411,25 @@
 // Tests text selection made at end points of individual lines of multiline
 // text.
 TEST_P(RenderTextHarfBuzzTest, LineEndSelections) {
-  const wchar_t* const ltr = L"abc\n\ndef";
-  const wchar_t* const rtl = L"\x5d0\x5d1\x5d2\n\n\x5d3\x5d4\x5d5";
+  const char* const ltr = "abc\n\ndef";
+  const char* const rtl = "\u05d0\u05d1\u05d2\n\n\u05d3\u05d4\u05d5";
   const int left_x = -100;
   const int right_x = 200;
   struct {
-    const wchar_t* const text;
+    const char* const text;
     const int line_num;
     const int x;
-    const wchar_t* const selected_text;
+    const char* const selected_text;
   } cases[] = {
-      {ltr, 1, left_x, L"abc\n"},
-      {ltr, 1, right_x, L"abc\n\n"},
-      {ltr, 2, left_x, L"abc\n\n"},
+      {ltr, 1, left_x, "abc\n"},
+      {ltr, 1, right_x, "abc\n\n"},
+      {ltr, 2, left_x, "abc\n\n"},
       {ltr, 2, right_x, ltr},
 
-      {rtl, 1, left_x, L"\x5d0\x5d1\x5d2\n\n"},
-      {rtl, 1, right_x, L"\x5d0\x5d1\x5d2\n"},
+      {rtl, 1, left_x, "\u05d0\u05d1\u05d2\n\n"},
+      {rtl, 1, right_x, "\u05d0\u05d1\u05d2\n"},
       {rtl, 2, left_x, rtl},
-      {rtl, 2, right_x, L"\x5d0\x5d1\x5d2\n\n"},
+      {rtl, 2, right_x, "\u05d0\u05d1\u05d2\n\n"},
   };
 
   RenderText* render_text = GetRenderText();
@@ -4474,7 +4438,7 @@
 
   for (size_t i = 0; i < arraysize(cases); i++) {
     SCOPED_TRACE(base::StringPrintf("Testing case %" PRIuS "", i));
-    render_text->SetText(WideToUTF16(cases[i].text));
+    render_text->SetText(UTF8ToUTF16(cases[i].text));
     test_api()->EnsureLayout();
 
     EXPECT_EQ(3u, test_api()->lines().size());
@@ -4483,7 +4447,7 @@
 
     render_text->MoveCursorTo(
         Point(cases[i].x, GetCursorYForTesting(cases[i].line_num)), true);
-    EXPECT_EQ(WideToUTF16(cases[i].selected_text),
+    EXPECT_EQ(UTF8ToUTF16(cases[i].selected_text),
               GetSelectedText(render_text));
   }
 }
@@ -4493,7 +4457,7 @@
   RenderText* render_text = GetRenderText();
   render_text->SetMultiline(true);
   render_text->SetDisplayRect(Rect(200, 1000));
-  render_text->SetText(WideToUTF16(L"abc\n\ndef"));
+  render_text->SetText(UTF8ToUTF16("abc\n\ndef"));
   test_api()->EnsureLayout();
 
   const std::vector<Range> line_char_range = {Range(0, 3), Range(4, 5),
@@ -4527,14 +4491,14 @@
   const int kFontSize = 13;
   RenderText* render_text = GetRenderText();
   render_text->SetFontList(FontList(Font(font_name, kFontSize)));
-  render_text->SetText(ASCIIToUTF16("abc"));
+  render_text->SetText(UTF8ToUTF16("abc"));
 
   DrawVisualText();
 }
 
 TEST_P(RenderTextHarfBuzzTest, LinesInvalidationOnElideBehaviorChange) {
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
-  render_text->SetText(ASCIIToUTF16("This is an example"));
+  render_text->SetText(UTF8ToUTF16("This is an example"));
   test_api()->EnsureLayout();
   EXPECT_FALSE(test_api()->lines().empty());
 
@@ -4552,7 +4516,7 @@
   RenderText* render_text = GetRenderText();
   const int font_height = render_text->font_list().GetHeight();
   render_text->SetDisplayRect(Rect(500, font_height));
-  render_text->SetText(ASCIIToUTF16("abc"));
+  render_text->SetText(UTF8ToUTF16("abc"));
 
   // Select everything so the test can use GetSelectionBoundsUnion().
   render_text->SelectAll(false);
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index e5f0b55..760c9437 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -55,6 +55,8 @@
     "ca_renderer_layer_params.h",
     "dc_renderer_layer_params.cc",
     "dc_renderer_layer_params.h",
+    "extension_set.cc",
+    "extension_set.h",
     "gl_bindings.cc",
     "gl_bindings.h",
     "gl_bindings_autogen_gl.cc",
diff --git a/ui/gl/extension_set.cc b/ui/gl/extension_set.cc
new file mode 100644
index 0000000..f1b0154
--- /dev/null
+++ b/ui/gl/extension_set.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/extension_set.h"
+#include "base/strings/string_split.h"
+
+namespace gl {
+
+ExtensionSet MakeExtensionSet(const base::StringPiece& extensions_string) {
+  return ExtensionSet(SplitStringPiece(
+      extensions_string, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL));
+}
+
+bool HasExtension(const ExtensionSet& extension_set,
+                  const base::StringPiece& extension) {
+  return extension_set.find(extension) != extension_set.end();
+}
+
+}  // namespace gl
diff --git a/ui/gl/extension_set.h b/ui/gl/extension_set.h
new file mode 100644
index 0000000..e8d3622
--- /dev/null
+++ b/ui/gl/extension_set.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GL_EXTENSION_SET_H_
+#define UI_GL_EXTENSION_SET_H_
+
+#include "base/containers/flat_set.h"
+#include "base/strings/string_piece.h"
+#include "ui/gl/gl_export.h"
+
+namespace gl {
+
+using ExtensionSet = base::flat_set<base::StringPiece>;
+
+GL_EXPORT ExtensionSet
+MakeExtensionSet(const base::StringPiece& extensions_string);
+
+GL_EXPORT bool HasExtension(const ExtensionSet& extension_set,
+                            const base::StringPiece& extension);
+
+template <size_t N>
+inline bool HasExtension(const ExtensionSet& extension_set,
+                         const char (&extension)[N]) {
+  return HasExtension(extension_set, base::StringPiece(extension, N - 1));
+}
+
+}  // namespace gl
+
+#endif  // UI_GL_EXTENSION_SET_H_
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 6b8e085..7c20a09e 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -2724,25 +2724,22 @@
 
   if set_name == 'gl':
     file.write("""\
-void DriverGL::InitializeDynamicBindings(
-    const GLVersionInfo* ver, const std::string& context_extensions) {
-  std::string extensions = context_extensions + " ";
-  ALLOW_UNUSED_LOCAL(extensions);
-
+void DriverGL::InitializeDynamicBindings(const GLVersionInfo* ver,
+                                         const ExtensionSet& extensions) {
 """)
   elif set_name == 'egl':
     file.write("""\
 void DriverEGL::InitializeClientExtensionBindings() {
   std::string client_extensions(GetClientExtensions());
-  client_extensions += " ";
-  ALLOW_UNUSED_LOCAL(client_extensions);
+  ExtensionSet extensions(MakeExtensionSet(client_extensions));
+  ALLOW_UNUSED_LOCAL(extensions);
 
 """)
   else:
     file.write("""\
 void Driver%s::InitializeExtensionBindings() {
-  std::string extensions(GetPlatformExtensions());
-  extensions += " ";
+  std::string platform_extensions(GetPlatformExtensions());
+  ExtensionSet extensions(MakeExtensionSet(platform_extensions));
   ALLOW_UNUSED_LOCAL(extensions);
 
 """ % (set_name.upper(),))
@@ -2751,7 +2748,7 @@
     # Extra space at the end of the extension name is intentional,
     # it is used as a separator
     for extension in extensions:
-      file.write('  ext.b_%s = %s.find("%s ") != std::string::npos;\n' %
+      file.write('  ext.b_%s = HasExtension(%s, "%s");\n' %
                  (extension, extension_var, extension))
 
     for func in extension_funcs:
@@ -2760,7 +2757,7 @@
         WriteConditionalFuncBinding(file, func)
 
   OutputExtensionBindings(
-    'client_extensions',
+    'extensions',
     sorted(used_client_extensions),
     [ f for f in functions if IsClientExtensionFunc(f) ])
 
@@ -2769,8 +2766,8 @@
 }
 
 void DriverEGL::InitializeExtensionBindings() {
-  std::string extensions(GetPlatformExtensions());
-  extensions += " ";
+  std::string platform_extensions(GetPlatformExtensions());
+  ExtensionSet extensions(MakeExtensionSet(platform_extensions));
   ALLOW_UNUSED_LOCAL(extensions);
 
 """)
diff --git a/ui/gl/gl_api_unittest.cc b/ui/gl/gl_api_unittest.cc
index 0e025760..b57f54f 100644
--- a/ui/gl/gl_api_unittest.cc
+++ b/ui/gl/gl_api_unittest.cc
@@ -58,10 +58,16 @@
     }
     api_->Initialize(driver_.get());
 
-    std::unique_ptr<GLVersionInfo> version =
-        GetVersionInfoFromContext(api_.get());
-    driver_->InitializeDynamicBindings(
-        version.get(), GetGLExtensionsFromCurrentContext(api_.get()));
+    std::string extensions_string =
+        GetGLExtensionsFromCurrentContext(api_.get());
+    ExtensionSet extension_set = MakeExtensionSet(extensions_string);
+
+    auto version = std::make_unique<GLVersionInfo>(
+        reinterpret_cast<const char*>(api_->glGetStringFn(GL_VERSION)),
+        reinterpret_cast<const char*>(api_->glGetStringFn(GL_RENDERER)),
+        extension_set);
+
+    driver_->InitializeDynamicBindings(version.get(), extension_set);
     api_->set_version(std::move(version));
   }
 
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index 65733bc..df7895e 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -29,6 +29,7 @@
 #include "base/logging.h"
 #include "base/threading/thread_local.h"
 #include "build/build_config.h"
+#include "ui/gl/extension_set.h"
 #include "ui/gl/gl_export.h"
 
 // The standard OpenGL native extension headers are also included.
@@ -424,7 +425,7 @@
 struct GL_EXPORT DriverGL {
   void InitializeStaticBindings();
   void InitializeDynamicBindings(const GLVersionInfo* ver,
-                                 const std::string& context_extensions);
+                                 const ExtensionSet& extensions);
   void ClearBindings();
 
   ProcsGL fn;
diff --git a/ui/gl/gl_bindings_autogen_egl.cc b/ui/gl/gl_bindings_autogen_egl.cc
index 637996d7..52c8aafc 100644
--- a/ui/gl/gl_bindings_autogen_egl.cc
+++ b/ui/gl/gl_bindings_autogen_egl.cc
@@ -128,11 +128,11 @@
 
 void DriverEGL::InitializeClientExtensionBindings() {
   std::string client_extensions(GetClientExtensions());
-  client_extensions += " ";
-  ALLOW_UNUSED_LOCAL(client_extensions);
+  ExtensionSet extensions(MakeExtensionSet(client_extensions));
+  ALLOW_UNUSED_LOCAL(extensions);
 
   ext.b_EGL_EXT_platform_base =
-      client_extensions.find("EGL_EXT_platform_base ") != std::string::npos;
+      HasExtension(extensions, "EGL_EXT_platform_base");
 
   if (ext.b_EGL_EXT_platform_base) {
     fn.eglGetPlatformDisplayEXTFn =
@@ -142,51 +142,41 @@
 }
 
 void DriverEGL::InitializeExtensionBindings() {
-  std::string extensions(GetPlatformExtensions());
-  extensions += " ";
+  std::string platform_extensions(GetPlatformExtensions());
+  ExtensionSet extensions(MakeExtensionSet(platform_extensions));
   ALLOW_UNUSED_LOCAL(extensions);
 
   ext.b_EGL_ANGLE_d3d_share_handle_client_buffer =
-      extensions.find("EGL_ANGLE_d3d_share_handle_client_buffer ") !=
-      std::string::npos;
+      HasExtension(extensions, "EGL_ANGLE_d3d_share_handle_client_buffer");
   ext.b_EGL_ANGLE_program_cache_control =
-      extensions.find("EGL_ANGLE_program_cache_control ") != std::string::npos;
+      HasExtension(extensions, "EGL_ANGLE_program_cache_control");
   ext.b_EGL_ANGLE_query_surface_pointer =
-      extensions.find("EGL_ANGLE_query_surface_pointer ") != std::string::npos;
+      HasExtension(extensions, "EGL_ANGLE_query_surface_pointer");
   ext.b_EGL_ANGLE_stream_producer_d3d_texture_nv12 =
-      extensions.find("EGL_ANGLE_stream_producer_d3d_texture_nv12 ") !=
-      std::string::npos;
+      HasExtension(extensions, "EGL_ANGLE_stream_producer_d3d_texture_nv12");
   ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle =
-      extensions.find("EGL_ANGLE_surface_d3d_texture_2d_share_handle ") !=
-      std::string::npos;
+      HasExtension(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle");
   ext.b_EGL_CHROMIUM_sync_control =
-      extensions.find("EGL_CHROMIUM_sync_control ") != std::string::npos;
+      HasExtension(extensions, "EGL_CHROMIUM_sync_control");
   ext.b_EGL_EXT_image_flush_external =
-      extensions.find("EGL_EXT_image_flush_external ") != std::string::npos;
-  ext.b_EGL_KHR_fence_sync =
-      extensions.find("EGL_KHR_fence_sync ") != std::string::npos;
+      HasExtension(extensions, "EGL_EXT_image_flush_external");
+  ext.b_EGL_KHR_fence_sync = HasExtension(extensions, "EGL_KHR_fence_sync");
   ext.b_EGL_KHR_gl_texture_2D_image =
-      extensions.find("EGL_KHR_gl_texture_2D_image ") != std::string::npos;
-  ext.b_EGL_KHR_image = extensions.find("EGL_KHR_image ") != std::string::npos;
-  ext.b_EGL_KHR_image_base =
-      extensions.find("EGL_KHR_image_base ") != std::string::npos;
-  ext.b_EGL_KHR_stream =
-      extensions.find("EGL_KHR_stream ") != std::string::npos;
+      HasExtension(extensions, "EGL_KHR_gl_texture_2D_image");
+  ext.b_EGL_KHR_image = HasExtension(extensions, "EGL_KHR_image");
+  ext.b_EGL_KHR_image_base = HasExtension(extensions, "EGL_KHR_image_base");
+  ext.b_EGL_KHR_stream = HasExtension(extensions, "EGL_KHR_stream");
   ext.b_EGL_KHR_stream_consumer_gltexture =
-      extensions.find("EGL_KHR_stream_consumer_gltexture ") !=
-      std::string::npos;
+      HasExtension(extensions, "EGL_KHR_stream_consumer_gltexture");
   ext.b_EGL_KHR_swap_buffers_with_damage =
-      extensions.find("EGL_KHR_swap_buffers_with_damage ") != std::string::npos;
-  ext.b_EGL_KHR_wait_sync =
-      extensions.find("EGL_KHR_wait_sync ") != std::string::npos;
+      HasExtension(extensions, "EGL_KHR_swap_buffers_with_damage");
+  ext.b_EGL_KHR_wait_sync = HasExtension(extensions, "EGL_KHR_wait_sync");
   ext.b_EGL_NV_post_sub_buffer =
-      extensions.find("EGL_NV_post_sub_buffer ") != std::string::npos;
+      HasExtension(extensions, "EGL_NV_post_sub_buffer");
   ext.b_EGL_NV_stream_consumer_gltexture_yuv =
-      extensions.find("EGL_NV_stream_consumer_gltexture_yuv ") !=
-      std::string::npos;
+      HasExtension(extensions, "EGL_NV_stream_consumer_gltexture_yuv");
   ext.b_GL_CHROMIUM_egl_khr_fence_sync_hack =
-      extensions.find("GL_CHROMIUM_egl_khr_fence_sync_hack ") !=
-      std::string::npos;
+      HasExtension(extensions, "GL_CHROMIUM_egl_khr_fence_sync_hack");
 
   if (ext.b_EGL_KHR_image || ext.b_EGL_KHR_image_base ||
       ext.b_EGL_KHR_gl_texture_2D_image) {
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index 37dc9e3..fadb5c0 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -547,152 +547,128 @@
   fn.glWaitSyncFn = 0;
 }
 
-void DriverGL::InitializeDynamicBindings(
-    const GLVersionInfo* ver,
-    const std::string& context_extensions) {
-  std::string extensions = context_extensions + " ";
-  ALLOW_UNUSED_LOCAL(extensions);
-
+void DriverGL::InitializeDynamicBindings(const GLVersionInfo* ver,
+                                         const ExtensionSet& extensions) {
   ext.b_GL_ANGLE_framebuffer_blit =
-      extensions.find("GL_ANGLE_framebuffer_blit ") != std::string::npos;
+      HasExtension(extensions, "GL_ANGLE_framebuffer_blit");
   ext.b_GL_ANGLE_framebuffer_multisample =
-      extensions.find("GL_ANGLE_framebuffer_multisample ") != std::string::npos;
+      HasExtension(extensions, "GL_ANGLE_framebuffer_multisample");
   ext.b_GL_ANGLE_instanced_arrays =
-      extensions.find("GL_ANGLE_instanced_arrays ") != std::string::npos;
+      HasExtension(extensions, "GL_ANGLE_instanced_arrays");
   ext.b_GL_ANGLE_request_extension =
-      extensions.find("GL_ANGLE_request_extension ") != std::string::npos;
+      HasExtension(extensions, "GL_ANGLE_request_extension");
   ext.b_GL_ANGLE_robust_client_memory =
-      extensions.find("GL_ANGLE_robust_client_memory ") != std::string::npos;
+      HasExtension(extensions, "GL_ANGLE_robust_client_memory");
   ext.b_GL_ANGLE_translated_shader_source =
-      extensions.find("GL_ANGLE_translated_shader_source ") !=
-      std::string::npos;
-  ext.b_GL_APPLE_fence =
-      extensions.find("GL_APPLE_fence ") != std::string::npos;
+      HasExtension(extensions, "GL_ANGLE_translated_shader_source");
+  ext.b_GL_APPLE_fence = HasExtension(extensions, "GL_APPLE_fence");
   ext.b_GL_APPLE_vertex_array_object =
-      extensions.find("GL_APPLE_vertex_array_object ") != std::string::npos;
+      HasExtension(extensions, "GL_APPLE_vertex_array_object");
   ext.b_GL_ARB_blend_func_extended =
-      extensions.find("GL_ARB_blend_func_extended ") != std::string::npos;
-  ext.b_GL_ARB_draw_buffers =
-      extensions.find("GL_ARB_draw_buffers ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_blend_func_extended");
+  ext.b_GL_ARB_draw_buffers = HasExtension(extensions, "GL_ARB_draw_buffers");
   ext.b_GL_ARB_draw_instanced =
-      extensions.find("GL_ARB_draw_instanced ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_draw_instanced");
   ext.b_GL_ARB_get_program_binary =
-      extensions.find("GL_ARB_get_program_binary ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_get_program_binary");
   ext.b_GL_ARB_instanced_arrays =
-      extensions.find("GL_ARB_instanced_arrays ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_instanced_arrays");
   ext.b_GL_ARB_internalformat_query =
-      extensions.find("GL_ARB_internalformat_query ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_internalformat_query");
   ext.b_GL_ARB_map_buffer_range =
-      extensions.find("GL_ARB_map_buffer_range ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_map_buffer_range");
   ext.b_GL_ARB_occlusion_query =
-      extensions.find("GL_ARB_occlusion_query ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_occlusion_query");
   ext.b_GL_ARB_program_interface_query =
-      extensions.find("GL_ARB_program_interface_query ") != std::string::npos;
-  ext.b_GL_ARB_robustness =
-      extensions.find("GL_ARB_robustness ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_program_interface_query");
+  ext.b_GL_ARB_robustness = HasExtension(extensions, "GL_ARB_robustness");
   ext.b_GL_ARB_sampler_objects =
-      extensions.find("GL_ARB_sampler_objects ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_sampler_objects");
   ext.b_GL_ARB_shader_image_load_store =
-      extensions.find("GL_ARB_shader_image_load_store ") != std::string::npos;
-  ext.b_GL_ARB_sync = extensions.find("GL_ARB_sync ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_shader_image_load_store");
+  ext.b_GL_ARB_sync = HasExtension(extensions, "GL_ARB_sync");
   ext.b_GL_ARB_texture_multisample =
-      extensions.find("GL_ARB_texture_multisample ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_texture_multisample");
   ext.b_GL_ARB_texture_storage =
-      extensions.find("GL_ARB_texture_storage ") != std::string::npos;
-  ext.b_GL_ARB_timer_query =
-      extensions.find("GL_ARB_timer_query ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_texture_storage");
+  ext.b_GL_ARB_timer_query = HasExtension(extensions, "GL_ARB_timer_query");
   ext.b_GL_ARB_transform_feedback2 =
-      extensions.find("GL_ARB_transform_feedback2 ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_transform_feedback2");
   ext.b_GL_ARB_vertex_array_object =
-      extensions.find("GL_ARB_vertex_array_object ") != std::string::npos;
+      HasExtension(extensions, "GL_ARB_vertex_array_object");
   ext.b_GL_CHROMIUM_bind_uniform_location =
-      extensions.find("GL_CHROMIUM_bind_uniform_location ") !=
-      std::string::npos;
+      HasExtension(extensions, "GL_CHROMIUM_bind_uniform_location");
   ext.b_GL_CHROMIUM_compressed_copy_texture =
-      extensions.find("GL_CHROMIUM_compressed_copy_texture ") !=
-      std::string::npos;
+      HasExtension(extensions, "GL_CHROMIUM_compressed_copy_texture");
   ext.b_GL_CHROMIUM_copy_compressed_texture =
-      extensions.find("GL_CHROMIUM_copy_compressed_texture ") !=
-      std::string::npos;
+      HasExtension(extensions, "GL_CHROMIUM_copy_compressed_texture");
   ext.b_GL_CHROMIUM_copy_texture =
-      extensions.find("GL_CHROMIUM_copy_texture ") != std::string::npos;
+      HasExtension(extensions, "GL_CHROMIUM_copy_texture");
   ext.b_GL_CHROMIUM_gles_depth_binding_hack =
-      extensions.find("GL_CHROMIUM_gles_depth_binding_hack ") !=
-      std::string::npos;
+      HasExtension(extensions, "GL_CHROMIUM_gles_depth_binding_hack");
   ext.b_GL_CHROMIUM_glgetstringi_hack =
-      extensions.find("GL_CHROMIUM_glgetstringi_hack ") != std::string::npos;
+      HasExtension(extensions, "GL_CHROMIUM_glgetstringi_hack");
   ext.b_GL_EXT_blend_func_extended =
-      extensions.find("GL_EXT_blend_func_extended ") != std::string::npos;
-  ext.b_GL_EXT_debug_marker =
-      extensions.find("GL_EXT_debug_marker ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_blend_func_extended");
+  ext.b_GL_EXT_debug_marker = HasExtension(extensions, "GL_EXT_debug_marker");
   ext.b_GL_EXT_direct_state_access =
-      extensions.find("GL_EXT_direct_state_access ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_direct_state_access");
   ext.b_GL_EXT_discard_framebuffer =
-      extensions.find("GL_EXT_discard_framebuffer ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_discard_framebuffer");
   ext.b_GL_EXT_disjoint_timer_query =
-      extensions.find("GL_EXT_disjoint_timer_query ") != std::string::npos;
-  ext.b_GL_EXT_draw_buffers =
-      extensions.find("GL_EXT_draw_buffers ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_disjoint_timer_query");
+  ext.b_GL_EXT_draw_buffers = HasExtension(extensions, "GL_EXT_draw_buffers");
   ext.b_GL_EXT_framebuffer_blit =
-      extensions.find("GL_EXT_framebuffer_blit ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_framebuffer_blit");
   ext.b_GL_EXT_framebuffer_multisample =
-      extensions.find("GL_EXT_framebuffer_multisample ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_framebuffer_multisample");
   ext.b_GL_EXT_framebuffer_object =
-      extensions.find("GL_EXT_framebuffer_object ") != std::string::npos;
-  ext.b_GL_EXT_gpu_shader4 =
-      extensions.find("GL_EXT_gpu_shader4 ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_framebuffer_object");
+  ext.b_GL_EXT_gpu_shader4 = HasExtension(extensions, "GL_EXT_gpu_shader4");
   ext.b_GL_EXT_instanced_arrays =
-      extensions.find("GL_EXT_instanced_arrays ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_instanced_arrays");
   ext.b_GL_EXT_map_buffer_range =
-      extensions.find("GL_EXT_map_buffer_range ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_map_buffer_range");
   ext.b_GL_EXT_multisampled_render_to_texture =
-      extensions.find("GL_EXT_multisampled_render_to_texture ") !=
-      std::string::npos;
+      HasExtension(extensions, "GL_EXT_multisampled_render_to_texture");
   ext.b_GL_EXT_occlusion_query_boolean =
-      extensions.find("GL_EXT_occlusion_query_boolean ") != std::string::npos;
-  ext.b_GL_EXT_robustness =
-      extensions.find("GL_EXT_robustness ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_occlusion_query_boolean");
+  ext.b_GL_EXT_robustness = HasExtension(extensions, "GL_EXT_robustness");
   ext.b_GL_EXT_shader_image_load_store =
-      extensions.find("GL_EXT_shader_image_load_store ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_shader_image_load_store");
   ext.b_GL_EXT_texture_buffer =
-      extensions.find("GL_EXT_texture_buffer ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_texture_buffer");
   ext.b_GL_EXT_texture_buffer_object =
-      extensions.find("GL_EXT_texture_buffer_object ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_texture_buffer_object");
   ext.b_GL_EXT_texture_storage =
-      extensions.find("GL_EXT_texture_storage ") != std::string::npos;
-  ext.b_GL_EXT_timer_query =
-      extensions.find("GL_EXT_timer_query ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_texture_storage");
+  ext.b_GL_EXT_timer_query = HasExtension(extensions, "GL_EXT_timer_query");
   ext.b_GL_EXT_transform_feedback =
-      extensions.find("GL_EXT_transform_feedback ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_transform_feedback");
   ext.b_GL_EXT_unpack_subimage =
-      extensions.find("GL_EXT_unpack_subimage ") != std::string::npos;
+      HasExtension(extensions, "GL_EXT_unpack_subimage");
   ext.b_GL_IMG_multisampled_render_to_texture =
-      extensions.find("GL_IMG_multisampled_render_to_texture ") !=
-      std::string::npos;
+      HasExtension(extensions, "GL_IMG_multisampled_render_to_texture");
   ext.b_GL_INTEL_framebuffer_CMAA =
-      extensions.find("GL_INTEL_framebuffer_CMAA ") != std::string::npos;
+      HasExtension(extensions, "GL_INTEL_framebuffer_CMAA");
   ext.b_GL_KHR_blend_equation_advanced =
-      extensions.find("GL_KHR_blend_equation_advanced ") != std::string::npos;
-  ext.b_GL_KHR_debug = extensions.find("GL_KHR_debug ") != std::string::npos;
-  ext.b_GL_KHR_robustness =
-      extensions.find("GL_KHR_robustness ") != std::string::npos;
+      HasExtension(extensions, "GL_KHR_blend_equation_advanced");
+  ext.b_GL_KHR_debug = HasExtension(extensions, "GL_KHR_debug");
+  ext.b_GL_KHR_robustness = HasExtension(extensions, "GL_KHR_robustness");
   ext.b_GL_NV_blend_equation_advanced =
-      extensions.find("GL_NV_blend_equation_advanced ") != std::string::npos;
-  ext.b_GL_NV_fence = extensions.find("GL_NV_fence ") != std::string::npos;
+      HasExtension(extensions, "GL_NV_blend_equation_advanced");
+  ext.b_GL_NV_fence = HasExtension(extensions, "GL_NV_fence");
   ext.b_GL_NV_framebuffer_mixed_samples =
-      extensions.find("GL_NV_framebuffer_mixed_samples ") != std::string::npos;
-  ext.b_GL_NV_path_rendering =
-      extensions.find("GL_NV_path_rendering ") != std::string::npos;
-  ext.b_GL_OES_EGL_image =
-      extensions.find("GL_OES_EGL_image ") != std::string::npos;
+      HasExtension(extensions, "GL_NV_framebuffer_mixed_samples");
+  ext.b_GL_NV_path_rendering = HasExtension(extensions, "GL_NV_path_rendering");
+  ext.b_GL_OES_EGL_image = HasExtension(extensions, "GL_OES_EGL_image");
   ext.b_GL_OES_get_program_binary =
-      extensions.find("GL_OES_get_program_binary ") != std::string::npos;
-  ext.b_GL_OES_mapbuffer =
-      extensions.find("GL_OES_mapbuffer ") != std::string::npos;
+      HasExtension(extensions, "GL_OES_get_program_binary");
+  ext.b_GL_OES_mapbuffer = HasExtension(extensions, "GL_OES_mapbuffer");
   ext.b_GL_OES_texture_buffer =
-      extensions.find("GL_OES_texture_buffer ") != std::string::npos;
+      HasExtension(extensions, "GL_OES_texture_buffer");
   ext.b_GL_OES_vertex_array_object =
-      extensions.find("GL_OES_vertex_array_object ") != std::string::npos;
+      HasExtension(extensions, "GL_OES_vertex_array_object");
 
   if (ext.b_GL_INTEL_framebuffer_CMAA) {
     fn.glApplyFramebufferAttachmentCMAAINTELFn =
diff --git a/ui/gl/gl_bindings_autogen_glx.cc b/ui/gl/gl_bindings_autogen_glx.cc
index ef9f9ef9..ed79f1d 100644
--- a/ui/gl/gl_bindings_autogen_glx.cc
+++ b/ui/gl/gl_bindings_autogen_glx.cc
@@ -114,26 +114,22 @@
 }
 
 void DriverGLX::InitializeExtensionBindings() {
-  std::string extensions(GetPlatformExtensions());
-  extensions += " ";
+  std::string platform_extensions(GetPlatformExtensions());
+  ExtensionSet extensions(MakeExtensionSet(platform_extensions));
   ALLOW_UNUSED_LOCAL(extensions);
 
   ext.b_GLX_ARB_create_context =
-      extensions.find("GLX_ARB_create_context ") != std::string::npos;
-  ext.b_GLX_EXT_swap_control =
-      extensions.find("GLX_EXT_swap_control ") != std::string::npos;
+      HasExtension(extensions, "GLX_ARB_create_context");
+  ext.b_GLX_EXT_swap_control = HasExtension(extensions, "GLX_EXT_swap_control");
   ext.b_GLX_EXT_texture_from_pixmap =
-      extensions.find("GLX_EXT_texture_from_pixmap ") != std::string::npos;
+      HasExtension(extensions, "GLX_EXT_texture_from_pixmap");
   ext.b_GLX_MESA_copy_sub_buffer =
-      extensions.find("GLX_MESA_copy_sub_buffer ") != std::string::npos;
+      HasExtension(extensions, "GLX_MESA_copy_sub_buffer");
   ext.b_GLX_MESA_swap_control =
-      extensions.find("GLX_MESA_swap_control ") != std::string::npos;
-  ext.b_GLX_OML_sync_control =
-      extensions.find("GLX_OML_sync_control ") != std::string::npos;
-  ext.b_GLX_SGIX_fbconfig =
-      extensions.find("GLX_SGIX_fbconfig ") != std::string::npos;
-  ext.b_GLX_SGI_video_sync =
-      extensions.find("GLX_SGI_video_sync ") != std::string::npos;
+      HasExtension(extensions, "GLX_MESA_swap_control");
+  ext.b_GLX_OML_sync_control = HasExtension(extensions, "GLX_OML_sync_control");
+  ext.b_GLX_SGIX_fbconfig = HasExtension(extensions, "GLX_SGIX_fbconfig");
+  ext.b_GLX_SGI_video_sync = HasExtension(extensions, "GLX_SGI_video_sync");
 
   if (ext.b_GLX_EXT_texture_from_pixmap) {
     fn.glXBindTexImageEXTFn = reinterpret_cast<glXBindTexImageEXTProc>(
diff --git a/ui/gl/gl_bindings_autogen_osmesa.cc b/ui/gl/gl_bindings_autogen_osmesa.cc
index 27185e3..c629e83 100644
--- a/ui/gl/gl_bindings_autogen_osmesa.cc
+++ b/ui/gl/gl_bindings_autogen_osmesa.cc
@@ -48,8 +48,8 @@
 }
 
 void DriverOSMESA::InitializeExtensionBindings() {
-  std::string extensions(GetPlatformExtensions());
-  extensions += " ";
+  std::string platform_extensions(GetPlatformExtensions());
+  ExtensionSet extensions(MakeExtensionSet(platform_extensions));
   ALLOW_UNUSED_LOCAL(extensions);
 }
 
diff --git a/ui/gl/gl_bindings_autogen_wgl.cc b/ui/gl/gl_bindings_autogen_wgl.cc
index 465f13a2..d6bdc1e 100644
--- a/ui/gl/gl_bindings_autogen_wgl.cc
+++ b/ui/gl/gl_bindings_autogen_wgl.cc
@@ -58,22 +58,19 @@
 }
 
 void DriverWGL::InitializeExtensionBindings() {
-  std::string extensions(GetPlatformExtensions());
-  extensions += " ";
+  std::string platform_extensions(GetPlatformExtensions());
+  ExtensionSet extensions(MakeExtensionSet(platform_extensions));
   ALLOW_UNUSED_LOCAL(extensions);
 
   ext.b_WGL_ARB_create_context =
-      extensions.find("WGL_ARB_create_context ") != std::string::npos;
+      HasExtension(extensions, "WGL_ARB_create_context");
   ext.b_WGL_ARB_extensions_string =
-      extensions.find("WGL_ARB_extensions_string ") != std::string::npos;
-  ext.b_WGL_ARB_pbuffer =
-      extensions.find("WGL_ARB_pbuffer ") != std::string::npos;
-  ext.b_WGL_ARB_pixel_format =
-      extensions.find("WGL_ARB_pixel_format ") != std::string::npos;
+      HasExtension(extensions, "WGL_ARB_extensions_string");
+  ext.b_WGL_ARB_pbuffer = HasExtension(extensions, "WGL_ARB_pbuffer");
+  ext.b_WGL_ARB_pixel_format = HasExtension(extensions, "WGL_ARB_pixel_format");
   ext.b_WGL_EXT_extensions_string =
-      extensions.find("WGL_EXT_extensions_string ") != std::string::npos;
-  ext.b_WGL_EXT_swap_control =
-      extensions.find("WGL_EXT_swap_control ") != std::string::npos;
+      HasExtension(extensions, "WGL_EXT_extensions_string");
+  ext.b_WGL_EXT_swap_control = HasExtension(extensions, "WGL_EXT_swap_control");
 
   if (ext.b_WGL_ARB_pixel_format) {
     fn.wglChoosePixelFormatARBFn =
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc
index 44cf4133..9dd442dc 100644
--- a/ui/gl/gl_context.cc
+++ b/ui/gl/gl_context.cc
@@ -125,11 +125,6 @@
   NOTIMPLEMENTED();
 }
 
-std::string GLContext::GetExtensions() {
-  DCHECK(IsCurrent(nullptr));
-  return GetGLExtensionsFromCurrentContext(gl_api_.get());
-}
-
 std::string GLContext::GetGLVersion() {
   DCHECK(IsCurrent(nullptr));
   DCHECK(gl_api_ != nullptr);
@@ -184,6 +179,7 @@
 void GLContext::ReinitializeDynamicBindings() {
   DCHECK(IsCurrent(nullptr));
   dynamic_bindings_initialized_ = false;
+  ResetExtensions();
   InitializeDynamicBindings();
 }
 
@@ -192,13 +188,7 @@
 }
 
 bool GLContext::HasExtension(const char* name) {
-  std::string extensions = GetExtensions();
-  extensions += " ";
-
-  std::string delimited_name(name);
-  delimited_name += " ";
-
-  return extensions.find(delimited_name) != std::string::npos;
+  return gl::HasExtension(GetExtensions(), name);
 }
 
 const GLVersionInfo* GLContext::GetVersionInfo() {
@@ -246,7 +236,7 @@
 
 std::unique_ptr<gl::GLVersionInfo> GLContext::GenerateGLVersionInfo() {
   return base::MakeUnique<GLVersionInfo>(
-      GetGLVersion().c_str(), GetGLRenderer().c_str(), GetExtensions().c_str());
+      GetGLVersion().c_str(), GetGLRenderer().c_str(), GetExtensions());
 }
 
 void GLContext::SetCurrent(GLSurface* surface) {
@@ -393,6 +383,14 @@
   return gpu_timing_->CreateGPUTimingClient();
 }
 
+const ExtensionSet& GLContextReal::GetExtensions() {
+  DCHECK(IsCurrent(nullptr));
+  if (!extensions_initialized_) {
+    SetExtensionsFromString(GetGLExtensionsFromCurrentContext(gl_api()));
+  }
+  return extensions_;
+}
+
 GLContextReal::~GLContextReal() {
   if (GetRealCurrent() == this)
     current_real_context_.Pointer()->Set(nullptr);
@@ -411,4 +409,16 @@
   return context;
 }
 
+void GLContextReal::SetExtensionsFromString(std::string extensions) {
+  extensions_string_ = std::move(extensions);
+  extensions_ = MakeExtensionSet(extensions_string_);
+  extensions_initialized_ = true;
+}
+
+void GLContextReal::ResetExtensions() {
+  extensions_.clear();
+  extensions_string_.clear();
+  extensions_initialized_ = false;
+}
+
 }  // namespace gl
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h
index 13b86df..5fe126a 100644
--- a/ui/gl/gl_context.h
+++ b/ui/gl/gl_context.h
@@ -7,13 +7,13 @@
 
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "base/atomicops.h"
 #include "base/cancelable_callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/cancellation_flag.h"
+#include "ui/gl/extension_set.h"
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_state_restorer.h"
@@ -133,8 +133,8 @@
   // passed to SetSwapInterval.
   void ForceSwapIntervalZero(bool force);
 
-  // Returns space separated list of extensions. The context must be current.
-  virtual std::string GetExtensions();
+  // Returns set of extensions. The context must be current.
+  virtual const ExtensionSet& GetExtensions() = 0;
 
   // Indicate that it is safe to force this context to switch GPUs, since
   // transitioning can cause corruption and hangs (OS X only).
@@ -239,6 +239,9 @@
   static GLContext* GetRealCurrent();
 
   virtual void OnSetSwapInterval(int interval) = 0;
+  virtual void ResetExtensions() = 0;
+
+  GLApi* gl_api() { return gl_api_.get(); }
 
  private:
   friend class base::RefCounted<GLContext>;
@@ -285,14 +288,22 @@
  public:
   explicit GLContextReal(GLShareGroup* share_group);
   scoped_refptr<GPUTimingClient> CreateGPUTimingClient() override;
+  const ExtensionSet& GetExtensions() override;
 
  protected:
   ~GLContextReal() override;
 
+  void ResetExtensions() override;
+
   void SetCurrent(GLSurface* surface) override;
+  void SetExtensionsFromString(std::string extensions);
+  const std::string& extension_string() { return extensions_string_; }
 
  private:
   std::unique_ptr<GPUTiming> gpu_timing_;
+  std::string extensions_string_;
+  ExtensionSet extensions_;
+  bool extensions_initialized_ = false;
   DISALLOW_COPY_AND_ASSIGN(GLContextReal);
 };
 
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index 8a5638b..716c0ca 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -291,15 +291,6 @@
   }
 }
 
-std::string GLContextEGL::GetExtensions() {
-  const char* extensions = eglQueryString(display_,
-                                          EGL_EXTENSIONS);
-  if (!extensions)
-    return GLContext::GetExtensions();
-
-  return GLContext::GetExtensions() + " " + extensions;
-}
-
 bool GLContextEGL::WasAllocatedUsingRobustnessExtension() {
   return GLSurfaceEGL::IsCreateContextRobustnessSupported();
 }
diff --git a/ui/gl/gl_context_egl.h b/ui/gl/gl_context_egl.h
index 6a436dc..75b2f320 100644
--- a/ui/gl/gl_context_egl.h
+++ b/ui/gl/gl_context_egl.h
@@ -33,7 +33,6 @@
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
   void OnSetSwapInterval(int interval) override;
-  std::string GetExtensions() override;
   bool WasAllocatedUsingRobustnessExtension() override;
   void SetUnbindFboOnMakeCurrent() override;
 
diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc
index 5475f4e..d66d3119 100644
--- a/ui/gl/gl_context_glx.cc
+++ b/ui/gl/gl_context_glx.cc
@@ -297,16 +297,6 @@
   }
 }
 
-std::string GLContextGLX::GetExtensions() {
-  DCHECK(IsCurrent(nullptr));
-  const char* extensions = GLSurfaceGLX::GetGLXExtensions();
-  if (extensions) {
-    return GLContext::GetExtensions() + " " + extensions;
-  }
-
-  return GLContext::GetExtensions();
-}
-
 bool GLContextGLX::WasAllocatedUsingRobustnessExtension() {
   return GLSurfaceGLX::IsCreateContextRobustnessSupported();
 }
diff --git a/ui/gl/gl_context_glx.h b/ui/gl/gl_context_glx.h
index 62c78e7..fd5d8d0 100644
--- a/ui/gl/gl_context_glx.h
+++ b/ui/gl/gl_context_glx.h
@@ -32,7 +32,6 @@
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
   void OnSetSwapInterval(int interval) override;
-  std::string GetExtensions() override;
   bool WasAllocatedUsingRobustnessExtension() override;
 
  protected:
diff --git a/ui/gl/gl_context_stub.cc b/ui/gl/gl_context_stub.cc
index 1c54f9d..7f60b288 100644
--- a/ui/gl/gl_context_stub.cc
+++ b/ui/gl/gl_context_stub.cc
@@ -13,8 +13,9 @@
 GLContextStub::GLContextStub(GLShareGroup* share_group)
     : GLContextReal(share_group),
       use_stub_api_(false),
-      version_str_("OpenGL ES 3.0"),
-      extensions_("GL_EXT_framebuffer_object") {}
+      version_str_("OpenGL ES 3.0") {
+  SetExtensionsString("GL_EXT_framebuffer_object");
+}
 
 bool GLContextStub::Initialize(GLSurface* compatible_surface,
                                const GLContextAttribs& attribs) {
@@ -56,16 +57,12 @@
          HasExtension("GL_KHR_robustness") || HasExtension("GL_EXT_robustness");
 }
 
-std::string GLContextStub::GetExtensions() {
-  return extensions_;
-}
-
 void GLContextStub::SetUseStubApi(bool stub_api) {
   use_stub_api_ = stub_api;
 }
 
 void GLContextStub::SetExtensionsString(const char* extensions) {
-  extensions_ = extensions;
+  SetExtensionsFromString(extensions);
 }
 
 void GLContextStub::SetGLVersionString(const char* version_str) {
@@ -80,8 +77,8 @@
     if (!version_str_.empty()) {
       stub_api->set_version(version_str_);
     }
-    if (!extensions_.empty()) {
-      stub_api->set_extensions(extensions_);
+    if (!extension_string().empty()) {
+      stub_api->set_extensions(extension_string());
     }
     return stub_api;
   }
diff --git a/ui/gl/gl_context_stub.h b/ui/gl/gl_context_stub.h
index 7ddc3d1..ca1514ca 100644
--- a/ui/gl/gl_context_stub.h
+++ b/ui/gl/gl_context_stub.h
@@ -30,7 +30,6 @@
   std::string GetGLVersion() override;
   std::string GetGLRenderer() override;
   bool WasAllocatedUsingRobustnessExtension() override;
-  std::string GetExtensions() override;
 
   void SetUseStubApi(bool stub_api);
   void SetExtensionsString(const char* extensions);
@@ -44,7 +43,6 @@
  private:
   bool use_stub_api_;
   std::string version_str_;
-  std::string extensions_;
 
   DISALLOW_COPY_AND_ASSIGN(GLContextStub);
 };
diff --git a/ui/gl/gl_context_wgl.cc b/ui/gl/gl_context_wgl.cc
index 726fcb6..520b4ca 100644
--- a/ui/gl/gl_context_wgl.cc
+++ b/ui/gl/gl_context_wgl.cc
@@ -162,19 +162,6 @@
   }
 }
 
-std::string GLContextWGL::GetExtensions() {
-  const char* extensions = nullptr;
-  if (g_driver_wgl.fn.wglGetExtensionsStringARBFn)
-    extensions = wglGetExtensionsStringARB(GLSurfaceWGL::GetDisplayDC());
-  else if (g_driver_wgl.fn.wglGetExtensionsStringEXTFn)
-    extensions = wglGetExtensionsStringEXT();
-
-  if (extensions)
-    return GLContext::GetExtensions() + " " + extensions;
-
-  return GLContext::GetExtensions();
-}
-
 GLContextWGL::~GLContextWGL() {
   Destroy();
 }
diff --git a/ui/gl/gl_context_wgl.h b/ui/gl/gl_context_wgl.h
index aed32873..52653a0 100644
--- a/ui/gl/gl_context_wgl.h
+++ b/ui/gl/gl_context_wgl.h
@@ -29,7 +29,6 @@
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
   void OnSetSwapInterval(int interval) override;
-  std::string GetExtensions() override;
 
  private:
   ~GLContextWGL() override;
diff --git a/ui/gl/gl_implementation.cc b/ui/gl/gl_implementation.cc
index 8ef1c22..c97e8f37 100644
--- a/ui/gl/gl_implementation.cc
+++ b/ui/gl/gl_implementation.cc
@@ -229,14 +229,6 @@
   return is_es || major_version < 3;
 }
 
-std::unique_ptr<GLVersionInfo> GetVersionInfoFromContext(GLApi* api) {
-  std::string extensions = GetGLExtensionsFromCurrentContext(api);
-  return base::MakeUnique<GLVersionInfo>(
-      reinterpret_cast<const char*>(api->glGetStringFn(GL_VERSION)),
-      reinterpret_cast<const char*>(api->glGetStringFn(GL_RENDERER)),
-      extensions.c_str());
-}
-
 base::NativeLibrary LoadLibraryAndPrintError(
     const base::FilePath::CharType* filename) {
   return LoadLibraryAndPrintError(base::FilePath(filename));
diff --git a/ui/gl/gl_implementation.h b/ui/gl/gl_implementation.h
index 28cbde27..507b39f 100644
--- a/ui/gl/gl_implementation.h
+++ b/ui/gl/gl_implementation.h
@@ -18,7 +18,6 @@
 namespace gl {
 
 class GLApi;
-struct GLVersionInfo;
 
 // The GL implementation currently in use.
 enum GLImplementation {
@@ -126,8 +125,6 @@
 GL_EXPORT bool WillUseGLGetStringForExtensions();
 GL_EXPORT bool WillUseGLGetStringForExtensions(GLApi* api);
 
-GL_EXPORT std::unique_ptr<GLVersionInfo> GetVersionInfoFromContext(GLApi* api);
-
 // Helpers to load a library and log error on failure.
 GL_EXPORT base::NativeLibrary LoadLibraryAndPrintError(
     const base::FilePath::CharType* filename);
diff --git a/ui/gl/gl_version_info.cc b/ui/gl/gl_version_info.cc
index 5bf6a7f..9e1b1cc 100644
--- a/ui/gl/gl_version_info.cc
+++ b/ui/gl/gl_version_info.cc
@@ -24,25 +24,7 @@
 
 GLVersionInfo::GLVersionInfo(const char* version_str,
                              const char* renderer_str,
-                             const char* extensions_str)
-    : GLVersionInfo() {
-  std::set<std::string> extensions;
-  if (extensions_str) {
-    auto split = base::SplitString(extensions_str, " ", base::KEEP_WHITESPACE,
-                                   base::SPLIT_WANT_NONEMPTY);
-    extensions.insert(split.begin(), split.end());
-  }
-  Initialize(version_str, renderer_str, extensions);
-}
-
-GLVersionInfo::GLVersionInfo(const char* version_str,
-                             const char* renderer_str,
-                             const std::set<std::string>& extensions)
-    : GLVersionInfo() {
-  Initialize(version_str, renderer_str, extensions);
-}
-
-GLVersionInfo::GLVersionInfo()
+                             const ExtensionSet& extensions)
     : is_es(false),
       is_angle(false),
       is_mesa(false),
@@ -52,11 +34,13 @@
       is_es2(false),
       is_es3(false),
       is_desktop_core_profile(false),
-      is_es3_capable(false) {}
+      is_es3_capable(false) {
+  Initialize(version_str, renderer_str, extensions);
+}
 
 void GLVersionInfo::Initialize(const char* version_str,
                                const char* renderer_str,
-                               const std::set<std::string>& extensions) {
+                               const ExtensionSet& extensions) {
   if (version_str) {
     ParseVersionString(version_str, &major_version, &minor_version,
                        &is_es, &is_es2, &is_es3);
@@ -71,16 +55,11 @@
   }
   is_desktop_core_profile =
       DesktopCoreCommonCheck(is_es, major_version, minor_version) &&
-      extensions.find("GL_ARB_compatibility") == extensions.end();
+      !HasExtension(extensions, "GL_ARB_compatibility");
   is_es3_capable = IsES3Capable(extensions);
 }
 
-bool GLVersionInfo::IsES3Capable(
-    const std::set<std::string>& extensions) const {
-  auto has_extension = [&extensions](std::string extension) -> bool {
-    return extensions.find(extension) != extensions.end();
-  };
-
+bool GLVersionInfo::IsES3Capable(const ExtensionSet& extensions) const {
   // Version ES3 capable without extensions needed.
   if (IsAtLeastGLES(3, 0) || IsAtLeastGL(4, 2)) {
     return true;
@@ -92,7 +71,8 @@
   }
 
   bool has_transform_feedback =
-      (IsAtLeastGL(4, 0) || has_extension("GL_ARB_transform_feedback2"));
+      (IsAtLeastGL(4, 0) ||
+       HasExtension(extensions, "GL_ARB_transform_feedback2"));
 
   // This code used to require the GL_ARB_gpu_shader5 extension in order to
   // have support for dynamic indexing of sampler arrays, which was
@@ -101,7 +81,7 @@
   // Mesa/Gallium on AMD GPUs) don't support it, we no longer require it.
 
   // tex storage is available in core spec since GL 4.2.
-  bool has_tex_storage = has_extension("GL_ARB_texture_storage");
+  bool has_tex_storage = HasExtension(extensions, "GL_ARB_texture_storage");
 
   // TODO(cwallez) check for texture related extensions. See crbug.com/623577
 
diff --git a/ui/gl/gl_version_info.h b/ui/gl/gl_version_info.h
index 1775716c..a0278fb 100644
--- a/ui/gl/gl_version_info.h
+++ b/ui/gl/gl_version_info.h
@@ -9,16 +9,15 @@
 #include <string>
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "ui/gl/extension_set.h"
 #include "ui/gl/gl_export.h"
 
 namespace gl {
 
 struct GL_EXPORT GLVersionInfo {
-  GLVersionInfo(const char* version_str, const char* renderer_str,
-                const char* extensions_str);
-
-  GLVersionInfo(const char* version_str, const char* renderer_str,
-                const std::set<std::string>& exts);
+  GLVersionInfo(const char* version_str,
+                const char* renderer_str,
+                const ExtensionSet& exts);
 
   bool IsAtLeastGL(unsigned major, unsigned minor) const {
     return !is_es && (major_version > major ||
@@ -62,11 +61,10 @@
   bool is_es3_capable;
 
  private:
-  GLVersionInfo();
   void Initialize(const char* version_str,
                   const char* renderer_str,
-                  const std::set<std::string>& extensions);
-  bool IsES3Capable(const std::set<std::string>& extensions) const;
+                  const ExtensionSet& extensions);
+  bool IsES3Capable(const ExtensionSet& extensions) const;
 
   DISALLOW_COPY_AND_ASSIGN(GLVersionInfo);
 };
diff --git a/ui/gl/gl_version_info_unittest.cc b/ui/gl/gl_version_info_unittest.cc
index 2463e0e..fed30da 100644
--- a/ui/gl/gl_version_info_unittest.cc
+++ b/ui/gl/gl_version_info_unittest.cc
@@ -15,14 +15,13 @@
       "OpenGL ES 2.0 (ANGLE 2.1.0.cd1b12260360)",
       "2.1 INTEL-10.6.33"};
   const char* renderer_str[] = {NULL, NULL, NULL, NULL};
-  const char* extensions_str[] = {"extensions", "extensions",
-                                  "extensions", "extensions"};
+  ExtensionSet extensions = {"extensions"};
   unsigned expected_major[] = {4, 4, 2, 2};
   unsigned expected_minor[] = {3, 5, 0, 1};
   std::unique_ptr<GLVersionInfo> version_info;
   for (unsigned i = 0; i < arraysize(version_str); i++) {
-    version_info.reset(new GLVersionInfo(version_str[i],
-        renderer_str[i], extensions_str[i]));
+    version_info.reset(
+        new GLVersionInfo(version_str[i], renderer_str[i], extensions));
     unsigned major, minor;
     bool is_es, is_es2, is_es3;
     version_info->ParseVersionString(version_str[i], &major, &minor,
diff --git a/ui/gl/init/gl_factory_android.cc b/ui/gl/init/gl_factory_android.cc
index 001b4a6..c66bde8 100644
--- a/ui/gl/init/gl_factory_android.cc
+++ b/ui/gl/init/gl_factory_android.cc
@@ -39,7 +39,6 @@
   bool IsCurrent(GLSurface* surface) override { return true; }
   void* GetHandle() override { return nullptr; }
   void OnSetSwapInterval(int interval) override {}
-  std::string GetExtensions() override;
 
  protected:
   ~GLNonOwnedContext() override {}
@@ -66,14 +65,6 @@
   return true;
 }
 
-std::string GLNonOwnedContext::GetExtensions() {
-  const char* extensions = eglQueryString(display_, EGL_EXTENSIONS);
-  if (!extensions)
-    return GLContext::GetExtensions();
-
-  return GLContext::GetExtensions() + " " + extensions;
-}
-
 }  // namespace
 
 std::vector<GLImplementation> GetAllowedGLImplementations() {
diff --git a/ui/gl/init/gl_factory_ozone.cc b/ui/gl/init/gl_factory_ozone.cc
index cad4a47..8b35da4 100644
--- a/ui/gl/init/gl_factory_ozone.cc
+++ b/ui/gl/init/gl_factory_ozone.cc
@@ -106,18 +106,12 @@
 }
 
 void SetDisabledExtensionsPlatform(const std::string& disabled_extensions) {
-  GLImplementation implementation = GetGLImplementation();
-  DCHECK_NE(kGLImplementationNone, implementation);
-  switch (implementation) {
-    case kGLImplementationEGLGLES2:
-      SetDisabledExtensionsEGL(disabled_extensions);
-      break;
-    case kGLImplementationDesktopGL:
-      // TODO(zmo): I don't think ozone goes down this path except for testing.
-      // This might change in the future though.
-      break;
-    case kGLImplementationSwiftShaderGL:
-    case kGLImplementationOSMesaGL:
+  if (HasGLOzone()) {
+    GetGLOzone()->SetDisabledExtensionsPlatform(disabled_extensions);
+    return;
+  }
+
+  switch (GetGLImplementation()) {
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       break;
@@ -127,17 +121,10 @@
 }
 
 bool InitializeExtensionSettingsOneOffPlatform() {
-  GLImplementation implementation = GetGLImplementation();
-  DCHECK_NE(kGLImplementationNone, implementation);
-  switch (implementation) {
-    case kGLImplementationEGLGLES2:
-      return InitializeExtensionSettingsOneOffEGL();
-    case kGLImplementationDesktopGL:
-      // TODO(zmo): I don't think ozone goes down this path except for testing.
-      // This might change in the future though.
-      return true;
-    case kGLImplementationSwiftShaderGL:
-    case kGLImplementationOSMesaGL:
+  if (HasGLOzone())
+    return GetGLOzone()->InitializeExtensionSettingsOneOffPlatform();
+
+  switch (GetGLImplementation()) {
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       return true;
diff --git a/ui/ozone/common/gl_ozone_egl.cc b/ui/ozone/common/gl_ozone_egl.cc
index 910b3f81..d3adeec 100644
--- a/ui/ozone/common/gl_ozone_egl.cc
+++ b/ui/ozone/common/gl_ozone_egl.cc
@@ -40,6 +40,15 @@
   gl::InitializeDebugGLBindingsEGL();
 }
 
+void GLOzoneEGL::SetDisabledExtensionsPlatform(
+    const std::string& disabled_extensions) {
+  gl::SetDisabledExtensionsEGL(disabled_extensions);
+}
+
+bool GLOzoneEGL::InitializeExtensionSettingsOneOffPlatform() {
+  return gl::InitializeExtensionSettingsOneOffEGL();
+}
+
 void GLOzoneEGL::ShutdownGL() {
   gl::GLSurfaceEGL::ShutdownOneOff();
   gl::ClearBindingsGL();
diff --git a/ui/ozone/common/gl_ozone_egl.h b/ui/ozone/common/gl_ozone_egl.h
index 11c3a86d..7e43d71 100644
--- a/ui/ozone/common/gl_ozone_egl.h
+++ b/ui/ozone/common/gl_ozone_egl.h
@@ -22,6 +22,9 @@
   bool InitializeGLOneOffPlatform() override;
   bool InitializeStaticGLBindings(gl::GLImplementation implementation) override;
   void InitializeDebugGLBindings() override;
+  void SetDisabledExtensionsPlatform(
+      const std::string& disabled_extensions) override;
+  bool InitializeExtensionSettingsOneOffPlatform() override;
   void ShutdownGL() override;
   bool GetGLWindowSystemBindingInfo(
       gl::GLWindowSystemBindingInfo* info) override;
diff --git a/ui/ozone/common/gl_ozone_osmesa.cc b/ui/ozone/common/gl_ozone_osmesa.cc
index e7ccc73..af19a96 100644
--- a/ui/ozone/common/gl_ozone_osmesa.cc
+++ b/ui/ozone/common/gl_ozone_osmesa.cc
@@ -43,6 +43,13 @@
   gl::InitializeDebugGLBindingsOSMESA();
 }
 
+void GLOzoneOSMesa::SetDisabledExtensionsPlatform(
+    const std::string& disabled_extensions) {}
+
+bool GLOzoneOSMesa::InitializeExtensionSettingsOneOffPlatform() {
+  return true;
+}
+
 void GLOzoneOSMesa::ShutdownGL() {
   gl::ClearBindingsGL();
   gl::ClearBindingsOSMESA();
diff --git a/ui/ozone/common/gl_ozone_osmesa.h b/ui/ozone/common/gl_ozone_osmesa.h
index 9ec57ca..3b09ba9 100644
--- a/ui/ozone/common/gl_ozone_osmesa.h
+++ b/ui/ozone/common/gl_ozone_osmesa.h
@@ -21,6 +21,9 @@
   bool InitializeGLOneOffPlatform() override;
   bool InitializeStaticGLBindings(gl::GLImplementation implementation) override;
   void InitializeDebugGLBindings() override;
+  void SetDisabledExtensionsPlatform(
+      const std::string& disabled_extensions) override;
+  bool InitializeExtensionSettingsOneOffPlatform() override;
   void ShutdownGL() override;
   bool GetGLWindowSystemBindingInfo(
       gl::GLWindowSystemBindingInfo* info) override;
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index 1de8eab6..cc0bb2f 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -294,6 +294,18 @@
   std::vector<ozone::mojom::DeviceCursorRequest> pending_cursor_requests_;
   std::vector<ozone::mojom::DrmDeviceRequest> pending_gpu_adapter_requests_;
 
+  // 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
+  // use at any time.
+  // TODO(rjkroege): Remove gpu_platform_support_host_ once ozone/drm with mojo
+  // has reached the stable channel.
+  // A raw pointer to either |gpu_platform_support_host_| or |host_drm_device_|
+  // is passed to |display_manager_| and |overlay_manager_| in IntializeUI.
+  // 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.
   std::unique_ptr<DeviceManager> device_manager_;
   std::unique_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_;
@@ -303,14 +315,6 @@
   std::unique_ptr<DrmDisplayHostManager> display_manager_;
   std::unique_ptr<DrmOverlayManager> overlay_manager_;
 
-  // 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
-  // use at any time.
-  // TODO(rjkroege): Remove gpu_platform_support_host_ once ozone/drm with mojo
-  // has reached the stable channel.
-  std::unique_ptr<DrmGpuPlatformSupportHost> gpu_platform_support_host_;
-  std::unique_ptr<HostDrmDevice> host_drm_device_;
-
 #if BUILDFLAG(USE_XKBCOMMON)
   XkbEvdevCodes xkb_evdev_code_converter_;
 #endif
diff --git a/ui/ozone/platform/x11/gl_ozone_glx.cc b/ui/ozone/platform/x11/gl_ozone_glx.cc
index 102b2f8..ab78a370 100644
--- a/ui/ozone/platform/x11/gl_ozone_glx.cc
+++ b/ui/ozone/platform/x11/gl_ozone_glx.cc
@@ -72,6 +72,15 @@
   gl::InitializeDebugGLBindingsGLX();
 }
 
+void GLOzoneGLX::SetDisabledExtensionsPlatform(
+    const std::string& disabled_extensions) {
+  gl::SetDisabledExtensionsGLX(disabled_extensions);
+}
+
+bool GLOzoneGLX::InitializeExtensionSettingsOneOffPlatform() {
+  return gl::InitializeExtensionSettingsOneOffGLX();
+}
+
 void GLOzoneGLX::ShutdownGL() {
   gl::ClearBindingsGL();
   gl::ClearBindingsGLX();
diff --git a/ui/ozone/platform/x11/gl_ozone_glx.h b/ui/ozone/platform/x11/gl_ozone_glx.h
index 686c674..2423800 100644
--- a/ui/ozone/platform/x11/gl_ozone_glx.h
+++ b/ui/ozone/platform/x11/gl_ozone_glx.h
@@ -19,6 +19,9 @@
   bool InitializeGLOneOffPlatform() override;
   bool InitializeStaticGLBindings(gl::GLImplementation implementation) override;
   void InitializeDebugGLBindings() override;
+  void SetDisabledExtensionsPlatform(
+      const std::string& disabled_extensions) override;
+  bool InitializeExtensionSettingsOneOffPlatform() override;
   void ShutdownGL() override;
   bool GetGLWindowSystemBindingInfo(
       gl::GLWindowSystemBindingInfo* info) override;
diff --git a/ui/ozone/public/gl_ozone.h b/ui/ozone/public/gl_ozone.h
index 159a4c4..02ccb4d0 100644
--- a/ui/ozone/public/gl_ozone.h
+++ b/ui/ozone/public/gl_ozone.h
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PUBLIC_GL_OZONE_H_
 #define UI_OZONE_PUBLIC_GL_OZONE_H_
 
+#include <string>
+
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "ui/gfx/geometry/size.h"
@@ -39,6 +41,17 @@
   // Initializes static debug GL bindings.
   virtual void InitializeDebugGLBindings() = 0;
 
+  // Disables the specified extensions in the window system bindings,
+  // e.g., GLX, EGL, etc. This is part of the GPU driver bug workarounds
+  // mechanism.
+  virtual void SetDisabledExtensionsPlatform(
+      const std::string& disabled_extensions) = 0;
+
+  // Initializes extension related settings for window system bindings that
+  // will be affected by SetDisabledExtensionsPlatform(). This function is
+  // called after SetDisabledExtensionsPlatform() to finalize the bindings.
+  virtual bool InitializeExtensionSettingsOneOffPlatform() = 0;
+
   // Clears static GL bindings.
   virtual void ShutdownGL() = 0;
 
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index db76cc8..8a51d75 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -363,9 +363,12 @@
       <message name="IDS_AX_CHECK_ACTION_VERB" desc="Verb stating the action that will occur when an unchecked checkbox is clicked, as used by accessibility.">
         check
       </message>
-      <message name="IDS_AX_CLICK_ACTION_VERB" desc="Verb stating the action that will occur when clicking on a generic clickable object, when we don't know what that action is, as used by accessibility.">
+      <message name="IDS_AX_CLICK_ACTION_VERB" desc="Verb stating the action that will occur when clicking on a generic clickable object, when we don't have a more specific action description, as used by accessibility.">
         click
       </message>
+      <message name="IDS_AX_CLICK_ANCESTOR_ACTION_VERB" desc="Verb stating the action that will occur when clicking on a generic object that is not itself clickable but one of its ancestors is, as used by accessibility.">
+        click ancestor
+      </message>
       <message name="IDS_AX_JUMP_ACTION_VERB" desc="Verb stating the action that will occur when an element such as an in-page link is activated, as used by accessibility.">
         jump
       </message>
@@ -700,7 +703,7 @@
           Annotate image
         </message>
         <message name="IDS_MESSAGE_CENTER_NOTIFIER_HATS_NAME" desc="The name of hats notifier that is a system component">
-          Hats
+          Survey
         </message>
         <message name="IDS_MESSAGE_CENTER_NOTIFIER_FINGERPRINT_UNLOCK_FEATURE_NAME" desc="The name of fingerprint unlock feature notifier that is a system component">
           Fingerprint Unlock Feature
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc
index 3841b89..21f640cb 100644
--- a/ui/views/bubble/tray_bubble_view.cc
+++ b/ui/views/bubble/tray_bubble_view.cc
@@ -13,6 +13,7 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_owner.h"
@@ -26,6 +27,7 @@
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/painter.h"
+#include "ui/views/views_delegate.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/shadow_types.h"
 
@@ -127,13 +129,6 @@
 
 void TrayBubbleView::Delegate::OnMouseExitedView() {}
 
-void TrayBubbleView::Delegate::RegisterAccelerators(
-    const std::vector<ui::Accelerator>& accelerators,
-    TrayBubbleView* tray_bubble_view) {}
-
-void TrayBubbleView::Delegate::UnregisterAllAccelerators(
-    TrayBubbleView* tray_bubble_view) {}
-
 base::string16 TrayBubbleView::Delegate::GetAccessibleNameForBubble() {
   return base::string16();
 }
@@ -151,6 +146,49 @@
 
 TrayBubbleView::InitParams::InitParams(const InitParams& other) = default;
 
+TrayBubbleView::RerouteEventHandler::RerouteEventHandler(
+    TrayBubbleView* tray_bubble_view)
+    : tray_bubble_view_(tray_bubble_view) {
+  aura::Env::GetInstance()->PrependPreTargetHandler(this);
+}
+
+TrayBubbleView::RerouteEventHandler::~RerouteEventHandler() {
+  aura::Env::GetInstance()->RemovePreTargetHandler(this);
+}
+
+void TrayBubbleView::RerouteEventHandler::OnKeyEvent(ui::KeyEvent* event) {
+  // Only passes Tab, Shift+Tab, Esc to the widget as it can consume more key
+  // events. e.g. Alt+Tab can be consumed as focus traversal by FocusManager.
+  ui::KeyboardCode key_code = event->key_code();
+  int flags = event->flags();
+  if ((key_code == ui::VKEY_TAB && flags == ui::EF_NONE) ||
+      (key_code == ui::VKEY_TAB && flags == ui::EF_SHIFT_DOWN) ||
+      (key_code == ui::VKEY_ESCAPE && flags == ui::EF_NONE)) {
+    // Make TrayBubbleView activatable as the following Widget::OnKeyEvent might
+    // try to activate it.
+    tray_bubble_view_->set_can_activate(true);
+
+    tray_bubble_view_->GetWidget()->OnKeyEvent(event);
+
+    if (event->handled())
+      return;
+  }
+
+  // Always consumes key event not to pass it to other widgets. Calling
+  // StopPropagation here to make this consistent with
+  // MenuController::OnWillDispatchKeyEvent.
+  event->StopPropagation();
+
+  // To provide consistent behavior with a menu, process accelerator as a menu
+  // is open if the event is not handled by the widget.
+  ui::Accelerator accelerator(*event);
+  ViewsDelegate::ProcessMenuAcceleratorResult result =
+      ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing(
+          accelerator);
+  if (result == ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU)
+    tray_bubble_view_->CloseBubbleView();
+}
+
 TrayBubbleView::TrayBubbleView(const InitParams& init_params)
     : BubbleDialogDelegateView(init_params.anchor_view,
                                GetArrowAlignment(init_params.anchor_alignment)),
@@ -188,9 +226,8 @@
 
 TrayBubbleView::~TrayBubbleView() {
   mouse_watcher_.reset();
-  if (delegate_) {
-    delegate_->UnregisterAllAccelerators(this);
 
+  if (delegate_) {
     // Inform host items (models) that their views are being destroyed.
     delegate_->BubbleViewDestroyed();
   }
@@ -209,15 +246,10 @@
 
   ++g_current_tray_bubble_showing_count_;
 
-  // If TrayBubbleView cannot be activated, register accelerators to capture key
-  // events for activating the view or closing it. TrayBubbleView expects that
-  // those accelerators are registered at the global level.
-  if (delegate_ && !CanActivate()) {
-    delegate_->RegisterAccelerators(
-        {ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE),
-         ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE),
-         ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN)},
-        this);
+  // If TrayBubbleView cannot be activated, register pre target event handler to
+  // reroute key events to the widget for activating the view or closing it.
+  if (!CanActivate()) {
+    reroute_event_handler_ = base::MakeUnique<RerouteEventHandler>(this);
   }
 }
 
@@ -258,8 +290,7 @@
 }
 
 void TrayBubbleView::ResetDelegate() {
-  if (delegate_)
-    delegate_->UnregisterAllAccelerators(this);
+  reroute_event_handler_.reset();
 
   delegate_ = nullptr;
 }
@@ -281,11 +312,23 @@
 }
 
 void TrayBubbleView::OnWidgetClosing(Widget* widget) {
+  // We no longer need to watch key events for activation if the widget is
+  // closing.
+  reroute_event_handler_.reset();
+
   BubbleDialogDelegateView::OnWidgetClosing(widget);
   --g_current_tray_bubble_showing_count_;
   DCHECK_GE(g_current_tray_bubble_showing_count_, 0);
 }
 
+void TrayBubbleView::OnWidgetActivationChanged(Widget* widget, bool active) {
+  // We no longer need to watch key events for activation if the widget is
+  // activated.
+  reroute_event_handler_.reset();
+
+  BubbleDialogDelegateView::OnWidgetActivationChanged(widget, active);
+}
+
 NonClientFrameView* TrayBubbleView::CreateNonClientFrameView(Widget* widget) {
   BubbleFrameView* frame = static_cast<BubbleFrameView*>(
       BubbleDialogDelegateView::CreateNonClientFrameView(widget));
@@ -387,26 +430,6 @@
   mouse_watcher_->Stop();
 }
 
-bool TrayBubbleView::AcceleratorPressed(const ui::Accelerator& accelerator) {
-  if (accelerator == ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)) {
-    CloseBubbleView();
-    return true;
-  }
-
-  if (accelerator == ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE) ||
-      accelerator == ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN)) {
-    ui::KeyEvent key_event(
-        accelerator.key_state() == ui::Accelerator::KeyState::PRESSED
-            ? ui::EventType::ET_KEY_PRESSED
-            : ui::EventType::ET_KEY_RELEASED,
-        accelerator.key_code(), accelerator.modifiers());
-    ActivateAndStartNavigation(key_event);
-    return true;
-  }
-
-  return false;
-}
-
 void TrayBubbleView::ChildPreferredSizeChanged(View* child) {
   SizeToContents();
 }
@@ -423,23 +446,9 @@
   if (!delegate_)
     return;
 
-  delegate_->UnregisterAllAccelerators(this);
   delegate_->HideBubble(this);
 }
 
-void TrayBubbleView::ActivateAndStartNavigation(const ui::KeyEvent& key_event) {
-  // No need to explicitly activate the widget. FocusManager will activate it if
-  // necessary.
-  set_can_activate(true);
-
-  if (!GetWidget()->GetFocusManager()->OnKeyEvent(key_event) && delegate_) {
-    // No need to handle accelerators by TrayBubbleView after focus has moved to
-    // the widget. The focused view will handle focus traversal.
-    // FocusManager::OnKeyEvent returns false when it consumes a key event.
-    delegate_->UnregisterAllAccelerators(this);
-  }
-}
-
 void TrayBubbleView::FocusDefaultIfNeeded() {
   views::FocusManager* manager = GetFocusManager();
   if (!manager || manager->GetFocusedView())
diff --git a/ui/views/bubble/tray_bubble_view.h b/ui/views/bubble/tray_bubble_view.h
index 77f6035..1d197fe 100644
--- a/ui/views/bubble/tray_bubble_view.h
+++ b/ui/views/bubble/tray_bubble_view.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/optional.h"
-#include "ui/base/accelerators/accelerator.h"
 #include "ui/events/event.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/bubble/bubble_dialog_delegate.h"
@@ -60,17 +59,6 @@
     virtual void OnMouseEnteredView();
     virtual void OnMouseExitedView();
 
-    // Called to register/unregister accelerators for TrayBubbleView.
-    // TrayBubbleView wants to register those accelerators at the global level.
-    // Those accelerators are used to activate TrayBubbleView, i.e. those
-    // accelerators need to be processed even if TrayBubbleView is not active.
-    // UnregisterAllAccelerators can be called even if RegisterAccelerators is
-    // not called.
-    virtual void RegisterAccelerators(
-        const std::vector<ui::Accelerator>& accelerators,
-        TrayBubbleView* tray_bubble_view);
-    virtual void UnregisterAllAccelerators(TrayBubbleView* tray_bubble_view);
-
     // Called from GetAccessibleNodeData(); should return the appropriate
     // accessible name for the bubble.
     virtual base::string16 GetAccessibleNameForBubble();
@@ -153,6 +141,7 @@
   void OnBeforeBubbleWidgetInit(Widget::InitParams* params,
                                 Widget* bubble_widget) const override;
   void OnWidgetClosing(Widget* widget) override;
+  void OnWidgetActivationChanged(Widget* widget, bool active) override;
 
   // Overridden from views::View.
   gfx::Size CalculatePreferredSize() const override;
@@ -166,9 +155,6 @@
   // Overridden from MouseWatcherListener
   void MouseMovedOutOfHost() override;
 
-  // Overridden from ui::AcceleratorTarget
-  bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
-
  protected:
   // Overridden from views::BubbleDialogDelegateView.
   int GetDialogButtons() const override;
@@ -180,8 +166,28 @@
       const ViewHierarchyChangedDetails& details) override;
 
  private:
+  // This reroutes receiving key events to the TrayBubbleView passed in the
+  // constructor. TrayBubbleView is not activated by default. But we want to
+  // activate it if user tries to interact it with keyboard. To capture those
+  // key events in early stage, RerouteEventHandler installs this handler to
+  // aura::Env. RerouteEventHandler also sends key events to ViewsDelegate to
+  // process accelerator as menu is currently open.
+  class RerouteEventHandler : public ui::EventHandler {
+   public:
+    explicit RerouteEventHandler(TrayBubbleView* tray_bubble_view);
+    ~RerouteEventHandler() override;
+
+    // Overridden from ui::EventHandler
+    void OnKeyEvent(ui::KeyEvent* event) override;
+
+   private:
+    // TrayBubbleView to which key events are going to be rerouted. Not owned.
+    TrayBubbleView* tray_bubble_view_;
+
+    DISALLOW_COPY_AND_ASSIGN(RerouteEventHandler);
+  };
+
   void CloseBubbleView();
-  void ActivateAndStartNavigation(const ui::KeyEvent& key_event);
 
   // Focus the default item if no item is focused.
   void FocusDefaultIfNeeded();
@@ -204,6 +210,10 @@
   // Used to find any mouse movements.
   std::unique_ptr<MouseWatcher> mouse_watcher_;
 
+  // Used to activate tray bubble view if user tries to interact the tray with
+  // keyboard.
+  std::unique_ptr<EventHandler> reroute_event_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(TrayBubbleView);
 };
 
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc
index 2eef2d1..5657285 100644
--- a/ui/views/controls/button/md_text_button.cc
+++ b/ui/views/controls/button/md_text_button.cc
@@ -6,6 +6,7 @@
 
 #include "base/i18n/case_conversion.h"
 #include "base/memory/ptr_util.h"
+#include "build/build_config.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
@@ -307,6 +308,21 @@
       // alpha for non-Harmony, 757575 @ 1.0 alpha for Harmony and turn it into
       // an effective b2b2b2 @ 1.0 alpha or 000000 @ 0.3 for the stroke_color.
       stroke_alpha = UseMaterialSecondaryButtons() ? 0x8f : 0x77;
+#if defined(OS_MACOSX)
+      // Without full secondary UI MD support, the text color is solid black,
+      // and so the border is too dark on Mac. On Retina it looks OK, so
+      // heuristically determine the scale factor as well.
+      if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) {
+        // The Compositor may only be set when attached to a Widget. But, since
+        // that also determines the theme, UpdateColors() will always be called
+        // after attaching to a Widget.
+        // TODO(tapted): Move this into SolidRoundRectPainter if we like this
+        // logic for Harmony.
+        auto* compositor = layer()->GetCompositor();
+        if (compositor && compositor->device_scale_factor() == 1)
+          stroke_alpha = 0x4d;  // Chosen to match full secondary UI MD (0.3).
+      }
+#endif
     }
     stroke_color = SkColorSetA(text_color, stroke_alpha);
   }
diff --git a/ui/views/test/event_generator_delegate_mac.mm b/ui/views/test/event_generator_delegate_mac.mm
index 3203a23d..af8c4001 100644
--- a/ui/views/test/event_generator_delegate_mac.mm
+++ b/ui/views/test/event_generator_delegate_mac.mm
@@ -272,6 +272,9 @@
   ui::EventSink* GetEventSink() override { return this; }
 
   // Overridden from ui::EventProcessor:
+  ui::EventTarget* GetInitialEventTarget(ui::Event* event) override {
+    return nullptr;
+  }
   ui::EventTarget* GetRootForEvent(ui::Event* event) override { return this; }
   ui::EventTargeter* GetDefaultEventTargeter() override {
     return this->GetEventTargeter();
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc
index acc2aaf..e1e866f 100644
--- a/ui/views/widget/root_view.cc
+++ b/ui/views/widget/root_view.cc
@@ -241,6 +241,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 // RootView, ui::EventProcessor overrides:
 
+ui::EventTarget* RootView::GetInitialEventTarget(ui::Event* event) {
+  // Views has no special initial target.
+  return nullptr;
+}
+
 ui::EventTarget* RootView::GetRootForEvent(ui::Event* event) {
   return this;
 }
diff --git a/ui/views/widget/root_view.h b/ui/views/widget/root_view.h
index 17ae8112..6d8761fe 100644
--- a/ui/views/widget/root_view.h
+++ b/ui/views/widget/root_view.h
@@ -93,6 +93,7 @@
   View* GetFocusTraversableParentView() override;
 
   // Overridden from ui::EventProcessor:
+  ui::EventTarget* GetInitialEventTarget(ui::Event* event) override;
   ui::EventTarget* GetRootForEvent(ui::Event* event) override;
   ui::EventTargeter* GetDefaultEventTargeter() override;
   void OnEventProcessingStarted(ui::Event* event) override;
diff --git a/ui/webui/resources/cr_elements/icons.html b/ui/webui/resources/cr_elements/icons.html
index bc0eae7..238e2f1 100644
--- a/ui/webui/resources/cr_elements/icons.html
+++ b/ui/webui/resources/cr_elements/icons.html
@@ -50,6 +50,7 @@
       <g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path></g>
       <g id="print"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"></path></g>
       <g id="search"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></g>
+      <g id="sms-connect"><path d="M20,2C21.1,2 22,2.9 22,4L22,16C22,17.1 21.1,18 20,18L6,18L2,22L2.01,4C2.01,2.9 2.9,2 4,2L20,2ZM8,8L4,12L8,16L8,13L14,13L14,11L8,11L8,8ZM19.666,7.872L16.038,4.372L16.038,6.997L10,6.997L10,9L16.038,9L16.038,11.372L19.666,7.872Z"></path></g>
       <!-- The <g> IDs are exposed as global variables in Vulcanized mode, which
         conflicts with the "settings" namespace of MD Settings. Using an "_icon"
         suffix prevents the naming conflict. -->
diff --git a/ui/webui/resources/js/cr/ui/list.js b/ui/webui/resources/js/cr/ui/list.js
index fafbd62..3bb4ca55 100644
--- a/ui/webui/resources/js/cr/ui/list.js
+++ b/ui/webui/resources/js/cr/ui/list.js
@@ -576,11 +576,13 @@
 
       var target = /** @type {HTMLElement} */ (e.target);
 
-      // If the target was this element we need to make sure that the user did
-      // not click on a border or a scrollbar.
       if (target == this) {
-        if (inViewport(target, e))
-          this.selectionController_.handleTouchEvents(e, -1);
+        // Unlike the mouse events, we don't check if the touch is inside the
+        // viewport because of these reasons:
+        // - The scrollbars do not interact with touch.
+        // - touch* events are not sent to this element when tapping or
+        //   dragging window borders by touch.
+        this.selectionController_.handleTouchEvents(e, -1);
         return;
       }
 
diff --git a/ui/wm/core/compound_event_filter.cc b/ui/wm/core/compound_event_filter.cc
index a3adb26..85933e06 100644
--- a/ui/wm/core/compound_event_filter.cc
+++ b/ui/wm/core/compound_event_filter.cc
@@ -17,10 +17,6 @@
 #include "ui/events/event.h"
 #include "ui/wm/public/activation_client.h"
 
-#if defined(OS_CHROMEOS) && defined(USE_X11)
-#include "ui/events/devices/x11/touch_factory_x11.h"  // nogncheck
-#endif
-
 namespace wm {
 
 namespace {
@@ -28,18 +24,7 @@
 // Returns true if the cursor should be hidden on touch events.
 // TODO(tdanderson|rsadam): Move this function into CursorClient.
 bool ShouldHideCursorOnTouch(const ui::TouchEvent& event) {
-#if defined(OS_WIN)
-  return true;
-#elif defined(OS_CHROMEOS)
-#if defined(USE_X11)
-  int device_id = event.source_device_id();
-  if (device_id >= 0 &&
-      !ui::TouchFactory::GetInstance()->IsMultiTouchDevice(device_id)) {
-    // If the touch event is coming from a mouse-device (i.e. not a real
-    // touch-device), then do not hide the cursor.
-    return false;
-  }
-#endif  // defined(USE_X11)
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
   return true;
 #else
   // Linux Aura does not hide the cursor on touch by default.